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.arch.AbstractInstr;
  import avrora.core.*;
  import avrora.sim.Simulator;
  import avrora.sim.State;
  import avrora.sim.output.SimPrinter;
  import cck.text.*;
  import cck.util.Option;
  import cck.util.Util;
  
  /**
   * The <code>ProfileMonitor</code> class represents a monitor that can collect profiling information such as
   * counts and branchcounts about the program as it executes.
   *
   * @author Ben L. Titzer
   */
  public class TraceMonitor extends MonitorFactory {
  
      final Option.List FROMTO = newOptionList("trace-from", "",
              "The \"trace-from\" option specifies the list of program point pairs for which " +
              "to enable the tracing. The tracing will be enabled when the first point is entered " +
              "and be disabled when the second point is reached. Nesting of multiple point pairs " +
              "is handled correctly.");
      final Option.Long TIME = newOption("trace-start", 0,
              "The \"trace-start\" option specifies the time to start the instruction trace, in " +
              "clock cycles. This option can be useful for diagnosing problems in long simulations " +
              "that happens after a given time is reached.");
  
      /**
       * The <code>Monitor</code> class implements the monitor for the profiler. It contains a
       * <code>ProgramProfiler</code> instance which is a probe that is executed after every instruction that
       * collects execution counts for every instruction in the program.
       */
      public class Mon implements Monitor {
          public final Simulator simulator;
          public final SimPrinter printer;
          public final Program program;
          public final GlobalProbe PROBE;
          public int count;
          int nesting;
  
          public class GlobalProbe implements Simulator.Probe {
              public void fireBefore(State s, int addr) {
                  print(s, s.getInstr(addr));
              }
  
              public void fireAfter(State s, int addr) {
                  count++;
              }
          }
  
          public class StartProbe extends Simulator.Probe.Empty {
              int start, end;
              int traceNum;
              String pair;
  
              StartProbe(int s, int e) {
                  start = s;
                  end = e;
                  pair = StringUtil.addrToString(s)+":"+ StringUtil.addrToString(e);
              }
  
              public void fireBefore(State s, int addr) {
                  traceNum++;
                  if ( nesting == 0 ) {
                      print("trace ("+pair+") begin: "+traceNum+" --------------------------");
                      print(s, s.getInstr(addr));
                      simulator.insertProbe(PROBE);
                  } else {
                      print("nested ("+pair+") begin: "+traceNum+" --------------------------");
                  }
                  nesting++;
              }
          }
  
          public class StartEvent implements Simulator.Event {
              public void fire() {
                  simulator.insertProbe(PROBE);
              }
          }
  
          public class EndProbe extends Simulator.Probe.Empty {
              int start, end;
              String pair;
  
              EndProbe(int s, int e) {
                  start = s;
                  end = e;
                  pair = StringUtil.addrToString(s)+":"+StringUtil.addrToString(e);
              }
  
              public void fireAfter(State s, int addr) {
                  nesting--;
                  if ( nesting == 0 ) {
                      print("trace ("+pair+") end --------------------------");
                      simulator.removeProbe(PROBE);
                  } else {
                      print("nested ("+pair+") end --------------------------");
  
                  }
              }
          }
  
          int nextpc;
  
          private void print(State s, AbstractInstr i) {
              //"#k{%x}: #k{%s} %s", color, pc, color, i.getVariant(), i.getOperands()
  
              StringBuffer buf = printer.getBuffer(100);
              int pc = s.getPC();
              int color = pc == nextpc ? Terminal.COLOR_BLUE : Terminal.COLOR_CYAN;
              Terminal.append(color, buf, StringUtil.to0xHex(pc, 4));
              buf.append(": ");
              buf.append(i.toString());
              printer.printBuffer(buf);
              nextpc = pc + i.getSize();
          }
  
          private void print(String s) {
              printer.println(s);
          }
  
          Mon(Simulator s) {
              simulator = s;
              printer = s.getPrinter();
              program = s.getProgram();
              PROBE = new GlobalProbe();
              long time = TIME.get();
              if ( time > 0 ) {
                  // if start time is specified, add an event to start the global probe
                  s.insertEvent(new StartEvent(), time);
              } else if ( FROMTO.get().isEmpty() ){
                  // if there are no fromt/to pairs, insert the global probe
                  s.insertProbe(PROBE);
              } else {
                  // if there are from/to pairs, insert the start and end probes
                  addPairs();
              }
          }
  
          private void addPairs() {
              for (String str : FROMTO.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 addPair(int start, int end) {
              if ( program.readInstr(start) == null ) return;
              if ( program.readInstr(end) == null ) return;
  
              simulator.insertProbe(new StartProbe(start, end), start);
              simulator.insertProbe(new EndProbe(start, end), end);
          }
  
          /**
           * The <code>report()</code> method generates a textual report for the profiling information gathered
           * from the execution of the program. The result is a table of performance information giving the
           * number of executions of each instruction, compressed for basic blocks.
           */
          public void report() {
              TermUtil.printSeparator("Trace results for node "+simulator.getID());
              long cycles = simulator.getClock().getCount();
              float ipc = count / (float)cycles;
              TermUtil.reportQuantity("Instructions executed", count, "");
              TermUtil.reportQuantity("Program throughput", ipc, "instrs/cycle");
              TermUtil.reportQuantity("Program throughput", ipc * simulator.getClock().getHZ() / 1000000, "mips");
              Terminal.nextln();
          }
      }
  
      /**
       * The constructor for the <code>ProfileMonitor</code> class creates a factory that is capable of
       * producing profile monitors for each simulator passed.
       */
      public TraceMonitor() {
          super("The \"trace\" monitor traces the execution of the entire program " +
                  "by printing every instruction as it executes. ");
      }
  
      /**
       * The <code>newMonitor()</code> method creates a new monitor for the given simulator that is capable of
       * collecting performance information as the program executes.
       *
       * @param s the simulator to create the monitor for
       * @return an instance of the <code>Monitor</code> interface that tracks performance information from the
       *         program
       */
      public Monitor newMonitor(Simulator s) {
          return new Mon(s);
      }
  }
  