trace.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:17k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1991,1993 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *  This product includes software developed by the Computer Systems
  16.  *  Engineering Group at Lawrence Berkeley Laboratory.
  17.  * 4. Neither the name of the University nor of the Laboratory may be used
  18.  *    to endorse or promote products derived from this software without
  19.  *    specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  * @(#) $Header: /cvsroot/nsnam/nam-1/trace.cc,v 1.69 2002/05/03 01:16:39 buchheim Exp $ (LBL)
  34.  */
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <sys/types.h>
  38. #include <fcntl.h>
  39. #ifdef WIN32
  40. #include <windows.h>
  41. #include <io.h>
  42. #else
  43. #include <unistd.h>
  44. #include <sys/file.h>
  45. #endif
  46. #include <sys/stat.h>
  47. #include <ctype.h>
  48. #include "trace.h"
  49. #include "state.h"
  50. #include "packet.h"
  51. #include "address.h"
  52. #include "nam_stream.h"
  53. extern double time_atof(const char*);
  54. class TraceClass : public TclClass {
  55.  public:
  56.   TraceClass() : TclClass("Trace") {}
  57.   TclObject* create(int argc, const char*const* argv);
  58. } trace_class;
  59. TclObject* TraceClass::create(int argc, const char*const* argv) {
  60.   if (argc != 6)
  61.     return (0);
  62.   /*
  63.    * Open the trace file for reading and read its first line
  64.    * to be able to determine needed values: trace start time,
  65.    * trace duration, etc.
  66.    */
  67.   Trace* tr = new Trace(argv[4], argv[5]);
  68.   if (!tr->valid()) {
  69.     delete tr;
  70.     tr = NULL;
  71.   }
  72.   return (tr);
  73. }
  74. //----------------------------------------------------------------------
  75. // Trace::Trace(const char *fname, const char *animator) 
  76. //   - Create a new tracefile parser and event handler for
  77. //     file "fname" and connect it to the animator object
  78. //----------------------------------------------------------------------
  79. Trace::Trace(const char *fname, const char *animator) : 
  80.   handlers_(0),
  81.   nam_(0),
  82.   skipahead_mode_(0),
  83.   count_(0) {
  84.   
  85.   last_event_time_ = 0.0;
  86.   // Connect to nam animator
  87.   nam_ = (NetworkAnimator *)TclObject::lookup(animator);
  88.   strncpy(fileName_, fname, sizeof(fileName_)-1);
  89.   fileName_[sizeof(fileName_)-1] = 0;
  90.   nam_stream_ = NamStream::open(fileName_);
  91.   if (!nam_stream_->is_ok()) {
  92.     delete nam_stream_;
  93.     nam_stream_ = NULL;
  94.     perror("nam: fdopen");
  95.     // exit(1);
  96.     return; // tr->valid() will check this
  97.   }
  98.   findLastLine();
  99.   /*
  100.    * Go to the beginning of the file, read the first line and
  101.    * save its contents.
  102.    */
  103.   off_t pos = nam_stream_->seek(0, SEEK_SET);
  104.   assert(pos == 0);
  105.   /*
  106.    * Minimum time on the nam time slider is the time of the first
  107.    * trace event.
  108.    */
  109.   mintime_ = nextTime();
  110.   now_ = mintime_;
  111.   State::instance()->setTimes(mintime_, maxtime_);
  112.   // Initialize ParseTable
  113.   parse_table_ = new ParseTable(&pending_);
  114. }
  115. //----------------------------------------------------------------------
  116. // Trace::~Trace()
  117. //----------------------------------------------------------------------
  118. Trace::~Trace() {
  119.   delete parse_table_;
  120. }
  121. //----------------------------------------------------------------------
  122. //----------------------------------------------------------------------
  123. int
  124. Trace::valid() {
  125.   return (nam_stream_ && nam_stream_->is_ok());
  126. }
  127. //----------------------------------------------------------------------
  128. //----------------------------------------------------------------------
  129. int
  130. Trace::ReadEvent(double now, TraceEvent& e) {
  131.   /*
  132.    * If specified time is after the next event's time, read
  133.    * the next line and return 1. Otherwise, just return 0.
  134.    */
  135.   if (direction_ == FORWARDS) {
  136.     if ((pending_.time != TIME_EOF) && (pending_.time < now)) {
  137.       e = pending_;
  138.       scan();
  139.       return (1);
  140.     }
  141.   } else {
  142.     /*going backwards!*/
  143.     /*
  144.      * two occasions: 1) pending_.time > now, 
  145.      * 2) pending_.time = -1, which means go to the end of file
  146.      */
  147.     if ((pending_.time > now) || (pending_.time == TIME_EOF)) {
  148.       e = pending_;
  149.       scan();
  150.       if (pending_.time == TIME_EOF)
  151.         pending_.time = TIME_BOF;
  152.       return (1);
  153.     }
  154.   }
  155.   return (0);
  156. }
  157. //---------------------------------------------------------------------
  158. // int
  159. // Trace::nextLine()
  160. //
  161. // - This needs to be cleaned up and it may effect other parts of
  162. //   the file parsing code.  It is not very efficient with the amount
  163. //   of seeking going on.  
  164. //---------------------------------------------------------------------
  165. int
  166. Trace::nextLine() {
  167.   char * position;
  168.   if (direction_ == FORWARDS) {
  169.     // moving forward through the trace file
  170.     // We need to read in one line at a time
  171.     nam_stream_->gets(pending_.image, sizeof(pending_.image));
  172.     ++lineno_;
  173.     if (nam_stream_->eof()) {
  174.       Tcl& tcl = Tcl::instance();
  175.       tcl.evalf("%s stopmaxtime %f", nam()->name(), pending_.time);
  176.       return 0;
  177.     }
  178.   } else {
  179.     // moving backwards through the trace file 
  180.     position = nam_stream_->rgets(pending_.image, sizeof(pending_.image));
  181.     lineno_--;
  182.     if (position == NULL ) {
  183.       fprintf(stderr, "nam file reading error.n");
  184.       return -1; // signal reading error
  185.     }
  186.     if (nam_stream_->tell() == 0) {
  187.       // Beginning of file reached so we need to stop
  188.       return -1;
  189.     }  
  190.   }
  191.   return(nam_stream_->tell());
  192. }
  193. //---------------------------------------------------------------------
  194. // void
  195. // Trace::scan()
  196. //   - scan for the next valid nam event line in file
  197. //   - Once everything becomes stable you can to get rid of all the
  198. //     data type specific scan functions
  199. //---------------------------------------------------------------------
  200. void
  201. Trace::scan() {
  202.   char * time;
  203.   /*
  204.    * Read the next line in the trace file and store its contents
  205.    * depending on line type.
  206.    */
  207.   while (1) {
  208.     TraceEvent & p = pending_;
  209.     time = p.image;
  210.     p.offset = nextLine();
  211.     if (p.offset <= 0) {
  212.       // We reached the beginning of the file
  213.       pending_.time = TIME_EOF;
  214.       // Reset the last event time tracker
  215.       last_event_time_ = 0.0;
  216.       //fprintf(stderr, "EOF Reached.n");
  217.       return;
  218.     }
  219.     // -----------------------------------------------
  220.     // This -t * line skipping is a hack to
  221.     // enable the wireless code to work properly.
  222.     // All the -t * lines are parsed in tcl files
  223.     // before the animation starts and reparsing them
  224.     // seems to screw up the wireless stuff.
  225.     // ------------------------------------------------
  226.     
  227.     // Skip over -t * lines
  228.     while (*time != '') {
  229.       // Find the -t flag
  230.       if (*time == '-') {
  231.         time++;
  232.         if (*time == 't') {
  233.           // Eat the whitespace
  234.           time++;
  235.           while (*time == ' ' || *time == 't') {
  236.             time++;
  237.           } 
  238.           // We should be pointing to the
  239.           // -t flag value now
  240.           if (*time == '*') {
  241.             break;
  242.           }
  243.         }
  244.       } else {
  245.         time++;
  246.       }
  247.     }
  248.     
  249.     if (*time == '*') {
  250.       // Notify user if their tracefile has initialization events that
  251.       // are mixed in with animation events
  252.       switch (direction_) {
  253.         case FORWARDS:
  254.           // last_event_time_ is initialized to 0.0 since events cannot happen before this time.
  255.           if (last_event_time_ != 0.0) {
  256.             fprintf(stderr, "Warning: Initialization event is mixed in with animation events.n");
  257.             fprintf(stderr, "%s", p.image);
  258.             fprintf(stderr, "The above event should occur before all -t <time> animation events.nn");
  259.             fprintf(stderr, "last_time_event_ %fn", last_event_time_);
  260.           }
  261.           break;
  262.       }
  263.       last_event_time_ = 0.0;
  264.       if (p.offset <= 0) {
  265.       pending_.time = TIME_EOF;
  266.       //fprintf(stderr, "EOF Reached.n");
  267.       return;
  268.       }
  269.       continue;
  270.     } 
  271.     if (parse_table_->parseLine(p.image)) {
  272.       switch (direction_) {
  273.         // Notify user if their tracefile has records that are out of order
  274.         case FORWARDS:
  275.           if (pending_.time < last_event_time_) {
  276.             fprintf(stderr, "Warning: Tracefile events are not sorted by time.n");
  277.             fprintf(stderr, "%s", p.image);
  278.             fprintf(stderr, "The above event should occur at or after -t %f.nn",
  279.                             last_event_time_);
  280.           }
  281.           break;
  282.         case BACKWARDS:
  283.           if (pending_.time > last_event_time_ && last_event_time_ != 0.0) {
  284.             fprintf(stderr, "Warning: Tracefile events are not sorted by time.n");
  285.             fprintf(stderr, "%s", p.image);
  286.             fprintf(stderr, "The above event should occur at or before -t %f.nn",
  287.                             last_event_time_);
  288.           }
  289.           break;
  290.       }
  291.       last_event_time_ = pending_.time;
  292.       return;
  293.     } else {
  294.       fprintf(stderr, "Parsing error in event.n");
  295.     }
  296.     
  297.   } // end while
  298.   /* NOTREACHED */
  299. }
  300. //----------------------------------------------------------------------
  301. // void
  302. // Trace::findLastLine()
  303. //   - Go to the specified trace file's last line, verify that
  304. //     the file isn't empty and that its last line is correctly
  305. //     formatted. Compute the time interval for the entire trace
  306. //     assuming it started at time 0.
  307. //----------------------------------------------------------------------
  308. void Trace::findLastLine() {
  309.   off_t pos;
  310.   // should initialize it
  311.   direction_ = FORWARDS;
  312.   pending_.time = 0.0;
  313.   pending_.image[0] = 0;
  314.   /*
  315.    * Fake it?
  316.    */
  317.   if (!nam_stream_->seekable()) {
  318.     maxtime_ = 0.0;
  319.     return;
  320.   }
  321.   /*
  322.    * If we can, find the end of time.
  323.    */
  324.   char buf[TRACE_LINE_MAXLEN+1];
  325.   /* is there stuff in the file */
  326.   nam_stream_->seek(0, SEEK_END);
  327.   if (nam_stream_->tell() <= 1) {
  328.     fprintf(stderr, "nam: empty trace file `%s'.", fileName_);
  329.     exit(1);
  330.   }
  331.   /*
  332.    * If the file is larger than 'buf', go to the end of the file
  333.    * at the point just large enough to fit into 'buf'.
  334.    */
  335.   if (nam_stream_->tell() > (off_t)(sizeof(buf) - 1)) {
  336.     pos = nam_stream_->seek(- (sizeof(buf) - 1), SEEK_CUR);
  337.     assert(pos != -1);
  338.   } else 
  339.     /* If the file is smaller than 'buf', go to the head of file */
  340.     nam_stream_->seek(0, SEEK_SET);
  341.   int n = nam_stream_->read(buf, sizeof(buf) - 1);
  342.   if (n < 0) {
  343.     perror("read");
  344.     exit(1);
  345.   }
  346.   buf[n] = 0;
  347.   /*
  348.    * This next check is bogus, but zlib fails it.
  349.    * Go figure.
  350.    * Fortunately compressed files should not be seekable.
  351.    */
  352.   pos = nam_stream_->tell();
  353.   assert(pos != -1);
  354.   /* Error if the last line doesn't have 'n' in it. */
  355.   char *cp = strrchr(buf, 'n');
  356.   if (cp == 0) {
  357.     fprintf(stderr, "nam: error, missing newline on the last line of `%s'.",
  358.       fileName_);
  359.     exit(1);
  360.   }
  361.   /*
  362.    * Look for the first 'n' and check if the line following
  363.    * it has the correct type, i.e., it starts with any of the
  364.    * characters in [h+-dv].
  365.    */
  366.   *cp = 0;
  367.   cp = strrchr(buf, 'n');
  368.   if (cp == 0 || strchr("h+-dvrRanlfDEGPAmVNXWT", *++cp) == 0) {
  369.     fprintf(stderr, "nam: no dynamic animation events in `%s'.n", fileName_);
  370.     maxtime_ = 0.0;
  371.     return;
  372.     //fprintf(stderr, "     Unknown event %sn", buf);
  373.     //exit(1);
  374.   }
  375.   /*
  376.    * Compute the time interval from the beginning of the trace
  377.    * to the end.
  378.    * XXX this should include the duration of the last event but
  379.    *     since we changed the format of 'size' from 'time' to
  380.    *     'bytes', we can no longer figure this out.
  381.    */
  382.   double time = 0.;
  383.   (void)sscanf(++cp, " -t %lg", &time);
  384.   maxtime_ = time;
  385. }
  386. /* Go to the beginning of the file, read the first line and process it. */
  387. void Trace::rewind(long offset)
  388. {
  389.   nam_stream_->seek(offset, SEEK_SET);
  390.   //lineno_ = 0;
  391.   scan();
  392. }
  393. /*
  394.  * Put the specified trace handler to the beginning of the trace 
  395.  * handler list.
  396.  */
  397. void Trace::addHandler(TraceHandler* th)
  398. {
  399.   TraceHandlerList* p = new TraceHandlerList;
  400.   p->th = th;
  401.   p->next = handlers_;
  402.   handlers_ = p;
  403. }
  404. //----------------------------------------------------------------------
  405. // void
  406. // Trace::settime(double now, int timeSliderClicked)
  407. //   - Set the current trace time to 'now'.
  408. //----------------------------------------------------------------------
  409. void Trace::settime(double now, int timeSliderClicked) {
  410.   if (now < now_) {
  411. #ifdef OLDWAY
  412.     for (TraceHandlerList* p = handlers_; p != 0; p = p->next)
  413.       p->th->reset(now);
  414.     StateInfo si;
  415.     State::instance()->get(now, si);
  416.     rewind(si.offset);
  417. #endif
  418.     direction_=BACKWARDS;
  419.   } else {
  420.     direction_=FORWARDS;
  421.   }
  422.   now_ = now;
  423.   /*
  424.    * Scan the trace file until the event occurring at time 'now'
  425.    * is read. For each event scanned, pass it on to all trace
  426.    * handlers in the trace handler list so they can handle
  427.    * them as needed.
  428.    */
  429.   Tcl& tcl = Tcl::instance();
  430.   Tcl_Interp* interp = tcl.interp();
  431.   static char event[128];
  432.   TraceEvent e;
  433.   while (ReadEvent(now, e)) {
  434.      //if (e.time == TIME_BOF) {
  435.      if (pending_.time == TIME_BOF) {
  436.        // Reached the beginning of file during backtracking
  437.        // Rewind to the beginning
  438.        direction_ = FORWARDS;
  439.        rewind(0);
  440.        continue;
  441.      }
  442.     if (skipahead_mode_) {
  443.       count_ = 0;
  444.       skipahead_mode_ = 0;
  445.       tcl.evalf("%s normalspeed", nam()->name());
  446.     }
  447.      
  448.     // Find Handler for this pending event?
  449.     for (TraceHandlerList* p = handlers_; p != 0; p = p->next)
  450.       p->th->handle(e, now, direction_);
  451.     if (e.tt == 'h' && (e.pe.src == 0 || e.pe.dst == 0)) {
  452.       sprintf(event, "%d %d %.6f %d/", e.pe.src, e.pe.dst, 
  453.                                        e.time, e.pe.pkt.id);
  454.       if (timeSliderClicked)
  455.         tcl.result((const char *)event);
  456.       else
  457.         Tcl_AppendResult(interp, event, 0);
  458.     }
  459.   }
  460.   for (TraceHandlerList* p = handlers_; p != 0; p = p->next)
  461.     p->th->update(now);
  462.   if (Packet::count() == 0 && ++count_ == 2) {
  463.     count_ = 0;
  464.     skipahead_mode_ = 1;
  465.     tcl.evalf("%s speedup %g", nam()->name(), pending_.time);
  466.   }
  467. }
  468. /*
  469.  * Process 'nam trace' commands:
  470.  *   mintime - return the trace start time
  471.  *   maxtime - return the trace duration
  472.  *   connect - add the specified trace handler to the trace handler list
  473.  *   settime - reset current time to specified time and adjust the
  474.  *             display as needed
  475.  *   nxtevent - read next event in trace file and animate from that point
  476.  *   reset    - reset nam tracefile reading
  477.  */
  478. int Trace::command(int argc, const char* const* argv)
  479. {
  480.   Tcl& tcl = Tcl::instance();
  481.   if (argc == 2) {
  482.     if (strcmp(argv[1], "mintime") == 0) {
  483.       char* bp = tcl.buffer();
  484.       sprintf(bp, "%g", mintime_);
  485.       tcl.result(bp);
  486.       return (TCL_OK);
  487.     } else if (strcmp(argv[1], "maxtime") == 0) {
  488.       char* bp = tcl.buffer();
  489.       sprintf(bp, "%g", maxtime_);
  490.       tcl.result(bp);
  491.       return (TCL_OK);
  492.     } else if (strcmp(argv[1], "nxtevent") == 0) {
  493.       char* bp = tcl.buffer();
  494.       sprintf(bp, "%g", pending_.time);
  495.       tcl.result(bp);
  496.       return (TCL_OK);
  497.     } else if (strcmp(argv[1], "reset") == 0) {
  498.       nam_stream_->close();
  499.       nam_stream_ = NULL;
  500.       nam_stream_ = NamStream::open(fileName_);
  501.       if (nam_stream_->is_ok()) {
  502.         delete nam_stream_;
  503.         nam_stream_ = NULL;
  504.         perror("nam: fdopen");
  505.         // exit(1);
  506.         return TCL_ERROR; // tr->valid() will check this
  507.       }
  508.                         return (TCL_OK);
  509.     }
  510.   }
  511.   if (argc == 3) {
  512.     if (strcmp(argv[1], "connect") == 0) {
  513.       /*
  514.        * Get the handler for the specified trace and
  515.        * add it to the trace's list of handlers.
  516.        */
  517.       TraceHandler* th = (TraceHandler*)TclObject::lookup(argv[2]);
  518.       if (th == 0) {
  519.         tcl.resultf("nam connect: no such trace %s",
  520.               argv[2]);
  521.         return (TCL_ERROR);
  522.       }
  523.       addHandler(th);
  524.       return (TCL_OK);
  525.     }
  526.   }
  527.   if (argc == 4 ) {
  528.     if (strcmp(argv[1], "settime") == 0) {
  529.       /*
  530.        * Set current time to the specified time and update
  531.        * the display to reflect the new current time.
  532.        */
  533.       double now = atof(argv[2]);
  534.       int timeSliderClicked = atoi(argv[3]);
  535.       settime(now, timeSliderClicked);
  536.       return (TCL_OK);
  537.     }
  538.   }
  539.   return (TclObject::command(argc, argv));
  540. }