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