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