Changed coreprof macros to match coreprof.h, altered output to print self-time as...
[IRC.git] / Robust / CoreProf / Trace.java
1 import java.io.FileInputStream;
2 import java.io.InputStream;
3 import java.io.BufferedInputStream;
4 import java.util.Vector;
5 import java.util.Hashtable;
6 import java.util.Iterator;
7 import java.util.Set;
8
9 public class Trace {
10
11   // everything defined here should match coreprof.h
12   // definitions exactly
13   public static final int CP_EVENT_MASK           = 3;
14   public static final int CP_EVENT_BASESHIFT      = 8;
15                                                   
16   public static final int CP_EVENTTYPE_BEGIN      = 1;
17   public static final int CP_EVENTTYPE_END        = 2;
18   public static final int CP_EVENTTYPE_ONEOFF     = 3;
19
20   public static final int CP_EVENTID_MAIN         = 0x04;
21   public static final int CP_EVENTID_RUNMALLOC    = 0x05;
22   public static final int CP_EVENTID_RUNFREE      = 0x06;
23   public static final int CP_EVENTID_TASKDISPATCH = 0x07;
24   public static final int CP_EVENTID_TASKRETIRE   = 0x08;
25   public static final int CP_EVENTID_TASKSTALLVAR = 0x09;
26   public static final int CP_EVENTID_TASKSTALLMEM = 0x0a;
27
28
29   void initNames() {
30     eid2name = new Hashtable<Integer, String>();
31     eid2name.put( CP_EVENTID_MAIN,         "MAIN        " );
32     eid2name.put( CP_EVENTID_RUNMALLOC,    "RUNMALLOC   " );
33     eid2name.put( CP_EVENTID_RUNFREE,      "RUNFREE     " );
34     eid2name.put( CP_EVENTID_TASKDISPATCH, "TASKDISPATCH" );
35     eid2name.put( CP_EVENTID_TASKRETIRE,   "TASKRETIRE  " );
36     eid2name.put( CP_EVENTID_TASKSTALLVAR, "TASKSTALLVAR" );
37     eid2name.put( CP_EVENTID_TASKSTALLMEM, "TASKSTALLMEM" );
38   }
39   
40
41   public static void main( String args[] ) {
42     if( args.length != 1 ) {
43       System.out.println( "usage: <coreprof.dat file>" );
44       System.exit( 0 );
45     }
46     Trace t = new Trace( args[0] );    
47     t.printStats();
48   }
49
50
51   // event IDs are a word, timestamps are long ints
52   public static final int WORD_SIZE      = 4;
53   public static final int EVENT_SIZE     = WORD_SIZE;
54   public static final int TIMESTAMP_SIZE = WORD_SIZE*2;
55   public static final int STACKMAX       = 512;
56
57   int                           numThreads;
58   BufferedInputStream[]         threadNum2stream;
59   int[]                         threadNum2numWords;
60   Event[][]                     threadNum2eventStack;
61   Hashtable<Integer, Counter>[] threadNum2eid2c;
62   Hashtable<Integer, String>    eid2name;
63
64   // calculate this as the single-longest running event
65   // and use it as the parent of all other events
66   long programDuration;
67
68
69   public Trace( String filename ) {  
70     programDuration = 0;
71     openInputStreams( filename );
72     initNames();
73     readThreads();
74   }
75
76
77   protected void openInputStreams( String filename ) {
78
79     BufferedInputStream bis    = null;
80     int                 offset = 0;
81
82     try {
83       bis    = new BufferedInputStream( new FileInputStream( filename ) );
84       offset = readHeader( bis );
85       bis.close();
86     } catch( Exception e ) {
87       e.printStackTrace();
88       System.exit( -1 );
89     }
90
91     threadNum2stream = new BufferedInputStream[numThreads];
92     
93     for( int i = 0; i < numThreads; ++i ) {
94       try {
95
96         // point a thread's event stream to the
97         // beginning of its data within the input file
98         threadNum2stream[i] = 
99           new BufferedInputStream( new FileInputStream( filename ) );
100
101         int skip = offset;
102         while( skip > 0 ) {
103           skip -= threadNum2stream[i].skip( skip );
104         }
105
106         offset += WORD_SIZE*threadNum2numWords[i];
107
108       } catch( Exception e ) {
109         e.printStackTrace();
110         System.exit( -1 );
111       }
112     }
113   }
114
115
116   int readHeader( BufferedInputStream bis ) {
117
118     // check version
119     int version = readInt( bis );
120     if( version != 0 ) {
121       throw new Error( "Unsupported Version" );
122     }
123     int offset = WORD_SIZE;
124     
125     // read number of threads
126     numThreads = readInt( bis );
127     offset += WORD_SIZE;
128
129     // read number of words used for all events, per thread
130     threadNum2numWords   = new int[numThreads];
131     threadNum2eventStack = new Event[numThreads][STACKMAX];
132     for( int i = 0; i < numThreads; ++i ) {
133       threadNum2numWords[i] = readInt( bis );
134       offset += WORD_SIZE;
135     }
136     return offset;
137   }
138
139
140   public void readThreads() {
141     // cannot have array of generics, so this line generates
142     // a compiler warning, just grimace and move on  :oP
143     threadNum2eid2c = new Hashtable[numThreads];
144
145     for( int i = 0; i < numThreads; i++ ) {
146       threadNum2eid2c[i] = new Hashtable<Integer, Counter>();
147       readThread( i );
148     }
149   }
150
151   
152   public void readThread( int tNum ) {
153
154     BufferedInputStream         stream   = threadNum2stream    [tNum];
155     int                         numWords = threadNum2numWords  [tNum];
156     Event[]                     stack    = threadNum2eventStack[tNum];
157     Hashtable<Integer, Counter> eid2c    = threadNum2eid2c     [tNum];
158
159     int  depth     = 0;
160     long timeStamp = 0;
161     int  i         = 0;
162
163     while( i < numWords ) {
164       
165       int event = readInt ( stream );
166       timeStamp = readLong( stream );
167       i += 3;
168
169       int eventType = event &  CP_EVENT_MASK;
170       int eventID   = event >> CP_EVENT_BASESHIFT;
171
172       switch( eventType ) {
173
174         case CP_EVENTTYPE_BEGIN: {
175           depth = pushEvent( stack, depth, eid2c, eventID, timeStamp );
176         } break;
177
178         case CP_EVENTTYPE_END: {
179           depth = popEvent( stack, depth, eventID, timeStamp );
180         } break;    
181     
182       }
183     }
184
185     if( depth != 0 ) {
186       // worker threads currently do not exit gracefully, and therefore
187       // never register their MAIN END event, so if the mismatch is with
188       // MAIN BEGIN then treat it as fine, otherwise warn.
189       if( depth == 1 ) {
190         // the value of timestamp will be equal to whatever the last
191         // properly registered event for this thread was
192         depth = popEvent( stack, depth, CP_EVENTID_MAIN, timeStamp );
193       } else {
194         System.out.println( "Warning: unmatched event begin/end\n" );
195       }
196     }
197   }
198
199
200   protected int pushEvent( Event[] stack,
201                            int d,
202                            Hashtable<Integer, Counter> eid2c,
203                            int eventID,
204                            long timeStamp ) {
205     int depth = d;
206     Counter counter = eid2c.get( eventID );
207     if( counter == null ) {
208       counter = new Counter();
209       eid2c.put( eventID, counter );
210     }
211     counter.count++;
212     if( stack[depth] == null ) {
213       stack[depth] = new Event( timeStamp, eventID, counter );
214     } else {
215       stack[depth].timeStamp = timeStamp;
216       stack[depth].eventID   = eventID;
217       stack[depth].counter   = counter;
218     }
219     depth++;
220     if( depth == STACKMAX ) {
221       throw new Error( "Event stack overflow\n" );
222     }
223     return depth;
224   }
225
226
227   protected int popEvent( Event[] stack,
228                           int d,
229                           int eventID,
230                           long timeStamp ) {
231     int depth = d;
232     depth--;
233     if( depth < 0 ) {
234       throw new Error( "Event stack underflow\n" );
235     }
236     Event   e           = stack[depth];
237     long    elapsedTime = timeStamp - e.timeStamp;
238     Counter c           = e.counter;
239     c.totalTime += elapsedTime;
240     c.selfTime  += elapsedTime;    
241     if( depth - 1 >= 0 ) {
242       Counter cParent = stack[depth-1].counter;
243       cParent.selfTime -= elapsedTime;
244     }
245     if( elapsedTime > programDuration ) {
246       programDuration = elapsedTime;
247     }
248     return depth;
249   }
250
251
252
253   public static int readInt( InputStream is ) {
254     try {
255       int b1 = is.read();
256       int b2 = is.read();
257       int b3 = is.read();
258       int b4 = is.read();
259
260       int retval = (b4<<24)|(b3<<16)|(b2<<8)|b1;
261
262       if( retval < 0 ) {
263         throw new Error();
264       }
265       return retval;
266
267     } catch( Exception e ) {
268       throw new Error();
269     }
270   }
271
272
273   public static long readLong( InputStream is ) {
274     try {
275       long b1 = is.read();
276       long b2 = is.read();
277       long b3 = is.read();
278       long b4 = is.read();
279       long b5 = is.read();
280       long b6 = is.read();
281       long b7 = is.read();
282       long b8 = is.read();
283
284       long retval = 
285         (b8<<56)|(b7<<48)|(b6<<40)|(b5<<32)|
286         (b4<<24)|(b3<<16)|(b2<< 8)|b1;
287       
288       if( retval < 0 ) {
289         throw new Error();
290       }
291       return retval;
292       
293     } catch( Exception e ) {
294       throw new Error();
295     }
296   }
297
298
299   public void printStats() {
300     
301     for( int i = 0; i < numThreads; ++i ) {
302
303       System.out.println( "Thread "+i );
304       
305       for( Iterator<Integer> evit = threadNum2eid2c[i].keySet().iterator();
306            evit.hasNext();
307            ) {
308         Integer event     = evit.next();
309         Counter c         = threadNum2eid2c[i].get( event );
310         String  eventname = eid2name.containsKey( event ) ?
311                             eid2name.get( event )         :
312                             Integer.toString( event );
313
314         // time stamps are measured in processor ticks, so don't bother converting
315         // to time in secs, just figure out how much time events take in terms of
316         // other events, or the total program time
317
318         float tSelf_perc = 
319           100.0f *
320           new Long( c.selfTime  ).floatValue() /
321           new Long( c.totalTime ).floatValue();
322
323         System.out.println( "Event: "+eventname+
324                             " total time(ticks)="+c.totalTime+
325                             " self time(%)=" +tSelf_perc+
326                             " count="+c.count
327                             );
328       }
329       System.out.println("----------------------------------------------------");
330     }
331   }
332
333 }