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