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 */
013package org.jikesrvm.adaptive.measurements.organizers;
014
015import org.jikesrvm.VM;
016import org.jikesrvm.adaptive.controller.Controller;
017import org.jikesrvm.adaptive.controller.HotMethodRecompilationEvent;
018import org.jikesrvm.adaptive.measurements.RuntimeMeasurements;
019import org.jikesrvm.adaptive.measurements.listeners.MethodListener;
020import org.jikesrvm.adaptive.util.AOSLogging;
021import org.jikesrvm.compilers.common.CompiledMethod;
022import org.jikesrvm.compilers.common.CompiledMethods;
023import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
024import org.jikesrvm.scheduler.RVMThread;
025import 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
037public 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 final 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  }
052
053  /**
054   * Initialization: set up data structures and sampling objects.
055   * <p>
056   * Uses either timer based sampling or counter based sampling,
057   * depending on {@link Controller#options}.
058   */
059  @Override
060  public void initialize() {
061    int numSamples = Controller.options.METHOD_SAMPLE_SIZE * RVMThread.availableProcessors;
062    if (Controller.options.mlCBS()) {
063      numSamples *= VM.CBSMethodSamplesPerTick;
064    }
065    MethodListener methodListener = new MethodListener(numSamples);
066    listener = methodListener;
067    listener.setOrganizer(this);
068
069    if (Controller.options.mlTimer()) {
070      RuntimeMeasurements.installTimerMethodListener(methodListener);
071    } else if (Controller.options.mlCBS()) {
072      RuntimeMeasurements.installCBSMethodListener(methodListener);
073    } else {
074      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED, "Unexpected value of method_listener_trigger");
075    }
076  }
077
078  @Override
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}