0db91ad87fbf70b196f1a01cd12d88c4ea4cb4cd
[IRC.git] / Robust / CoreProf / Trace.java
1 import java.io.*;
2 import java.util.*;
3
4 public class Trace {
5
6   // everything defined here should match coreprof.h
7   // definitions exactly
8   public static final int CP_EVENT_MASK           = 3;
9   public static final int CP_EVENT_BASESHIFT      = 8;
10                                                   
11   public static final int CP_EVENTTYPE_BEGIN      = 1;
12   public static final int CP_EVENTTYPE_END        = 2;
13   public static final int CP_EVENTTYPE_ONEOFF     = 3;
14
15   public static final int CP_EVENTID_MAIN             = 0x04;
16   public static final int CP_EVENTID_RUNMALLOC        = 0x10;
17   public static final int CP_EVENTID_RUNFREE          = 0x11;
18   public static final int CP_EVENTID_POOLALLOC        = 0x14;
19   public static final int CP_EVENTID_COUNT_POOLALLOC  = 0x15;
20   public static final int CP_EVENTID_COUNT_POOLREUSE  = 0x16;
21   public static final int CP_EVENTID_WORKSCHEDGRAB    = 0x20;
22   public static final int CP_EVENTID_WORKSCHEDSUBMIT  = 0x21;
23   public static final int CP_EVENTID_TASKDISPATCH     = 0x30;
24   public static final int CP_EVENTID_PREPAREMEMQ      = 0x31;
25   public static final int CP_EVENTID_TASKEXECUTE      = 0x40;
26   public static final int CP_EVENTID_TASKRETIRE       = 0x50;
27   public static final int CP_EVENTID_TASKSTALLVAR     = 0x60;
28   public static final int CP_EVENTID_TASKSTALLMEM     = 0x61;
29   public static final int CP_EVENTID_RCR_TRAVERSE     = 0x80;
30   public static final int CP_EVENTID_DEBUG_A          = 0x180;
31   public static final int CP_EVENTID_DEBUG_B          = 0x181;
32   public static final int CP_EVENTID_DEBUG_C          = 0x182;
33   public static final int CP_EVENTID_DEBUG_D          = 0x183;
34   public static final int CP_EVENTID_DEBUG_E          = 0x184;
35   public static final int CP_EVENTID_DEBUG_F          = 0x185;
36   public static final int CP_EVENTID_DEBUG_G          = 0x186;
37   public static final int CP_EVENTID_DEBUG_H          = 0x187;
38   public static final int CP_EVENTID_DEBUG_I          = 0x188;
39   public static final int CP_EVENTID_DEBUG_J          = 0x189;
40
41
42   void initNames() {
43     eid2name = new Hashtable<Integer, String>();
44     eid2name.put( CP_EVENTID_MAIN,              "MAIN           " );
45     eid2name.put( CP_EVENTID_RUNMALLOC,         "RUNMALLOC      " );
46     eid2name.put( CP_EVENTID_RUNFREE,           "RUNFREE        " );
47     eid2name.put( CP_EVENTID_POOLALLOC,         "POOLALLOC      " );
48     eid2name.put( CP_EVENTID_COUNT_POOLALLOC,   "POOLALLOC CNT  " );
49     eid2name.put( CP_EVENTID_COUNT_POOLREUSE,   "POOLREUSE CNT  " );
50     eid2name.put( CP_EVENTID_WORKSCHEDGRAB,     "WORKSCHEDGRAB  " );
51     eid2name.put( CP_EVENTID_WORKSCHEDSUBMIT,   "WORKSCHEDSUBMIT" );
52     eid2name.put( CP_EVENTID_TASKDISPATCH,      "TASKDISPATCH   " );
53     eid2name.put( CP_EVENTID_PREPAREMEMQ,       "PREPAREMEMQ    " );
54     eid2name.put( CP_EVENTID_TASKEXECUTE,       "TASKEXECUTE    " );
55     eid2name.put( CP_EVENTID_TASKRETIRE,        "TASKRETIRE     " );
56     eid2name.put( CP_EVENTID_TASKSTALLVAR,      "TASKSTALLVAR   " );
57     eid2name.put( CP_EVENTID_TASKSTALLMEM,      "TASKSTALLMEM   " );
58     eid2name.put( CP_EVENTID_RCR_TRAVERSE,      "RCR TRAVERSE   " );
59     eid2name.put( CP_EVENTID_DEBUG_A,           "DEBUG A        " );
60     eid2name.put( CP_EVENTID_DEBUG_B,           "DEBUG B        " );
61     eid2name.put( CP_EVENTID_DEBUG_C,           "DEBUG C        " );
62     eid2name.put( CP_EVENTID_DEBUG_D,           "DEBUG D        " );
63     eid2name.put( CP_EVENTID_DEBUG_E,           "DEBUG E        " );
64     eid2name.put( CP_EVENTID_DEBUG_F,           "DEBUG F        " );
65     eid2name.put( CP_EVENTID_DEBUG_G,           "DEBUG G        " );
66     eid2name.put( CP_EVENTID_DEBUG_H,           "DEBUG H        " );
67     eid2name.put( CP_EVENTID_DEBUG_I,           "DEBUG I        " );
68     eid2name.put( CP_EVENTID_DEBUG_J,           "DEBUG J        " );
69   }
70
71   Hashtable<Integer, String> eid2name;
72   
73
74
75   public static void main( String args[] ) {
76     if( args.length < 2 ) {
77       System.out.println( "usage: <coreprof.dat file> <trace out file> [-2txt]\n"+
78                           "\nThe -2txt option will take the raw binary events and spit\n"+
79                           "out every event as text in events.txt, useful for debugging\n"+
80                           "event mis-matches." );
81       System.exit( 0 );
82     }
83     String inputfile=null;
84     String outputfile=null;
85     boolean events=false;
86     HashSet<Integer> eventset=new HashSet<Integer>();
87     boolean hasinput=false;
88     long maxtime=-1;
89     long mintime=0;
90     long scale=1;
91
92     for(int i=0; i<args.length; i++) {
93       if (args[i].equals("-2txt")) {
94         events=true;
95       } else if (args[i].equals("-event")) {
96         eventset.add(Integer.parseInt(args[i+1]));
97         i++;
98       } else if (args[i].equals("-maxtime")) {
99         maxtime=Long.parseLong(args[i+1]);
100         i++;
101       } else if (args[i].equals("-mintime")) {
102         mintime=Long.parseLong(args[i+1]);
103         i++;
104       } else if (args[i].equals("-scale")) {
105         scale=Long.parseLong(args[i+1]);
106         i++;
107       } else {
108         if (hasinput) {
109           outputfile=args[i];
110         } else {
111           hasinput=true;
112           inputfile=args[i];
113         }
114       }
115     }
116
117     Trace t = new Trace(events, inputfile, outputfile, eventset, mintime, maxtime,scale);
118   }
119
120
121
122   // event IDs are a word, timestamps are long ints
123   public static final int WORD_SIZE      = 4;
124   public static final int EVENT_SIZE     = WORD_SIZE;
125   public static final int TIMESTAMP_SIZE = WORD_SIZE*2;
126
127   int          numThreads;
128   ThreadData[] threadData;
129   HashSet<Integer> eventset;
130
131   boolean        convert2txt;
132   BufferedWriter txtStream;
133
134   boolean             convert2plot;
135   BufferedWriter      bwPlot;
136   long                tSysZero;
137   long maxtime;
138   long mintime;
139   long scale;
140
141   public Trace( boolean c2txt, String inFile, String outFile,  HashSet<Integer> eventset, long mintime, long maxtime, long scale) {
142     this.eventset=eventset;
143     this.maxtime=maxtime;
144     this.mintime=mintime;
145     this.scale=scale;
146     convert2txt  = c2txt;
147     convert2plot = true;
148
149     openInputStreams( inFile );
150
151     initNames();
152
153     if (convert2plot) {
154       printPlotCmd();
155     }
156
157     for( int i = 0; i < numThreads; i++ ) {
158       readThread( i );
159     }
160
161     printStats( outFile );
162
163     if( convert2plot ) {
164       try {
165         bwPlot.write("plot [0:"+(globendtime/scale)+"] [-1:"+(numThreads+1)+"] -3\n");
166         bwPlot.close();
167       } catch (IOException e) {
168         e.printStackTrace();
169       }
170     }
171   }
172
173
174   public static int readInt( InputStream is ) {
175     try {
176       int b1 = is.read();
177       int b2 = is.read();
178       int b3 = is.read();
179       int b4 = is.read();
180
181       int retval = (b4<<24)|(b3<<16)|(b2<<8)|b1;
182
183       if( retval < 0 ) {
184         throw new Error();
185       }
186       return retval;
187
188     } catch( Exception e ) {
189       throw new Error();
190     }
191   }
192
193
194   public static long readLong( InputStream is ) {
195     try {
196       long b1 = is.read();
197       long b2 = is.read();
198       long b3 = is.read();
199       long b4 = is.read();
200       long b5 = is.read();
201       long b6 = is.read();
202       long b7 = is.read();
203       long b8 = is.read();
204
205       long retval = 
206         (b8<<56)|(b7<<48)|(b6<<40)|(b5<<32)|
207         (b4<<24)|(b3<<16)|(b2<< 8)|b1;
208       
209       if( retval < 0 ) {
210         throw new Error();
211       }
212       return retval;
213       
214     } catch( Exception e ) {
215       throw new Error();
216     }
217   }
218
219
220   protected void openInputStreams( String filename ) {
221
222     BufferedInputStream bis    = null;
223     int                 offset = 0;
224
225     try {
226       bis    = new BufferedInputStream( new FileInputStream( filename ) );
227       offset = readHeader( bis );
228       bis.close();
229
230     } catch( Exception e ) {
231       e.printStackTrace();
232       System.exit( -1 );
233     }
234
235     for( int i = 0; i < numThreads; ++i ) {
236       try {
237         // point a thread's event stream to the
238         // beginning of its data within the input file
239         threadData[i].dataStream = 
240           new BufferedInputStream( new FileInputStream( filename ) );
241
242         int skip = offset;
243         while( skip > 0 ) {
244           skip -= threadData[i].dataStream.skip( skip );
245         }
246         threadData[i].dataStream.mark(20);
247         int eventRaw = readInt ( threadData[i].dataStream );
248         long Stamp    = readLong( threadData[i].dataStream );
249         threadData[i].dataStream.reset();
250         
251         if (globalstarttime==-1||globalstarttime>Stamp)
252           globalstarttime=Stamp;
253
254
255         offset += WORD_SIZE*threadData[i].numDataWords;
256
257       } catch( Exception e ) {
258         e.printStackTrace();
259         System.exit( -1 );
260       }
261     }
262   }
263
264
265   int readHeader( BufferedInputStream bis ) {
266
267     // check version
268     int version = readInt( bis );
269     if( version != 0 ) {
270       throw new Error( "Unsupported Version" );
271     }
272     int offset = WORD_SIZE;
273     
274     // read number of threads
275     numThreads = readInt( bis );
276     offset += WORD_SIZE;
277
278     threadData = new ThreadData[numThreads];
279
280     // read number of words used for all events, per thread
281     for( int i = 0; i < numThreads; ++i ) {
282       threadData[i] = new ThreadData();
283       threadData[i].numDataWords = readInt( bis );
284       offset += WORD_SIZE;
285     }
286     return offset;
287   }
288
289   
290   public void readThread( int tNum ) {
291
292     System.out.print( "Reading thread "+tNum );
293
294     if( convert2txt ) {
295       try {
296         txtStream = new BufferedWriter( new FileWriter( "events.txt" ) );
297
298         txtStream.write( "\n\n\n\n" );
299         txtStream.write( "*************************************************\n" );
300         txtStream.write( "**  Thread "+tNum+"\n" );
301         txtStream.write( "*************************************************\n" );
302       } catch( IOException e ) {
303         e.printStackTrace();
304         System.exit( -1 );
305       }
306     }
307
308
309     ThreadData tdata = threadData[tNum];
310     tdata.stackDepth = 0;
311     long timeStamp   = 0;
312     int  i           = 0;
313     int numProgress  = 10;
314
315     int progressChunk = tdata.numDataWords / numProgress;
316     int j;
317     boolean[] progress = new boolean[numProgress];
318     for( j = 0; j < numProgress; ++j ) {
319       progress[j] = false;
320     }
321     j = 0;
322     
323     long lasttime=-1;
324     while( i < tdata.numDataWords ) {
325       
326       if( !progress[j] && i > j*progressChunk ) {
327         System.out.print( "." );
328         progress[j] = true;
329         if( j < numProgress - 1 ) {
330           ++j;
331         }
332       }
333
334       int eventRaw = readInt ( tdata.dataStream );
335       timeStamp    = readLong( tdata.dataStream );
336       i += 3;
337
338       int eventType = eventRaw &  CP_EVENT_MASK;
339       int eventID   = eventRaw >> CP_EVENT_BASESHIFT;
340
341       if (eventset.isEmpty()||eventset.contains(eventID))
342         switch( eventType ) {
343
344         case CP_EVENTTYPE_BEGIN: {
345           if( eventID == CP_EVENTID_MAIN ) {
346             tSysZero = timeStamp;
347           }
348           if( tdata.stackDepth>0 && convert2plot ) {
349             EventSummary esParent = tdata.eventStack.get( tdata.stackDepth - 1 );
350             long starttime=lasttime>esParent.timeStampBeginLatestInstance?lasttime:esParent.timeStampBeginLatestInstance;
351             addPointToPlot( tNum, esParent.eventID, starttime, timeStamp);
352           }
353
354           pushEvent( tdata, eventID, timeStamp );          
355         } break;
356
357         case CP_EVENTTYPE_END: {
358           if( convert2plot ) {
359             EventSummary esParent = tdata.eventStack.get( tdata.stackDepth - 1 );
360             long starttime=lasttime>esParent.timeStampBeginLatestInstance?lasttime:esParent.timeStampBeginLatestInstance;
361
362             addPointToPlot( tNum, esParent.eventID, starttime, timeStamp);
363             lasttime=timeStamp;
364           }
365           popEvent( tdata, eventID, timeStamp );
366         } break;    
367         }
368     }
369
370     System.out.println( "" );
371
372     while( tdata.stackDepth > 0 ) {
373       // worker threads currently do not exit gracefully, and therefore
374       // may not register END events, so supply them with whatever the
375       // latest known timestamp is
376       EventSummary eventSummary = tdata.eventStack.get( tdata.stackDepth);
377
378       if( eventSummary == null ) {
379         // if there is no previous event it means there are no children
380         // events with a timestamp for the workaround, so just punt
381         break;
382       }
383
384       popEvent( tdata, eventSummary.eventID, timeStamp );
385
386       --tdata.stackDepth;
387     }
388
389   }
390
391
392   protected void pushEvent( ThreadData tdata,
393                             int        eventID,
394                             long       timeStamp ) {
395
396     EventSummary eventSummary = null;
397
398     if( tdata.stackDepth == 0 ) {
399       // there are no parents, so look in the rootEvents
400       // for an existing EventSummary of this type
401       for( Iterator<EventSummary> itr = tdata.rootEvents.iterator();
402            itr.hasNext();
403            ) {
404         EventSummary es = itr.next();
405         if( es.eventID == eventID ) {
406           eventSummary = es;
407           break;
408         }
409       }
410       if( eventSummary == null ) {
411         // there is no summary for this event type yet,
412         // so add it
413         eventSummary = new EventSummary( eventID );
414         tdata.rootEvents.add( eventSummary );
415       }
416
417     } else {
418       // look through the parent's children for an existing
419       // EventSummary of this type
420       EventSummary esParent = tdata.eventStack.get( tdata.stackDepth - 1 );
421       for( Iterator<EventSummary> itr = esParent.children.iterator();
422            itr.hasNext();
423            ) {
424         EventSummary es = itr.next();
425         if( es.eventID == eventID ) {
426           eventSummary = es;
427           break;
428         }
429       }
430       if( eventSummary == null ) {
431         // there is no summary for this event type yet,
432         // under this parent, so add it
433         eventSummary = new EventSummary( eventID );
434         esParent.children.add( eventSummary );
435         eventSummary.parent = esParent;
436       }
437     }
438
439     eventSummary.timeStampBeginLatestInstance = timeStamp;
440     
441     eventSummary.instanceCount++;
442
443     if( tdata.eventStack.size() <= tdata.stackDepth ) {
444       tdata.eventStack.setSize( 2*tdata.stackDepth + 20 );
445     }
446
447     tdata.eventStack.set( tdata.stackDepth, eventSummary );
448
449
450     // print to the event text file (if needed) before
451     // updating the stack depth to get tabs right
452     if( convert2txt ) {
453       try {
454         for( int tabs = 0; tabs < tdata.stackDepth; ++tabs ) {
455           txtStream.write( "  " );
456         }
457         txtStream.write( "begin "+getEventName( eventID )+"@"+timeStamp+"\n" );
458       } catch( IOException e ) {
459         e.printStackTrace();
460         System.exit( -1 );
461       }
462     }
463
464
465     tdata.stackDepth++;
466   }
467
468
469   protected void popEvent( ThreadData tdata,
470                            int        eventID,
471                            long       timeStamp ) {
472     tdata.stackDepth--;
473
474
475     // print to the event text file (if needed) after
476     // updating the stack depth to get tabs right
477     if( convert2txt ) {
478       try {
479         for( int tabs = 0; tabs < tdata.stackDepth; ++tabs ) {
480           txtStream.write( "  " );
481         }
482         txtStream.write( "end   "+getEventName( eventID )+"@"+timeStamp+"\n" );
483       } catch( IOException e ) {
484         e.printStackTrace();
485         System.exit( -1 );
486       }
487     }
488
489
490     if( tdata.stackDepth < 0 ) {
491       throw new Error( "Event stack underflow\n" );
492     }
493
494     EventSummary eventSummary = tdata.eventStack.get( tdata.stackDepth );
495     assert eventSummary != null;
496
497     if( eventSummary.eventID != eventID ) {
498       System.out.println( "Warning: event begin("+
499                           getEventName( eventSummary.eventID )+
500                           ") end("+
501                           getEventName( eventID )+
502                           ") mismatch!\n" );
503     }
504
505     long elapsedTime = 
506       timeStamp - eventSummary.timeStampBeginLatestInstance;
507
508     eventSummary.totalTime_ticks += elapsedTime;
509     eventSummary.selfTime_ticks  += elapsedTime;
510     
511     if( tdata.stackDepth - 1 >= 0 ) {
512       EventSummary esParent = tdata.eventStack.get( tdata.stackDepth-1 );
513       esParent.selfTime_ticks -= elapsedTime;
514     }
515   }
516
517   long globalstarttime=-1;
518   long globendtime=-1;
519
520   public void addPointToPlot( int thread, int eventID, long starttime, long endtime) {
521     try {
522       long nstart=starttime-globalstarttime-mintime;
523       long nend=endtime-globalstarttime-mintime;
524       if ((maxtime==-1 || (endtime-globalstarttime)<maxtime)&&(nend>0)) {
525         if (nend>globendtime)
526           globendtime=nend;
527         if (nstart<0)
528           nstart=0;
529         bwPlot.write( "set arrow from "+(nstart/scale)+","+thread+
530                       " to "+(nend/scale)+","+thread+" lt palette cb "+eventID+" nohead\n");
531       }
532     } catch( IOException e ) {
533       e.printStackTrace();
534       System.exit( -1 );
535     }
536   }
537
538
539
540   public void printStats( String filename ) {
541
542     System.out.println( "Printing..." );
543
544     try {
545       BufferedWriter bw = 
546         new BufferedWriter( new FileWriter( filename ) );
547       
548       for( int i = 0; i < numThreads; ++i ) {
549
550         ThreadData tdata = threadData[i];
551
552         bw.write( "----------------------------------\n" );
553         bw.write( "Thread "+i+"\n" );
554       
555         for( Iterator<EventSummary> itr = tdata.rootEvents.iterator();
556              itr.hasNext();
557              ) {
558           EventSummary es = itr.next();
559           printEventSummary( bw, es, 0 );
560         }
561
562         bw.write( "\n" );
563       }
564
565       bw.close();
566     } catch( IOException e ) {
567       e.printStackTrace();
568       System.exit( -1 );
569     }
570   }
571
572
573   public String getEventName( int eventID ) {
574     return
575       eid2name.containsKey( eventID ) ?
576       eid2name.get        ( eventID ) :
577       Integer.toString    ( eventID );
578   }
579   
580
581   public void printEventSummary( BufferedWriter bw,
582                                  EventSummary   es, 
583                                  int            depth ) 
584     throws IOException {
585
586     String strIndent = "";
587     for( int i = 0; i < depth; ++i ) {
588       strIndent += "--";
589     }
590
591     String strEventName = getEventName( es.eventID );
592         
593     float tOfParent_perc;
594     String strPercParent = "";
595     if( es.parent != null ) {
596       float divisor = new Long( es.parent.totalTime_ticks ).floatValue();
597       if( divisor <= 0.00001f ) {
598         divisor = 0.00001f;
599       }
600
601       tOfParent_perc =
602         100.0f *
603         new Long( es.totalTime_ticks        ).floatValue() /
604         divisor;
605       
606       strPercParent = String.format( " %%ofParent=%5.1f",
607                                      tOfParent_perc );
608     }
609     
610     float tSelf_perc = 
611       100.0f *
612       new Long( es.selfTime_ticks  ).floatValue() /
613       new Long( es.totalTime_ticks ).floatValue();      
614
615     String strSelfStats =
616       String.format( " total(ticks)=%12dK, %%self=%5.1f, count=%d, avgTicks=%d",
617                      es.totalTime_ticks/1000,
618                      tSelf_perc,
619                      es.instanceCount,
620                      (int)((float)es.totalTime_ticks/(float)es.instanceCount) );
621
622     bw.write( strIndent+
623               strEventName+
624               strPercParent+
625               strSelfStats+
626               "\n" );
627
628     for( Iterator<EventSummary> itr = es.children.iterator();
629          itr.hasNext();
630          ) {
631       EventSummary esChild = itr.next();
632       printEventSummary( bw, esChild, depth + 1 );
633     }    
634   }
635
636
637   public void printPlotCmd() {
638     try {
639       bwPlot = 
640         new BufferedWriter( new FileWriter( "plot.cmd" ) );
641     } catch( IOException e ) {
642       e.printStackTrace();
643       System.exit( -1 );
644     }    
645   }
646 }