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