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