a122d210b5ea8cb295a007c73121d6cb150a8cd4
[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_COUNT_POOLALLOC  = 0x15;
19   public static final int CP_EVENTID_COUNT_POOLREUSE  = 0x16;
20   public static final int CP_EVENTID_WORKSCHEDGRAB    = 0x20;
21   public static final int CP_EVENTID_TASKDISPATCH     = 0x30;
22   public static final int CP_EVENTID_TASKEXECUTE      = 0x31;
23   public static final int CP_EVENTID_TASKRETIRE       = 0x32;
24   public static final int CP_EVENTID_TASKSTALLVAR     = 0x40;
25   public static final int CP_EVENTID_TASKSTALLMEM     = 0x41;
26
27
28   void initNames() {
29     eid2name = new Hashtable<Integer, String>();
30     eid2name.put( CP_EVENTID_MAIN,          "MAIN         " );
31     eid2name.put( CP_EVENTID_RUNMALLOC,     "RUNMALLOC    " );
32     eid2name.put( CP_EVENTID_RUNFREE,       "RUNFREE      " );
33     eid2name.put( CP_EVENTID_RUNFREE,       "POOLALLOC    " );
34     eid2name.put( CP_EVENTID_RUNFREE,       "POOLREUSE    " );
35     eid2name.put( CP_EVENTID_WORKSCHEDGRAB, "WORKSCHEDGRAB" );
36     eid2name.put( CP_EVENTID_TASKDISPATCH,  "TASKDISPATCH " );
37     eid2name.put( CP_EVENTID_TASKEXECUTE,   "TASKEXECUTE  " );
38     eid2name.put( CP_EVENTID_TASKRETIRE,    "TASKRETIRE   " );
39     eid2name.put( CP_EVENTID_TASKSTALLVAR,  "TASKSTALLVAR " );
40     eid2name.put( CP_EVENTID_TASKSTALLMEM,  "TASKSTALLMEM " );
41   }
42
43   Hashtable<Integer, String> eid2name;
44   
45
46
47   public static void main( String args[] ) {
48     if( args.length != 2 ) {
49       System.out.println( "usage: <coreprof.dat file> <trace out file>" );
50       System.exit( 0 );
51     }
52     Trace t = new Trace( args[0], args[1] );
53   }
54
55
56
57   // event IDs are a word, timestamps are long ints
58   public static final int WORD_SIZE      = 4;
59   public static final int EVENT_SIZE     = WORD_SIZE;
60   public static final int TIMESTAMP_SIZE = WORD_SIZE*2;
61
62   int          numThreads;
63   ThreadData[] threadData;
64
65
66
67   public Trace( String inFile, String outFile ) {
68
69     openInputStreams( inFile );
70
71     initNames();
72
73     for( int i = 0; i < numThreads; i++ ) {
74       readThread( i );
75     }
76
77     printStats( outFile );
78   }
79
80
81   public static int readInt( InputStream is ) {
82     try {
83       int b1 = is.read();
84       int b2 = is.read();
85       int b3 = is.read();
86       int b4 = is.read();
87
88       int retval = (b4<<24)|(b3<<16)|(b2<<8)|b1;
89
90       if( retval < 0 ) {
91         throw new Error();
92       }
93       return retval;
94
95     } catch( Exception e ) {
96       throw new Error();
97     }
98   }
99
100
101   public static long readLong( InputStream is ) {
102     try {
103       long b1 = is.read();
104       long b2 = is.read();
105       long b3 = is.read();
106       long b4 = is.read();
107       long b5 = is.read();
108       long b6 = is.read();
109       long b7 = is.read();
110       long b8 = is.read();
111
112       long retval = 
113         (b8<<56)|(b7<<48)|(b6<<40)|(b5<<32)|
114         (b4<<24)|(b3<<16)|(b2<< 8)|b1;
115       
116       if( retval < 0 ) {
117         throw new Error();
118       }
119       return retval;
120       
121     } catch( Exception e ) {
122       throw new Error();
123     }
124   }
125
126
127   protected void openInputStreams( String filename ) {
128
129     BufferedInputStream bis    = null;
130     int                 offset = 0;
131
132     try {
133       bis    = new BufferedInputStream( new FileInputStream( filename ) );
134       offset = readHeader( bis );
135       bis.close();
136     } catch( Exception e ) {
137       e.printStackTrace();
138       System.exit( -1 );
139     }
140
141     for( int i = 0; i < numThreads; ++i ) {
142       try {
143         // point a thread's event stream to the
144         // beginning of its data within the input file
145         threadData[i].dataStream = 
146           new BufferedInputStream( new FileInputStream( filename ) );
147
148         int skip = offset;
149         while( skip > 0 ) {
150           skip -= threadData[i].dataStream.skip( skip );
151         }
152
153         offset += WORD_SIZE*threadData[i].numDataWords;
154
155       } catch( Exception e ) {
156         e.printStackTrace();
157         System.exit( -1 );
158       }
159     }
160   }
161
162
163   int readHeader( BufferedInputStream bis ) {
164
165     // check version
166     int version = readInt( bis );
167     if( version != 0 ) {
168       throw new Error( "Unsupported Version" );
169     }
170     int offset = WORD_SIZE;
171     
172     // read number of threads
173     numThreads = readInt( bis );
174     offset += WORD_SIZE;
175
176     threadData = new ThreadData[numThreads];
177
178     // read number of words used for all events, per thread
179     for( int i = 0; i < numThreads; ++i ) {
180       threadData[i] = new ThreadData();
181       threadData[i].numDataWords = readInt( bis );
182       offset += WORD_SIZE;
183     }
184     return offset;
185   }
186
187   
188   public void readThread( int tNum ) {
189
190     System.out.print( "Reading thread "+tNum );
191
192     ThreadData tdata = threadData[tNum];
193     tdata.stackDepth = 0;
194     long timeStamp   = 0;
195     int  i           = 0;
196     int numProgress  = 10;
197
198     int progressChunk = tdata.numDataWords / numProgress;
199     int j;
200     boolean[] progress = new boolean[numProgress];
201     for( j = 0; j < numProgress; ++j ) {
202       progress[j] = false;
203     }
204     j = 0;
205     
206     while( i < tdata.numDataWords ) {
207       
208       if( !progress[j] && i > j*progressChunk ) {
209         System.out.print( "." );
210         progress[j] = true;
211         if( j < numProgress - 1 ) {
212           ++j;
213         }
214       }
215
216       int eventRaw = readInt ( tdata.dataStream );
217       timeStamp    = readLong( tdata.dataStream );
218       i += 3;
219
220       int eventType = eventRaw &  CP_EVENT_MASK;
221       int eventID   = eventRaw >> CP_EVENT_BASESHIFT;
222
223       switch( eventType ) {
224
225         case CP_EVENTTYPE_BEGIN: {
226           pushEvent( tdata, eventID, timeStamp );
227         } break;
228
229         case CP_EVENTTYPE_END: {
230           popEvent( tdata, eventID, timeStamp );
231         } break;    
232     
233       }
234     }
235
236     System.out.println( "" );
237
238     while( tdata.stackDepth > 0 ) {
239       // worker threads currently do not exit gracefully, and therefore
240       // may not register END events, so supply them with whatever the
241       // latest known timestamp is
242       EventSummary eventSummary = tdata.eventStack.get( tdata.stackDepth );
243
244       if( eventSummary == null ) {
245         // if there is no previous event it means there are no children
246         // events with a timestamp for the workaround, so just punt
247         break;
248       }
249
250       popEvent( tdata, eventSummary.eventID, timeStamp );
251
252       --tdata.stackDepth;
253     }
254   }
255
256
257   protected void pushEvent( ThreadData tdata,
258                             int        eventID,
259                             long       timeStamp ) {
260
261     EventSummary eventSummary = null;
262
263     if( tdata.stackDepth == 0 ) {
264       // there are no parents, so look in the rootEvents
265       // for an existing EventSummary of this type
266       for( Iterator<EventSummary> itr = tdata.rootEvents.iterator();
267            itr.hasNext();
268            ) {
269         EventSummary es = itr.next();
270         if( es.eventID == eventID ) {
271           eventSummary = es;
272           break;
273         }
274       }
275       if( eventSummary == null ) {
276         // there is no summary for this event type yet,
277         // so add it
278         eventSummary = new EventSummary( eventID );
279         tdata.rootEvents.add( eventSummary );
280       }
281
282     } else {
283       // look through the parent's children for an existing
284       // EventSummary of this type
285       EventSummary esParent = tdata.eventStack.get( tdata.stackDepth - 1 );
286       for( Iterator<EventSummary> itr = esParent.children.iterator();
287            itr.hasNext();
288            ) {
289         EventSummary es = itr.next();
290         if( es.eventID == eventID ) {
291           eventSummary = es;
292           break;
293         }
294       }
295       if( eventSummary == null ) {
296         // there is no summary for this event type yet,
297         // under this parent, so add it
298         eventSummary = new EventSummary( eventID );
299         esParent.children.add( eventSummary );
300         eventSummary.parent = esParent;
301       }
302     }
303
304     eventSummary.timeStampBeginLatestInstance = timeStamp;
305     
306     eventSummary.instanceCount++;
307
308     if( tdata.eventStack.size() <= tdata.stackDepth ) {
309       tdata.eventStack.setSize( 2*tdata.stackDepth + 20 );
310     }
311
312     tdata.eventStack.set( tdata.stackDepth, eventSummary );
313
314     tdata.stackDepth++;
315   }
316
317
318   protected void popEvent( ThreadData tdata,
319                            int        eventID,
320                            long       timeStamp ) {
321     tdata.stackDepth--;
322     if( tdata.stackDepth < 0 ) {
323       throw new Error( "Event stack underflow\n" );
324     }
325
326     EventSummary eventSummary = tdata.eventStack.get( tdata.stackDepth );
327     assert eventSummary != null;
328
329     if( eventSummary.eventID != eventID ) {
330       System.out.println( "Warning: event begin("+
331                           getEventName( eventSummary.eventID )+
332                           ") end("+
333                           getEventName( eventID )+
334                           ") mismatch!\n" );
335     }
336
337     long elapsedTime = 
338       timeStamp - eventSummary.timeStampBeginLatestInstance;
339
340     eventSummary.totalTime_ticks += elapsedTime;
341     eventSummary.selfTime_ticks  += elapsedTime;
342     
343     if( tdata.stackDepth - 1 >= 0 ) {
344       EventSummary esParent = tdata.eventStack.get( tdata.stackDepth-1 );
345       esParent.selfTime_ticks -= elapsedTime;
346     }
347   }
348
349
350
351   public void printStats( String filename ) {
352
353     System.out.println( "Printing..." );
354
355     try {
356       BufferedWriter bw = 
357         new BufferedWriter( new FileWriter( filename ) );
358       
359       for( int i = 0; i < numThreads; ++i ) {
360
361         ThreadData tdata = threadData[i];
362
363         bw.write( "----------------------------------\n" );
364         bw.write( "Thread "+i+"\n" );
365       
366         for( Iterator<EventSummary> itr = tdata.rootEvents.iterator();
367              itr.hasNext();
368              ) {
369           EventSummary es = itr.next();
370           printEventSummary( bw, es, 0 );
371         }
372
373         bw.write( "\n" );
374       }
375
376       bw.close();
377
378     } catch( IOException e ) {}
379   }
380
381
382   public String getEventName( int eventID ) {
383     return
384       eid2name.containsKey( eventID ) ?
385       eid2name.get        ( eventID ) :
386       Integer.toString    ( eventID );
387   }
388   
389
390   public void printEventSummary( BufferedWriter bw,
391                                  EventSummary   es, 
392                                  int            depth ) 
393     throws IOException {
394
395     String strIndent = "";
396     for( int i = 0; i < depth; ++i ) {
397       strIndent += "--";
398     }
399
400     String strEventName = getEventName( es.eventID );
401         
402     float tOfParent_perc;
403     String strPercParent = "";
404     if( es.parent != null ) {
405       float divisor = new Long( es.parent.totalTime_ticks ).floatValue();
406       if( divisor <= 0.00001f ) {
407         divisor = 0.00001f;
408       }
409
410       tOfParent_perc =
411         100.0f *
412         new Long( es.totalTime_ticks        ).floatValue() /
413         divisor;
414       
415       strPercParent = String.format( " %%ofParent=%5.1f",
416                                      tOfParent_perc );
417     }
418     
419     float tSelf_perc = 
420       100.0f *
421       new Long( es.selfTime_ticks  ).floatValue() /
422       new Long( es.totalTime_ticks ).floatValue();      
423
424     String strSelfStats =
425       String.format( " total(ticks)=%12dK, %%self=%5.1f, count=%d",
426                      es.totalTime_ticks/1000,
427                      tSelf_perc,
428                      es.instanceCount );
429
430     bw.write( strIndent+
431               strEventName+
432               strPercParent+
433               strSelfStats+
434               "\n" );
435
436     for( Iterator<EventSummary> itr = es.children.iterator();
437          itr.hasNext();
438          ) {
439       EventSummary esChild = itr.next();
440       printEventSummary( bw, esChild, depth + 1 );
441     }    
442   }
443 }