Merge branch 'charm' of charmgit:charm into charm
[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
228     void setNewStartTime(double t) {
229       time -= t;
230       if (endTime>=t) endTime -= t;
231       if (recvTime>=t) recvTime -= t;
232     }
233
234     void pup(PUP::er &p);
235     ~LogEntry(){
236       if (fName) delete [] fName;
237       if (userSuppliedNote) delete [] userSuppliedNote;
238     }
239 };
240
241 class TraceProjections;
242
243 /// log pool in trace projection
244 class LogPool {
245   friend class TraceProjections;
246 #ifdef PROJ_ANALYSIS
247   // The macro is here "just-in-case". Somehow, it seems it is not necessary
248   //   to declare friend classes ahead of time in C++.
249   friend class TraceProjectionsBOC;
250   friend class KMeansBOC;
251 #endif  //PROJ_ANALYSIS
252   friend class controlPointManager;
253   private:
254     bool writeData;
255     unsigned int poolSize;
256     unsigned int numEntries;
257     LogEntry *pool;
258     FILE *fp;
259     FILE *deltafp;
260     FILE *stsfp;
261     FILE *rcfp;
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   public:
289     LogPool(char *pgm);
290     ~LogPool();
291     void setBinary(int b) { binary = b; }
292     void setNumSubdirs(int n) { nSubdirs = n; }
293 #if CMK_PROJECTIONS_USE_ZLIB
294     void setCompressed(int c) { compressed = c; }
295 #endif
296     void createFile(const char *fix="");
297     void createSts(const char *fix="");
298     void createRC();
299     void openLog(const char *mode);
300     void closeLog(void);
301     void writeLog(void);
302     void write(int writedelta);
303     void writeSts(void);
304     void writeSts(TraceProjections *traceProj);
305     void writeRC(void);
306
307     void initializePhases() {
308       keepPhase = new bool[numPhases];
309       for (int i=0; i<numPhases; i++) {
310         keepPhase[i] = true;
311       }
312     }
313
314     void setAllPhases(bool val) {
315       for (int i=0; i<numPhases; i++) {
316         keepPhase[i] = val;
317       }
318     }
319
320     void add(unsigned char type, unsigned short mIdx, unsigned short eIdx,
321              double time, int event, int pe, int ml=0, CmiObjId* id=0, 
322              double recvT=0.0, double cpuT=0.0, int numPe=0);
323
324     // complementary function to set papi info to current log entry
325     // must be called after an add()
326     void addPapi(int numPap, int *pap_ids, LONG_LONG_PAPI *papVals) {
327       pool[numEntries-1].addPapi(numPap, pap_ids, papVals);
328     }
329
330         /** add a record for a user supplied piece of data */
331         void addUserSupplied(int data);
332
333         /** add a record for a user supplied piece of data */
334         void addUserSuppliedNote(char *note);
335
336
337         void add(unsigned char type,double time,unsigned short funcID,int lineNum,char *fileName);
338   
339         void addMemoryUsage(unsigned char type,double time,double memUsage);
340         void addUserSuppliedBracketedNote(char *note, int eventID, double bt, double et);
341
342     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);
343     void flushLogBuffer();
344     void postProcessLog();
345
346     void setWriteData(bool b){
347       writeData = b;
348     }
349     void modLastEntryTimestamp(double ts);
350
351     void setNewStartTime() {
352       for(UInt i=0; i<numEntries; i++) pool[i].setNewStartTime(globalStartTime);
353     }
354 };
355
356 /*
357         class that represents a key in a CkHashtable with a string as a key
358 */
359 class StrKey {
360         char *str;
361         int len;
362         unsigned int key;
363         public:
364         StrKey(char *_str,int _len){
365                 str = _str;
366                 len = _len;
367                 key = 0;
368                 for(int i=0;i<len;i++){
369                         key += str[i];
370                 }
371         }
372         static CkHashCode staticHash(const void *k,size_t){
373                 return ((StrKey *)k)->key;
374         }
375         static int staticCompare(const void *a,const void *b,size_t){
376                 StrKey *p,*q;
377                 p = (StrKey *)a;
378                 q = (StrKey *)b;
379                 if(p->len != q->len){
380                         return 0;
381                 }
382                 for(int i=0;i<p->len;i++){
383                         if(p->str[i] != q->str[i]){
384                                 return 0;
385                         }
386                 }
387                 return 1;
388         }
389         inline CkHashCode hash() const{
390                 return key;
391         }
392         inline int compare(const StrKey &t) const {
393                 if(len != t.len){
394                         return 0;
395                 }
396                 for(int i=0;i<len;i++){
397                         if(str[i] != t.str[i]){
398                                 return 0;
399                         }       
400                 }
401                 return 1;
402         }
403         inline char *getStr(){
404                 return str;
405         }
406 };
407
408 class NestedEvent {
409  public:
410   int event, msgType, ep, srcPe, ml;
411   CmiObjId *idx;
412   NestedEvent() {}
413   NestedEvent(int _event, int _msgType, int _ep, int _srcPe, int _ml, CmiObjId *_idx) :
414     event(_event), msgType(_msgType), ep(_ep), srcPe(_srcPe), ml(_ml), idx(_idx) { }
415 };
416
417 /// class for recording trace projections events 
418 /**
419   TraceProjections will log Converse/Charm++ events and write into .log files;
420   events descriptions will be written into .sts file.
421 */
422 class TraceProjections : public Trace {
423 #ifdef PROJ_ANALYSIS
424   // The macro is here "just-in-case". Somehow, it seems it is not necessary
425   //   to declare friend classes ahead of time in C++.
426   friend class TraceProjectionsBOC;
427   friend class KMeansBOC;
428 #endif // PROJ_ANALYSIS
429  private:
430     LogPool* _logPool;        /**<  logpool for all events */
431     int curevent;
432     int execEvent;
433     int execEp;
434     int execPe;
435     int inEntry;
436     int computationStarted;
437
438     int funcCount;
439     CkHashtableT<StrKey,int> funcHashtable;
440
441     int traceNestedEvents;
442     CkQ<NestedEvent> nestedEvents;
443     
444     int currentPhaseID;
445     LogEntry* lastPhaseEvent;
446
447     //as user now can specify the idx, it's possible that user may specify an existing idx
448     //so that we need a data structure to track idx. --added by Chao Mei
449     CkVec<int> idxVec;
450     int idxRegistered(int idx);    
451 #if CMK_HAS_COUNTER_PAPI
452     int papiEventSet;
453     LONG_LONG_PAPI *papiValues;
454 #endif
455
456   public:
457     int converseExit; // used for exits that bypass CkExit.
458     double endTime;
459
460     TraceProjections(char **argv);
461     void userEvent(int e);
462     void userBracketEvent(int e, double bt, double et);
463     void userSuppliedBracketedNote(char*, int, double, double);
464
465     void userSuppliedData(int e);
466     void userSuppliedNote(char* note);
467     void memoryUsage(double m);
468     void creation(envelope *e, int epIdx, int num=1);
469     void creation(char *m);
470     void creationMulticast(envelope *e, int epIdx, int num=1, int *pelist=NULL);
471     void creationDone(int num=1);
472     void beginExecute(envelope *e);
473     void beginExecute(char *msg);
474     void beginExecute(CmiObjId  *tid);
475     void beginExecute(int event,int msgType,int ep,int srcPe,int ml,CmiObjId *idx=NULL);
476     void changeLastEntryTimestamp(double ts);
477     void beginExecuteLocal(int event,int msgType,int ep,int srcPe,int ml,CmiObjId *idx=NULL);
478     void endExecute(void);
479     void endExecute(char *msg);
480     void endExecuteLocal(void);
481     void messageRecv(char *env, int pe);
482     void beginIdle(double curWallTime);
483     void endIdle(double curWallTime);
484     void beginPack(void);
485     void endPack(void);
486     void beginUnpack(void);
487     void endUnpack(void);
488     void enqueue(envelope *e);
489     void dequeue(envelope *e);
490     void beginComputation(void);
491     void endComputation(void);
492
493     int traceRegisterUserEvent(const char*, int);
494     void traceClearEps();
495     void traceWriteSts();
496     void traceClose();
497     void traceBegin();
498     void traceEnd();
499 #if CMK_SMP_TRACE_COMMTHREAD
500     void traceBeginOnCommThread();
501     void traceEndOnCommThread();
502 #endif
503     void traceFlushLog() { _logPool->flushLogBuffer(); }
504
505     //functions that perform function tracing
506     CkHashtableIterator *getfuncIterator(){return funcHashtable.iterator();};
507     int getFuncNumber(){return funcHashtable.numObjects();};
508     void regFunc(const char *name, int &idx, int idxSpecifiedByUser=0);
509     void beginFunc(char *name,char *file,int line);
510     void beginFunc(int idx,char *file,int line);
511     void endFunc(char *name);
512     void endFunc(int num);
513
514     /* start recognizing phases in trace-projections */
515     /* _TRACE_END_PHASE must be called collectively on all processors */
516     /*   in order for phase numbers to match up. */
517     void endPhase();
518
519     /* This is for moving projections to being a charm++ module */
520     void closeTrace(void);
521
522     void setWriteData(bool b){
523       _logPool->setWriteData(b);
524     }
525
526     /* for overiding basic thread listener support in Trace class */
527     virtual void traceAddThreadListeners(CthThread tid, envelope *e);
528 };
529
530 using namespace PUP;
531
532 class toProjectionsFile : public toTextFile {
533  protected:
534   virtual void bytes(void *p,int n,size_t itemSize,dataType t);
535  public:
536   //Begin writing to this file, which should be opened for ascii write.
537   toProjectionsFile(FILE *f_) :toTextFile(f_) {}
538 };
539 class fromProjectionsFile : public fromTextFile {
540  protected:
541   virtual void bytes(void *p,int n,size_t itemSize,dataType t);
542  public:
543   //Begin writing to this file, which should be opened for ascii read.
544   fromProjectionsFile(FILE *f_) :fromTextFile(f_) {}
545 };
546
547 #if CMK_PROJECTIONS_USE_ZLIB
548 class toProjectionsGZFile : public PUP::er {
549   gzFile f;
550  protected:
551   virtual void bytes(void *p,int n,size_t itemSize,dataType t);
552  public:
553   //Begin writing to this gz file, which should be opened for gz write.
554   toProjectionsGZFile(gzFile f_) :er(IS_PACKING), f(f_) {}
555 };
556 #endif
557
558
559
560
561 #if CMK_TRACE_ENABLED
562 /// Disable the outputting of the trace logs
563 void disableTraceLogOutput();
564
565 /// Enable the outputting of the trace logs
566 void enableTraceLogOutput();
567
568 /// Force the log file to be flushed
569 void flushTraceLog();
570 #else
571 static inline void disableTraceLogOutput() { }
572 static inline void enableTraceLogOutput() { }
573 static inline void flushTraceLog() { }
574 #endif
575
576 #endif
577
578 /*@}*/