Modifications for TAU tracing in the Charm++ framework.
[charm.git] / src / ck-perf / trace-common.C
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /**
9  * \addtogroup CkPerf
10 */
11 /*@{*/
12
13 #include <stdlib.h>
14 #if defined(_WIN32) && !defined(__CYGWIN__)
15 #include <direct.h>
16 #define CHDIR _chdir
17 #define GETCWD _getcwd
18 #define PATHSEP '\\'
19 #define PATHSEPSTR "\\"
20 #else
21 #include <unistd.h>
22 #define CHDIR chdir
23 #define GETCWD getcwd
24 #define PATHSEP '/'
25 #define PATHSEPSTR "/"
26 #endif
27
28 // cannot include charm++.h because trace-common.o is part of libconv-core.a
29 #include "charm.h"
30 #include "middle.h"
31 #include "cklists.h"
32 #include "ckliststring.h"
33
34 #include "trace.h"
35 #include "trace-common.h"
36 #include "allEvents.h"          //projector
37 #include "register.h" // for _entryTable
38
39 CpvCExtern(int, _traceCoreOn);   // projector
40
41 #ifdef CMK_OPTIMIZE
42 static int warned = 0;
43 #define OPTIMIZE_WARNING if (!warned) { warned=1;  CmiPrintf("\n\n!!!! Warning: tracing not available with CMK_OPTIMIZE!\n");  return;  }
44 #else
45 #define OPTIMIZE_WARNING /*empty*/
46 #endif
47
48 #define DEBUGF(x)          // CmiPrintf x
49
50 CkpvDeclare(TraceArray*, _traces);              // lists of all trace modules
51
52 /* trace for bluegene */
53 class TraceBluegene;
54 CkpvDeclare(TraceBluegene*, _tracebg);
55 int traceBluegeneLinked=0;                      // if trace-bluegene is linked
56
57 CkpvDeclare(double, traceInitTime);
58 CkpvDeclare(double, traceInitCpuTime);
59 CpvDeclare(int, traceOn);
60 CkpvDeclare(int, traceOnPe);
61 CkpvDeclare(char*, traceRoot);
62 CkpvDeclare(char*, selective);
63 CkpvDeclare(bool, verbose);
64
65 typedef void (*mTFP)();                   // function pointer for
66 CpvStaticDeclare(mTFP, machineTraceFuncPtr);    // machine user event
67                                           // registration
68
69 int _threadMsg, _threadChare, _threadEP;
70 int _packMsg, _packChare, _packEP;
71 int _unpackMsg, _unpackChare, _unpackEP;
72 int _dummyMsg, _dummyChare, _dummyEP;
73
74 /// decide parameters from command line
75 static void traceCommonInit(char **argv)
76 {
77   CmiArgGroup("Charm++","Tracing");
78   DEBUGF(("[%d] in traceCommonInit.\n", CkMyPe()));
79   CkpvInitialize(double, traceInitTime);
80   CkpvAccess(traceInitTime) = CmiStartTimer();
81   CkpvInitialize(double, traceInitCpuTime);
82   CkpvAccess(traceInitCpuTime) = TRACE_CPUTIMER();
83   CpvInitialize(int, traceOn);
84   CpvAccess(traceOn) = 0;
85   CpvInitialize(int, _traceCoreOn); //projector
86   CpvAccess(_traceCoreOn)=0; //projector
87   CpvInitialize(mTFP, machineTraceFuncPtr);
88   CpvAccess(machineTraceFuncPtr) = NULL;
89   CkpvInitialize(int, traceOnPe);
90   CkpvAccess(traceOnPe) = 1;
91
92   CkpvInitialize(bool, verbose);
93   if (CmiGetArgFlag(argv, "+traceWarn")) {
94     CkpvAccess(verbose) = true;
95   } else {
96     CkpvAccess(verbose) = false;
97   }
98
99   char *root;
100   char *temproot;
101   char *temproot2;
102   CkpvInitialize(char*, traceRoot);
103   if (CmiGetArgStringDesc(argv, "+traceroot", &temproot, "Directory to write trace files to")) {
104     int i;
105     // Trying to decide if the traceroot path is absolute or not. If it is not
106     // then create an absolute pathname for it.
107     if (temproot[0] != PATHSEP) {
108       temproot2 = GETCWD(NULL,0);
109       root = (char *)malloc(strlen(temproot2)+1+strlen(temproot)+1);
110       strcpy(root, temproot2);
111       strcat(root, PATHSEPSTR);
112       strcat(root, temproot);
113     } else {
114       root = (char *)malloc(strlen(temproot)+1);
115       strcpy(root,temproot);
116     }
117     for (i=strlen(argv[0])-1; i>=0; i--) if (argv[0][i] == PATHSEP) break;
118     i++;
119     CkpvAccess(traceRoot) = (char *)malloc(strlen(argv[0]+i) + strlen(root) + 2);    _MEMCHECK(CkpvAccess(traceRoot));
120     strcpy(CkpvAccess(traceRoot), root);
121     strcat(CkpvAccess(traceRoot), PATHSEPSTR);
122     strcat(CkpvAccess(traceRoot), argv[0]+i);
123     if (CkMyPe() == 0) 
124       CmiPrintf("Trace: traceroot: %s\n", CkpvAccess(traceRoot));
125   }
126   else {
127     CkpvAccess(traceRoot) = (char *) malloc(strlen(argv[0])+1);
128     _MEMCHECK(CkpvAccess(traceRoot));
129     strcpy(CkpvAccess(traceRoot), argv[0]);
130   }
131         /* added for TAU trace module. */
132         char *cwd;
133   CkpvInitialize(char*, selective);
134   if (CmiGetArgStringDesc(argv, "+selective", &temproot, "TAU's selective instrumentation file")) {
135     int i;
136     // Trying to decide if the traceroot path is absolute or not. If it is not
137     // then create an absolute pathname for it.
138     if (temproot[0] != PATHSEP) {
139       cwd = GETCWD(NULL,0);
140       root = (char *)malloc(strlen(cwd)+strlen(temproot)+2);
141       strcpy(root, cwd);
142       strcat(root, PATHSEPSTR);
143       strcat(root, temproot);
144     } else {
145       root = (char *)malloc(strlen(temproot)+1);
146       strcpy(root,temproot);
147     }
148     CkpvAccess(selective) = (char *) malloc(strlen(root)+1);
149     _MEMCHECK(CkpvAccess(selective));
150     strcpy(CkpvAccess(selective), root);
151     if (CkMyPe() == 0) 
152       CmiPrintf("Trace: selective: %s\n", CkpvAccess(selective));
153   }
154   else {
155     CkpvAccess(selective) = (char *) malloc(3);
156     _MEMCHECK(CkpvAccess(selective));
157     strcpy(CkpvAccess(selective), "");
158   }
159   
160 #ifdef __BLUEGENE__
161   if(BgNodeRank()==0) {
162 #else
163   if(CkMyRank()==0) {
164 #endif
165     _threadMsg = CkRegisterMsg("dummy_thread_msg", 0, 0, 0);
166     _threadChare = CkRegisterChare("dummy_thread_chare", 0);
167     CkRegisterChareInCharm(_threadChare);
168     _threadEP = CkRegisterEp("dummy_thread_ep", 0, _threadMsg,_threadChare, 0+CK_EP_INTRINSIC);
169
170     _packMsg = CkRegisterMsg("dummy_pack_msg", 0, 0, 0);
171     _packChare = CkRegisterChare("dummy_pack_chare", 0);
172     CkRegisterChareInCharm(_packChare);
173     _packEP = CkRegisterEp("dummy_pack_ep", 0, _packMsg,_packChare, 0+CK_EP_INTRINSIC);
174
175     _unpackMsg = CkRegisterMsg("dummy_unpack_msg", 0, 0, 0);
176     _unpackChare = CkRegisterChare("dummy_unpack_chare", 0);
177     CkRegisterChareInCharm(_unpackChare);
178     _unpackEP = CkRegisterEp("dummy_unpack_ep", 0, _unpackMsg,_unpackChare, 0+CK_EP_INTRINSIC);
179
180     _dummyMsg = CkRegisterMsg("dummy_msg", 0, 0, 0);
181     _dummyChare = CkRegisterChare("dummy_chare", 0);
182     CkRegisterChareInCharm(_dummyChare);
183     _dummyEP = CkRegisterEp("dummy_ep", 0, _dummyMsg,_dummyChare, 0+CK_EP_INTRINSIC);
184   }
185 }
186
187 /** Write out the common parts of the .sts file. */
188 extern void traceWriteSTS(FILE *stsfp,int nUserEvents) {
189   fprintf(stsfp, "MACHINE %s\n",CMK_MACHINE_NAME);
190   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes());
191   fprintf(stsfp, "TOTAL_CHARES %d\n", _chareTable.size());
192   fprintf(stsfp, "TOTAL_EPS %d\n", _entryTable.size());
193   fprintf(stsfp, "TOTAL_MSGS %d\n", _msgTable.size());
194   fprintf(stsfp, "TOTAL_PSEUDOS %d\n", 0);
195   fprintf(stsfp, "TOTAL_EVENTS %d\n", nUserEvents);
196   int i;
197   for(i=0;i<_chareTable.size();i++)
198     fprintf(stsfp, "CHARE %d %s\n", i, _chareTable[i]->name);
199   for(i=0;i<_entryTable.size();i++)
200     fprintf(stsfp, "ENTRY CHARE %d %s %d %d\n", i, _entryTable[i]->name,
201                  _entryTable[i]->chareIdx, _entryTable[i]->msgIdx);
202   for(i=0;i<_msgTable.size();i++)
203     fprintf(stsfp, "MESSAGE %d %d\n", i, _msgTable[i]->size);
204 }
205
206 extern "C"
207 void traceCommonBeginIdle(void *proj,double curWallTime)
208 {
209   ((TraceArray *)proj)->beginIdle(curWallTime);
210 }
211  
212 extern "C"
213 void traceCommonEndIdle(void *proj,double curWallTime)
214 {
215   ((TraceArray *)proj)->endIdle(curWallTime);
216 }
217
218 void TraceArray::traceBegin() {
219   if (n==0) return; // No tracing modules registered.
220 #if ! CMK_TRACE_IN_CHARM
221   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
222   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
223 #endif
224   ALLDO(traceBegin());
225 }
226
227 void TraceArray::traceEnd() {
228   if (n==0) return; // No tracing modules registered.
229   ALLDO(traceEnd());
230 #if ! CMK_TRACE_IN_CHARM
231   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
232   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
233 #endif
234 }
235
236 /*Install the beginIdle/endIdle condition handlers.*/
237 extern "C" void traceBegin(void) {
238   OPTIMIZE_WARNING
239   DEBUGF(("[%d] traceBegin called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
240   if (CpvAccess(traceOn)==1) return;
241   CkpvAccess(_traces)->traceBegin();
242   CpvAccess(traceOn) = 1;
243 }
244
245 /*Cancel the beginIdle/endIdle condition handlers.*/
246 extern "C" void traceEnd(void) {
247   OPTIMIZE_WARNING
248   DEBUGF(("[%d] traceEnd called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
249   if (CpvAccess(traceOn)==0) return;
250   CkpvAccess(_traces)->traceEnd();
251   CpvAccess(traceOn) = 0;
252 }
253
254 static int checkTraceOnPe(char **argv)
255 {
256   int i;
257   int traceOnPE = 1;
258   char *procs = NULL;
259 #if CMK_BLUEGENE_CHARM
260   // check bgconfig file for settings
261   traceOnPE=0;
262   if (BgTraceProjectionOn(CkMyPe())) traceOnPE = 1;
263 #endif
264   if (CmiGetArgStringDesc(argv, "+traceprocessors", &procs, "A list of processors to trace, e.g. 0,10,20-30"))
265   {
266     CkListString procList(strdup(procs));
267     traceOnPE = procList.includes(CkMyPe());
268   }
269   // must include pe 0, otherwise sts file is not generated
270   if (CkMyPe()==0) traceOnPE = 1;
271 #if !CMK_TRACE_IN_CHARM
272   /* skip communication thread */
273   traceOnPE = traceOnPE && (CkMyRank() != CkMyNodeSize());
274 #endif
275   return traceOnPE;
276 }
277
278 /// defined in moduleInit.C
279 void _createTraces(char **argv);
280
281 /**
282     traceInit:          called at Converse level
283     traceCharmInit:     called at Charm++ level
284 */
285 /// initialize trace framework, also create the trace module(s).
286 static inline void _traceInit(char **argv) 
287 {
288   CkpvInitialize(TraceArray *, _traces);
289   CkpvAccess(_traces) = new TraceArray;
290
291   // common init
292   traceCommonInit(argv);
293
294   // check if trace is turned on/off for this pe
295   CkpvAccess(traceOnPe) = checkTraceOnPe(argv);
296
297   // defined in moduleInit.C
298   _createTraces(argv);
299
300   // set trace on/off
301   CkpvAccess(_traces)->setTraceOnPE(CkpvAccess(traceOnPe));
302
303   if (CkpvAccess(_traces)->length() && !CmiGetArgFlagDesc(argv,"+traceoff","Disable tracing"))
304     traceBegin();
305 }
306
307 /// Converse version
308 extern "C" void traceInit(char **argv) 
309 {
310 #if ! CMK_TRACE_IN_CHARM
311   _traceInit(argv);
312 #endif
313   initTraceCore(argv);
314 }
315
316 /// Charm++ version
317 extern "C" void traceCharmInit(char **argv) 
318 {
319 #if CMK_TRACE_IN_CHARM
320   _traceInit(argv);
321 #endif
322 }
323
324 // CMK_OPTIMIZE is already guarded in convcore.c
325 extern "C"
326 void traceMessageRecv(char *msg, int pe)
327 {
328 #if ! CMK_TRACE_IN_CHARM
329   CkpvAccessOther(_traces, CmiRankOf(pe))->messageRecv(msg, pe);
330 #endif
331 }
332
333 // CMK_OPTIMIZE is already guarded in convcore.c
334 // converse thread tracing is not supported in blue gene simulator
335 // in BigSim, threads need to be traced manually (because virtual processors
336 // themselves are implemented as threads and we don't want them to be traced
337 // In BigSim, so far, only AMPI threads are traced.
338 extern "C"
339 void traceResume(CmiObjId *tid)
340 {
341     _TRACE_ONLY(CkpvAccess(_traces)->beginExecute(tid));
342     if(CpvAccess(_traceCoreOn))
343             resumeTraceCore();
344 }
345
346 extern "C"
347 void traceSuspend(void)
348 {
349   _TRACE_ONLY(CkpvAccess(_traces)->endExecute());
350 }
351
352 extern "C"
353 void traceAwaken(CthThread t)
354 {
355   CkpvAccess(_traces)->creation(0, _threadEP);
356 }
357
358 extern "C"
359 void traceUserEvent(int e)
360 {
361 #ifndef CMK_OPTIMIZE
362   if (CpvAccess(traceOn))
363     CkpvAccess(_traces)->userEvent(e);
364 #endif
365 }
366
367 extern "C"
368 void traceUserBracketEvent(int e, double beginT, double endT)
369 {
370 #ifndef CMK_OPTIMIZE
371   if (CpvAccess(traceOn) && CkpvAccess(_traces))
372     CkpvAccess(_traces)->userBracketEvent(e, beginT, endT);
373 #endif
374 }
375
376 extern "C"
377 void traceUserSuppliedData(int d)
378 {
379 #ifndef CMK_OPTIMIZE
380   if (CpvAccess(traceOn) && CkpvAccess(_traces))
381     CkpvAccess(_traces)->userSuppliedData(d);
382 #endif
383 }
384
385 extern "C"
386 void traceMemoryUsage()
387 {
388 #ifndef CMK_OPTIMIZE
389   long d = CmiMemoryUsage();
390
391   if (CpvAccess(traceOn) && CkpvAccess(_traces))
392     CkpvAccess(_traces)->memoryUsage(d);
393 #endif
394 }
395
396
397 extern "C"
398 void registerMachineUserEventsFunction(void (*eventRegistrationFunc)()) {
399   CmiAssert(CpvInitialized(machineTraceFuncPtr));
400   CpvAccess(machineTraceFuncPtr) = eventRegistrationFunc;
401 }
402
403 extern "C"
404 void (*registerMachineUserEvents())() {
405   CmiAssert(CpvInitialized(machineTraceFuncPtr));
406   if (CpvAccess(machineTraceFuncPtr) != NULL) {
407     return CpvAccess(machineTraceFuncPtr);
408   } else {
409     return NULL;
410   }
411 }
412
413 extern "C"
414 int traceRegisterUserEvent(const char*x, int e)
415 {
416 #ifndef CMK_OPTIMIZE
417   return CkpvAccess(_traces)->traceRegisterUserEvent(x, e);
418 #else
419   return 0;
420 #endif
421 }
422
423 extern "C"
424 void traceClearEps(void)
425 {
426   OPTIMIZE_WARNING
427   CkpvAccess(_traces)->traceClearEps();
428 }
429
430 extern "C"
431 void traceWriteSts(void)
432 {
433   OPTIMIZE_WARNING
434   CkpvAccess(_traces)->traceWriteSts();
435 }
436
437 extern "C"
438 void traceFlushLog(void)
439 {
440   OPTIMIZE_WARNING
441   CkpvAccess(_traces)->traceFlushLog();
442 }
443
444 /**
445     traceClose:         this function is called at Converse
446     traceCharmClose:    called at Charm++ level
447 */
448 extern "C"
449 void traceClose(void)
450 {
451 #if ! CMK_BLUEGENE_CHARM
452   OPTIMIZE_WARNING
453   CkpvAccess(_traces)->traceClose();
454 #endif   
455 }
456
457 extern "C"
458 void traceCharmClose(void)
459 {
460 #if CMK_BLUEGENE_CHARM
461   OPTIMIZE_WARNING
462   CkpvAccess(_traces)->traceClose();
463 #endif
464 }
465
466 /* **CW** Support for thread listeners. This makes a call to each
467    trace module which must support the call.
468 */
469 extern "C"
470 void traceAddThreadListeners(CthThread tid, envelope *e) {
471   _TRACE_ONLY(CkpvAccess(_traces)->traceAddThreadListeners(tid, e));
472 }
473
474 #if 0
475 // helper functions
476 int CkIsCharmMessage(char *msg)
477 {
478 //CmiPrintf("getMsgtype: %d %d %d %d %d\n", ((envelope *)msg)->getMsgtype(), CmiGetHandler(msg), CmiGetXHandler(msg), _charmHandlerIdx, index_skipCldHandler);
479   if ((CmiGetHandler(msg) == _charmHandlerIdx) &&
480          (CmiGetHandlerFunction(msg) == (CmiHandler)_processHandler))
481     return 1;
482   if (CmiGetXHandler(msg) == _charmHandlerIdx) return 1;
483   return 0;
484 }
485 #endif
486
487 // return 1 if any one of tracing modules is linked.
488 int  traceAvailable()
489 {
490 #ifdef CMK_OPTIMIZE
491   return 0;
492 #else
493   return CkpvAccess(_traces)->length()>0;
494 #endif
495 }
496
497 double CmiTraceTimer()
498 {
499   return TraceTimer();
500 }
501
502 void TraceArray::creation(envelope *env, int ep, int num)
503
504     if (_entryTable[ep]->traceEnabled)
505         ALLDO(creation(env, ep, num));
506 }
507
508 void TraceArray::creationMulticast(envelope *env, int ep, int num,
509                                    int *pelist)
510 {
511   if (_entryTable[ep]->traceEnabled)
512     ALLDO(creationMulticast(env, ep, num, pelist));
513 }
514
515 /*
516 extern "C" 
517 void registerFunction(char *name){
518         _TRACE_ONLY(CkpvAccess(_traces)->regFunc(name));
519 }
520 */
521
522 extern "C"
523 int traceRegisterFunction(const char* name, int idx) {
524 #ifndef CMK_OPTIMIZE
525   if(idx==-999){
526     CkpvAccess(_traces)->regFunc(name, idx);
527   } else {
528     CkpvAccess(_traces)->regFunc(name, idx, 1);
529   }
530   return idx;
531 #else
532   return 0;
533 #endif
534 }
535
536 extern "C" 
537 void traceBeginFuncProj(char *name,char *file,int line){
538          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(name,file,line));
539 }
540
541 extern "C"
542 void traceBeginFuncIndexProj(int idx,char *file,int line){
543          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(idx,file,line));
544 }
545
546 extern "C" 
547 void traceEndFuncProj(char *name){
548          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(name));
549 }
550
551 extern "C" 
552 void traceEndFuncIndexProj(int idx){
553          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(idx));
554 }
555
556 /*@}*/