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      }
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    }