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