code: /**
   * Copyright (c) 2004-2005, Regents of the University of California
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * Redistributions of source code must retain the above copyright notice,
   * this list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution.
   *
   * Neither the name of the University of California, Los Angeles nor the
   * names of its contributors may be used to endorse or promote products
   * derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  package avrora.monitors;
  
  import avrora.core.*;
  import avrora.sim.Simulator;
  import avrora.sim.State;
  import cck.stat.Distribution;
  import cck.text.*;
  import cck.util.Option;
  import cck.util.Util;
  
  /**
   * The <code>TripTimeMonitor</code> class implements a monitor that tracks the time from
   * executing instruction A in the program until the program reaches instruction B. For
   * example, if A is the beginning of an interrupt handler and B is the end of an interrupt
   * handler, then the monitor will record the time it takes to execute the entire interrupt
   * handler. For each pair of points A and B, it collects statistics about each "trip"
   * between the two points, reporting the results at the end of execution. 
   *
   * @author Ben L. Titzer
   */
  public class TripTimeMonitor extends MonitorFactory {
  
      final Option.List PAIRS = newOptionList("pairs", "",
              "The \"pairs\" option specifies the list of program point pairs for which " +
              "to measure the point-to-point trip time. ");
      final Option.List FROM = newOptionList("from", "",
              "The \"from\" option specifies the list of program points for which " +
              "to measure to every other instruction in the program. ");
      final Option.List TO = newOptionList("to", "",
              "The \"from\" option specifies the list of program points for which " +
              "to measure from every other instruction in the program. ");
      final Option.Bool DISTRIBUTION = newOption("distribution", false,
              "This option, when specified, causes the trip time monitor to print a complete distribution of the " +
              "trip times for each pair of program points. WARNING: this option can consume large amounts of memory " +
              "and generate a large amount of output.");
  
      public TripTimeMonitor() {
          super("The \"trip-time\" monitor records profiling " +
                  "information about the program that consists of the time it takes " +
                  "(on average) to reach one point from another point in the program.");
      }
  
      protected class PointToPointMon implements Monitor {
  
          class Pair {
              final int start;
              final int end;
              long cumul;
              long cumul_sqr;
              int count;
              long max;
              long min;
  
              Pair startLink;
              Pair endLink;
  
              Distribution distrib;
  
  
              Pair(int start, int end) {
                  this.start = start;
                  this.end = end;
  
                  cumul = 0;
                  cumul_sqr = 0;
                  max = 0;
                  min = Long.MAX_VALUE;
                  if ( DISTRIBUTION.get() )
                      distrib = new Distribution("trip time "
                              +StringUtil.addrToString(start)+" -to- "
                              +StringUtil.addrToString(end), "Trips", "Total Time", "Distribution");
              }
  
              void record(long time) {
                  if ( distrib != null ) {
                      distrib.record((int)time);
                  } else {
                      cumul += time;
                      cumul_sqr += (time * time);
                      max = Math.max(max, time);
                      min = Math.min(min, time);
                  }
                  count++;
              }
  
              void report(Printer printer) {
                  if ( distrib == null ) {
                  float avg = (float)cumul / count;
                  double std = Math.sqrt(((double)cumul_sqr / count) - (avg * avg));
                  Terminal.println("  "+ StringUtil.addrToString(start)+"  "
                          +StringUtil.addrToString(end)+"  "
                          +StringUtil.rightJustify(count, 8)+"  "
                          +StringUtil.rightJustify(avg, 10)+"  "
                          +StringUtil.rightJustify((float)std, 10)+"  "
                          +StringUtil.rightJustify((float)max, 9)+"  "
                          +StringUtil.rightJustify((float)min, 9)
                          );
                  } else {
                      distrib.process();
                      distrib.print(printer);
                  }
              }
          }
  
          final Pair[] startArray;
          final Pair[] endArray;
          final long[] lastEnter;
  
          final Simulator simulator;
          final Program program;
          final PTPProbe PROBE;
  
          PointToPointMon(Simulator s) {
              simulator = s;
              program = s.getProgram();
              int psize = program.program_end;
              startArray = new Pair[psize];
              endArray = new Pair[psize];
              lastEnter = new long[psize];
              PROBE = new PTPProbe();
  
              addPairs();
              addFrom();
              addTo();
          }
  
          private void addPairs() {
              for (String str : PAIRS.get()) {
                  int ind = str.indexOf(':');
                  if (ind <= 0)
                      throw Util.failure("invalid address format: " + StringUtil.quote(str));
                  String src = str.substring(0, ind);
                  String dst = str.substring(ind + 1);
  
                  SourceMapping.Location loc = getLocation(src);
                  SourceMapping.Location tar = getLocation(dst);
  
                  addPair(loc.lma_addr, tar.lma_addr);
              }
          }
  
          private SourceMapping.Location getLocation(String src) {
              SourceMapping lm = program.getSourceMapping();
              SourceMapping.Location loc = lm.getLocation(src);
              if ( loc == null )
                  Util.userError("Invalid program address: ", src);
              if ( program.readInstr(loc.lma_addr) == null )
                  Util.userError("Invalid program address: ", src);
              return loc;
          }
  
          private void addFrom() {
              SourceMapping sm = program.getSourceMapping();
              for (String str : FROM.get()) {
                  SourceMapping.Location loc = sm.getLocation(str);
                  for ( int cntr = 0; cntr < program.program_end; cntr = program.getNextPC(cntr) )
                      addPair(loc.lma_addr, cntr);
              }
          }
  
          private void addTo() {
              SourceMapping sm = program.getSourceMapping();
              for (String str : TO.get()) {
                  SourceMapping.Location loc = sm.getLocation(str);
                  for ( int cntr = 0; cntr < program.program_end; cntr = program.getNextPC(cntr) )
                      addPair(cntr, loc.lma_addr);
              }
          }
  
          void addPair(int start, int end) {
  
              if ( program.readInstr(start) == null ) return;
              if ( program.readInstr(end) == null ) return;
  
              Pair p = new Pair(start, end);
  
              if (startArray[p.start] == null && endArray[p.start] == null)
                  simulator.insertProbe(PROBE, p.start);
  
              p.startLink = startArray[p.start];
              startArray[p.start] = p;
  
              if (startArray[p.end] == null && endArray[p.end] == null)
                  simulator.insertProbe(PROBE, p.end);
  
  
              p.endLink = endArray[p.end];
              endArray[p.end] = p;
  
          }
  
          protected class PTPProbe extends Simulator.Probe.Empty {
              public void fireBefore(State state, int pc) {
                  long time = state.getCycles();
  
                  for ( Pair p = endArray[pc]; p != null; p = p.startLink ) {
                      if ( lastEnter[p.start] < 0 ) continue;
                      p.record(time - lastEnter[p.start]);
                  }
  
                  lastEnter[pc] = time;
              }
          }
  
          public void report() {
              TermUtil.printSeparator("Trip time results for node "+simulator.getID());
              Terminal.printGreen("  start      end     count         avg         std        max        min");
              Terminal.nextln();
              TermUtil.printThinSeparator(Terminal.MAXLINE);
              for ( int cntr = 0; cntr < lastEnter.length; cntr++ )
                  for ( Pair p = startArray[cntr]; p != null; p = p.startLink ) {
                      if ( p.count > 0 ) p.report(Printer.STDOUT);
                  }
              Terminal.nextln();
          }
      }
  
      public Monitor newMonitor(Simulator s) {
          return new PointToPointMon(s);
      }
  }
  