001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.adaptive.measurements.organizers;
014
015 import org.jikesrvm.VM;
016 import org.jikesrvm.adaptive.controller.Controller;
017 import org.jikesrvm.adaptive.controller.HotMethodRecompilationEvent;
018 import org.jikesrvm.adaptive.measurements.RuntimeMeasurements;
019 import org.jikesrvm.adaptive.measurements.listeners.MethodListener;
020 import org.jikesrvm.adaptive.util.AOSLogging;
021 import org.jikesrvm.compilers.common.CompiledMethod;
022 import org.jikesrvm.compilers.common.CompiledMethods;
023 import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
024 import org.jikesrvm.scheduler.RVMThread;
025 import org.vmmagic.pragma.NonMoving;
026
027 /**
028 * An organizer for method listener information.
029 * <p>
030 * This organizer is designed to work well with non-decayed
031 * cumulative method samples. The basic idea is that each time
032 * the sampling threshold is reached we update the accumulated method
033 * sample data with the new data and then notify the controller of all
034 * methods that were sampled in the current window.
035 */
036 @NonMoving
037 public final class MethodSampleOrganizer extends Organizer {
038
039 /**
040 * Filter out all opt-compiled methods that were compiled
041 * at this level or higher.
042 */
043 private int filterOptLevel;
044
045 /**
046 * @param filterOptLevel filter out all opt-compiled methods that
047 * were compiled at this level or higher
048 */
049 public MethodSampleOrganizer(int filterOptLevel) {
050 this.filterOptLevel = filterOptLevel;
051 makeDaemon(true);
052 }
053
054 /**
055 * Initialization: set up data structures and sampling objects.
056 */
057 @Override
058 public void initialize() {
059 int numSamples = Controller.options.METHOD_SAMPLE_SIZE * RVMThread.numProcessors;
060 if (Controller.options.mlCBS()) {
061 numSamples *= VM.CBSMethodSamplesPerTick;
062 }
063 MethodListener methodListener = new MethodListener(numSamples);
064 listener = methodListener;
065 listener.setOrganizer(this);
066
067 if (Controller.options.mlTimer()) {
068 RuntimeMeasurements.installTimerMethodListener(methodListener);
069 } else if (Controller.options.mlCBS()) {
070 RuntimeMeasurements.installCBSMethodListener(methodListener);
071 } else {
072 if (VM.VerifyAssertions) VM._assert(false, "Unexpected value of method_listener_trigger");
073 }
074 }
075
076 /**
077 * Method that is called when the sampling threshold is reached
078 */
079 void thresholdReached() {
080 AOSLogging.logger.organizerThresholdReached();
081
082 int numSamples = ((MethodListener) listener).getNumSamples();
083 int[] samples = ((MethodListener) listener).getSamples();
084
085 // (1) Update the global (cumulative) sample data
086 Controller.methodSamples.update(samples, numSamples);
087
088 // (2) Remove duplicates from samples buffer.
089 // NOTE: This is a dirty trick and may be ill-advised.
090 // Rather than copying the unique samples into a different buffer
091 // we treat samples as if it was a scratch buffer.
092 // NOTE: This is worse case O(numSamples^2) but we expect a
093 // significant number of duplicates, so it's probably better than
094 // the other obvious alternative (sorting samples).
095 int uniqueIdx = 1;
096 outer:
097 for (int i = 1; i < numSamples; i++) {
098 int cur = samples[i];
099 for (int j = 0; j < uniqueIdx; j++) {
100 if (cur == samples[j]) continue outer;
101 }
102 samples[uniqueIdx++] = cur;
103 }
104
105 // (3) For all samples in 0...uniqueIdx, if the method represented by
106 // the sample is compiled at an opt level below filterOptLevel
107 // then report it to the controller.
108 for (int i = 0; i < uniqueIdx; i++) {
109 int cmid = samples[i];
110 double ns = Controller.methodSamples.getData(cmid);
111 CompiledMethod cm = CompiledMethods.getCompiledMethod(cmid);
112 if (cm != null) { // not already obsoleted
113 int compilerType = cm.getCompilerType();
114
115 // Enqueue it unless it's either a trap method or already opt
116 // compiled at filterOptLevel or higher.
117 if (!(compilerType == CompiledMethod.TRAP ||
118 (compilerType == CompiledMethod.OPT &&
119 (((OptCompiledMethod) cm).getOptLevel() >= filterOptLevel)))) {
120 HotMethodRecompilationEvent event = new HotMethodRecompilationEvent(cm, ns);
121 Controller.controllerInputQueue.insert(ns, event);
122 AOSLogging.logger.controllerNotifiedForHotness(cm, ns);
123 }
124 }
125 }
126 }
127 }