projections generate topology file.
[charm.git] / src / ck-perf / trace-projections.h
1 /**
2  * \addtogroup CkPerf
3 */
4 /*@{*/
5
6 #ifndef _PROJECTIONS_H
7 #define _PROJECTIONS_H
8
9 #include <stdio.h>
10 #include <errno.h>
11 #include <unistd.h>
12
13 #include "trace.h"
14 #include "trace-common.h"
15 #include "ckhashtable.h"
16
17 #if CMK_HAS_COUNTER_PAPI
18 #include <papi.h>
19 #define NUMPAPIEVENTS 2
20 #endif
21
22 #if CMK_PROJECTIONS_USE_ZLIB
23 #include <zlib.h>
24 #endif
25
26 #include "pup.h"
27
28 #define PROJECTION_VERSION  "7.0"
29
30 #define PROJ_ANALYSIS 1
31
32 // Macro to make projections check for errors before an fprintf succeeds.
33 #define CheckAndFPrintF(f,string,data) \
34 do { \
35   int result = fprintf(f,string,data); \
36   if (result == -1) { \
37     CmiAbort("Projections I/O error!"); \
38   } \
39 } while(false)
40
41 /// a log entry in trace projection
42 class LogEntry {
43   public:
44     double time;
45     double endTime; // Should be used for all bracketed events. Currently only used for bracketed user supplied note
46     double cputime;
47     double recvTime;
48     int event;
49     int pe;
50     unsigned short mIdx;
51     unsigned short eIdx;
52     int msglen;
53     CmiObjId   id;
54     int numpes;
55     int *pes;
56     int userSuppliedData;
57     char *userSuppliedNote;
58     unsigned long memUsage;
59
60     // this is taken out so as to provide a placeholder value for non-PAPI
61     // versions (whose value is *always* zero).
62     //int numPapiEvents;
63 #if CMK_HAS_COUNTER_PAPI
64     LONG_LONG_PAPI papiValues[NUMPAPIEVENTS];
65 #endif
66     unsigned char type; 
67     char *fName;
68     int flen;
69
70   public:
71     
72     LogEntry() {
73       fName=NULL;flen=0;pes=NULL;numpes=0;userSuppliedNote = NULL;
74     }
75
76     LogEntry(double tm, unsigned char t, unsigned short m=0, 
77              unsigned short e=0, int ev=0, int p=0, int ml=0, 
78              CmiObjId *d=NULL, double rt=0., double cputm=0., int numPe=0) {
79       type = t; mIdx = m; eIdx = e; event = ev; pe = p; 
80       time = tm; msglen = ml;
81       if (d) id = *d; else {id.id[0]=id.id[1]=id.id[2]=id.id[3]=0; };
82       recvTime = rt; cputime = cputm;
83       // initialize for papi as well as non papi versions.
84 #if CMK_HAS_COUNTER_PAPI
85       //numPapiEvents = NUMPAPIEVENTS;
86 #else
87       //numPapiEvents = 0;
88 #endif
89       userSuppliedNote = NULL;
90       fName = NULL;
91       flen=0;
92       pes=NULL;
93       numpes=numPe;
94     }
95
96     LogEntry(double _time,unsigned char _type,unsigned short _funcID,
97              int _lineNum,char *_fileName){
98       time = _time;
99       type = _type;
100       mIdx = _funcID;
101       event = _lineNum;
102       userSuppliedNote = NULL;      
103       pes=NULL;
104       numpes=0;
105       setFName(_fileName);
106     }
107
108     // Constructor for User Supplied Data
109     LogEntry(double _time,unsigned char _type, int value,
110              int _lineNum,char *_fileName){
111       time = _time;
112       type = _type;
113       userSuppliedData = value;
114       userSuppliedNote = NULL;
115       pes=NULL;
116       numpes=0;
117       setFName(_fileName);
118     }
119
120     // Constructor for User Supplied Data
121     LogEntry(double _time,unsigned char _type, char* note,
122              int _lineNum,char *_fileName){
123       time = _time;
124       type = _type;
125       pes=NULL;
126       numpes=0;
127       setFName(_fileName);
128       if(note != NULL)
129         setUserSuppliedNote(note);
130     }
131
132
133    // Constructor for bracketed user supplied note
134     LogEntry(double bt, double et, unsigned char _type, char *note, int eventID){
135       time = bt;
136       endTime = et;
137       type = _type;
138       pes=NULL;
139       numpes=0;
140       event = eventID;
141       if(note != NULL)
142         setUserSuppliedNote(note);
143     }
144
145
146     // Constructor for multicast data
147     LogEntry(double tm, unsigned short m, unsigned short e, int ev, int p,
148              int ml, CmiObjId *d, double rt, int numPe, int *pelist){
149
150       type = CREATION_MULTICAST; 
151       mIdx = m; 
152       eIdx = e; 
153       event = ev; 
154       pe = p; 
155       time = tm; 
156       msglen = ml;
157       
158       if (d) id = *d; else {id.id[0]=id.id[1]=id.id[2]=id.id[3]=-1; };
159       recvTime = rt; 
160       numpes = numPe;
161       userSuppliedNote = NULL;
162       if (pelist != NULL) {
163         pes = new int[numPe];
164         for (int i=0; i<numPe; i++) {
165           pes[i] = pelist[i];
166         }
167       } else {
168         pes= NULL;
169       }
170
171     }
172
173
174     void setFName(char *_fileName){
175       if(_fileName == NULL){
176         fName = NULL;
177         flen = 0;
178       }else{
179         fName = new char[strlen(_fileName)+2];
180         fName[0] = ' ';
181         memcpy(fName+1,_fileName,strlen(_fileName)+1);
182         flen = strlen(fName)+1;
183       } 
184     }
185
186     // complementary function for adding papi data
187     void addPapi(LONG_LONG_PAPI *papiVals){
188 #if CMK_HAS_COUNTER_PAPI
189         memcpy(papiValues, papiVals, sizeof(LONG_LONG_PAPI)*NUMPAPIEVENTS);
190 #endif
191     }
192    
193     void setUserSuppliedData(int data){
194       userSuppliedData = data;
195     }
196
197     void setUserSuppliedNote(char *note){
198
199       int length = strlen(note)+1;
200       userSuppliedNote = new char[length];
201       memcpy(userSuppliedNote,note,length);
202       for(int i=0;i<length;i++){
203         if(userSuppliedNote[i] == '\n' || userSuppliedNote[i] == '\r'){
204           userSuppliedNote[i] = ' ';
205         }
206       }
207           
208     }
209         
210
211     /// A constructor for a memory usage record
212     LogEntry(unsigned char _type, double _time, long _memUsage) {
213       time = _time;
214       type = _type;
215       memUsage = _memUsage;
216       fName = NULL;
217       flen = 0;
218       pes=NULL;
219       numpes=0;
220     }
221
222
223     void *operator new(size_t s) {void*ret=malloc(s);_MEMCHECK(ret);return ret;}
224     void *operator new(size_t, void *ptr) { return ptr; }
225     void operator delete(void *ptr) {free(ptr); }
226 #if defined(WIN32) || CMK_MULTIPLE_DELETE
227     void operator delete(void *, void *) { }
228 #endif
229
230     void setNewStartTime(double t) {
231       time -= t;
232       if (endTime>=t) endTime -= t;
233       if (recvTime>=t) recvTime -= t;
234     }
235
236     void pup(PUP::er &p);
237     ~LogEntry(){
238       if (fName) delete [] fName;
239       if (userSuppliedNote) delete [] userSuppliedNote;
240     }
241 };
242
243 class TraceProjections;
244
245 /// log pool in trace projection
246 class LogPool {
247   friend class TraceProjections;
248 #ifdef PROJ_ANALYSIS
249   // The macro is here "just-in-case". Somehow, it seems it is not necessary
250   //   to declare friend classes ahead of time in C++.
251   friend class TraceProjectionsBOC;
252   friend class KMeansBOC;
253 #endif  //PROJ_ANALYSIS
254   friend class controlPointManager;
255   private:
256     bool writeData;
257     unsigned int poolSize;
258     unsigned int numEntries;
259     LogEntry *pool;
260     FILE *fp;
261     FILE *deltafp;
262     FILE *stsfp;
263     FILE *rcfp;
264     FILE *topofp;
265     char *fname;
266     char *dfname;
267     char *pgmname;
268     int binary;
269     int nSubdirs;
270 #if CMK_PROJECTIONS_USE_ZLIB
271     gzFile deltazfp;
272     gzFile zfp;
273     int compressed;
274 #endif
275     // **CW** prevTime stores the timestamp of the last event
276     // written out to log. This allows the implementation of
277     // simple delta encoding and should only be used when
278     // writing out logs.
279     double prevTime;
280     double timeErr;
281     double globalStartTime; // used at the end on Pe 0 only
282     double globalEndTime; // used at the end on Pe 0 only
283
284     int numPhases;
285     bool hasFlushed;
286     bool *keepPhase;  // one decision per phase
287
288     int headerWritten;
289     bool fileCreated;
290     void writeHeader();
291   public:
292     LogPool(char *pgm);
293     ~LogPool();
294     void setBinary(int b) { binary = b; }
295     void setNumSubdirs(int n) { nSubdirs = n; }
296 #if CMK_PROJECTIONS_USE_ZLIB
297     void setCompressed(int c) { compressed = c; }
298 #endif
299     void createFile(const char *fix="");
300     void createSts(const char *fix="");
301     void createTopo(const char *fix="");
302     void createRC();
303     void openLog(const char *mode);
304     void closeLog(void);
305     void writeLog(void);
306     void write(int writedelta);
307     void writeSts(void);
308     void writeSts(TraceProjections *traceProj);
309     void writeRC(void);
310     void writeTopo();
311
312     void initializePhases() {
313       keepPhase = new bool[numPhases];
314       for (int i=0; i<numPhases; i++) {
315         keepPhase[i] = true;
316       }
317     }
318
319     void setAllPhases(bool val) {
320       for (int i=0; i<numPhases; i++) {
321         keepPhase[i] = val;
322       }
323     }
324
325     void add(unsigned char type, unsigned short mIdx, unsigned short eIdx,
326              double time, int event, int pe, int ml=0, CmiObjId* id=0, 
327              double recvT=0.0, double cpuT=0.0, int numPe=0);
328
329     // complementary function to set papi info to current log entry
330     // must be called after an add()
331     void addPapi(LONG_LONG_PAPI *papVals) {
332       pool[numEntries-1].addPapi(papVals);
333     }
334
335         /** add a record for a user supplied piece of data */
336         void addUserSupplied(int data);
337
338         /** add a record for a user supplied piece of data */
339         void addUserSuppliedNote(char *note);
340
341
342         void add(unsigned char type,double time,unsigned short funcID,int lineNum,char *fileName);
343   
344         void addMemoryUsage(unsigned char type,double time,double memUsage);
345         void addUserSuppliedBracketedNote(char *note, int eventID, double bt, double et);
346
347     void addCreationMulticast(unsigned short mIdx,unsigned short eIdx,double time,int event,int pe, int ml=0, CmiObjId* id=0, double recvT=0., int numPe=0, int *pelist=NULL);
348     void flushLogBuffer();
349     void postProcessLog();
350
351     void setWriteData(bool b){
352       writeData = b;
353     }
354     void modLastEntryTimestamp(double ts);
355
356     void setNewStartTime() {
357       for(UInt i=0; i<numEntries; i++) pool[i].setNewStartTime(globalStartTime);
358     }
359 };
360
361 /*
362         class that represents a key in a CkHashtable with a string as a key
363 */
364 class StrKey {
365         char *str;
366         int len;
367         unsigned int key;
368         public:
369         StrKey(char *_str,int _len){
370                 str = _str;
371                 len = _len;
372                 key = 0;
373                 for(int i=0;i<len;i++){
374                         key += str[i];
375                 }
376         }
377         static CkHashCode staticHash(const void *k,size_t){
378                 return ((StrKey *)k)->key;
379         }
380         static int staticCompare(const void *a,const void *b,size_t){
381                 StrKey *p,*q;
382                 p = (StrKey *)a;
383                 q = (StrKey *)b;
384                 if(p->len != q->len){
385                         return 0;
386                 }
387                 for(int i=0;i<p->len;i++){
388                         if(p->str[i] != q->str[i]){
389                                 return 0;
390                         }
391                 }
392                 return 1;
393         }
394         inline CkHashCode hash() const{
395                 return key;
396         }
397         inline int compare(const StrKey &t) const {
398                 if(len != t.len){
399                         return 0;
400                 }
401                 for(int i=0;i<len;i++){
402                         if(str[i] != t.str[i]){
403                                 return 0;
404                         }       
405                 }
406                 return 1;
407         }
408         inline char *getStr(){
409                 return str;
410         }
411 };
412
413 class NestedEvent {
414  public:
415   int event, msgType, ep, srcPe, ml;
416   CmiObjId *idx;
417   NestedEvent() {}
418   NestedEvent(int _event, int _msgType, int _ep, int _srcPe, int _ml, CmiObjId *_idx) :
419     event(_event), msgType(_msgType), ep(_ep), srcPe(_srcPe), ml(_ml), idx(_idx) { }
420 };
421
422 /// class for recording trace projections events 
423 /**
424   TraceProjections will log Converse/Charm++ events and write into .log files;
425   events descriptions will be written into .sts file.
426 */
427 class TraceProjections : public Trace {
428 #ifdef PROJ_ANALYSIS
429   // The macro is here "just-in-case". Somehow, it seems it is not necessary
430   //   to declare friend classes ahead of time in C++.
431   friend class TraceProjectionsBOC;
432   friend class KMeansBOC;
433 #endif // PROJ_ANALYSIS
434  private:
435     LogPool* _logPool;        /**<  logpool for all events */
436     int curevent;
437     int execEvent;
438     int execEp;
439     int execPe;
440     int inEntry;
441     int computationStarted;
442
443     int funcCount;
444     CkHashtableT<StrKey,int> funcHashtable;
445
446     int traceNestedEvents;
447     CkQ<NestedEvent> nestedEvents;
448     
449     int currentPhaseID;
450     LogEntry* lastPhaseEvent;
451
452     //as user now can specify the idx, it's possible that user may specify an existing idx
453     //so that we need a data structure to track idx. --added by Chao Mei
454     CkVec<int> idxVec;
455     int idxRegistered(int idx);    
456 #if CMK_HAS_COUNTER_PAPI
457     int papiEventSet;
458     LONG_LONG_PAPI papiValues[NUMPAPIEVENTS];
459 #endif
460
461   public:
462     int converseExit; // used for exits that bypass CkExit.
463     double endTime;
464
465     TraceProjections(char **argv);
466     void userEvent(int e);
467     void userBracketEvent(int e, double bt, double et);
468     void userSuppliedBracketedNote(char*, int, double, double);
469
470     void userSuppliedData(int e);
471     void userSuppliedNote(char* note);
472     void memoryUsage(double m);
473     void creation(envelope *e, int epIdx, int num=1);
474     void creation(char *m);
475     void creationMulticast(envelope *e, int epIdx, int num=1, int *pelist=NULL);
476     void creationDone(int num=1);
477     void beginExecute(envelope *e);
478     void beginExecute(char *msg);
479     void beginExecute(CmiObjId  *tid);
480     void beginExecute(int event,int msgType,int ep,int srcPe,int ml,CmiObjId *idx=NULL);
481     void changeLastEntryTimestamp(double ts);
482     void beginExecuteLocal(int event,int msgType,int ep,int srcPe,int ml,CmiObjId *idx=NULL);
483     void endExecute(void);
484     void endExecute(char *msg);
485     void endExecuteLocal(void);
486     void messageRecv(char *env, int pe);
487     void beginIdle(double curWallTime);
488     void endIdle(double curWallTime);
489     void beginPack(void);
490     void endPack(void);
491     void beginUnpack(void);
492     void endUnpack(void);
493     void enqueue(envelope *e);
494     void dequeue(envelope *e);
495     void beginComputation(void);
496     void endComputation(void);
497
498     int traceRegisterUserEvent(const char*, int);
499     void traceClearEps();
500     void traceWriteSts();
501     void traceClose();
502     void traceBegin();
503     void traceEnd();
504 #if CMK_SMP_TRACE_COMMTHREAD
505     void traceBeginOnCommThread();
506     void traceEndOnCommThread();
507 #endif
508     void traceCommSetMsgID(char *msg);
509     void traceGetMsgID(char *msg, int *pe, int *event);
510     void traceSetMsgID(char *msg, int pe, int event);
511     void traceFlushLog() { _logPool->flushLogBuffer(); }
512
513     //functions that perform function tracing
514     CkHashtableIterator *getfuncIterator(){return funcHashtable.iterator();};
515     int getFuncNumber(){return funcHashtable.numObjects();};
516     void regFunc(const char *name, int &idx, int idxSpecifiedByUser=0);
517     void beginFunc(char *name,char *file,int line);
518     void beginFunc(int idx,char *file,int line);
519     void endFunc(char *name);
520     void endFunc(int num);
521
522     /* start recognizing phases in trace-projections */
523     /* _TRACE_END_PHASE must be called collectively on all processors */
524     /*   in order for phase numbers to match up. */
525     void endPhase();
526
527     /* This is for moving projections to being a charm++ module */
528     void closeTrace(void);
529
530     void setWriteData(bool b){
531       _logPool->setWriteData(b);
532     }
533
534     /* for overiding basic thread listener support in Trace class */
535     virtual void traceAddThreadListeners(CthThread tid, envelope *e);
536 };
537
538 using namespace PUP;
539
540 class toProjectionsFile : public toTextFile {
541  protected:
542   virtual void bytes(void *p,int n,size_t itemSize,dataType t);
543  public:
544   //Begin writing to this file, which should be opened for ascii write.
545   toProjectionsFile(FILE *f_) :toTextFile(f_) {}
546 };
547 class fromProjectionsFile : public fromTextFile {
548  protected:
549   virtual void bytes(void *p,int n,size_t itemSize,dataType t);
550  public:
551   //Begin writing to this file, which should be opened for ascii read.
552   fromProjectionsFile(FILE *f_) :fromTextFile(f_) {}
553 };
554
555 #if CMK_PROJECTIONS_USE_ZLIB
556 class toProjectionsGZFile : public PUP::er {
557   gzFile f;
558  protected:
559   virtual void bytes(void *p,int n,size_t itemSize,dataType t);
560  public:
561   //Begin writing to this gz file, which should be opened for gz write.
562   toProjectionsGZFile(gzFile f_) :er(IS_PACKING), f(f_) {}
563 };
564 #endif
565
566
567
568
569 #if CMK_TRACE_ENABLED
570 /// Disable the outputting of the trace logs
571 void disableTraceLogOutput();
572
573 /// Enable the outputting of the trace logs
574 void enableTraceLogOutput();
575
576 /// Force the log file to be flushed
577 void flushTraceLog();
578 #else
579 static inline void disableTraceLogOutput() { }
580 static inline void enableTraceLogOutput() { }
581 static inline void flushTraceLog() { }
582 #endif
583
584 #endif
585
586 /*@}*/