add API to pass application annotation time to tracing framework
[charm.git] / src / ck-perf / trace-common.C
1 /**
2  * \addtogroup CkPerf
3 */
4 /*@{*/
5
6 #include <sys/stat.h>
7 #include <sys/types.h>
8
9 #include "charm.h"
10 #include "middle.h"
11 #include "cklists.h"
12 #include "ckliststring.h"
13
14 #include "trace.h"
15 #include "trace-common.h"
16 #include "allEvents.h"          //projector
17 #include "register.h" // for _entryTable
18
19 CpvCExtern(int, _traceCoreOn);   // projector
20
21 #if ! CMK_TRACE_ENABLED
22 static int warned = 0;
23 #define OPTIMIZE_WARNING if (!warned) { warned=1;  CmiPrintf("\n\n!!!! Warning: tracing not available without CMK_TRACE_ENABLED!\n");  return;  }
24 #else
25 #define OPTIMIZE_WARNING /*empty*/
26 #endif
27
28 #define DEBUGF(x)          // CmiPrintf x
29
30 CkpvDeclare(TraceArray*, _traces);              // lists of all trace modules
31
32 /* trace for bluegene */
33 class TraceBluegene;
34 CkpvDeclare(TraceBluegene*, _tracebg);
35 int traceBluegeneLinked=0;                      // if trace-bluegene is linked
36
37 CkpvDeclare(double, traceInitTime);
38 CkpvDeclare(double, traceInitCpuTime);
39 CpvDeclare(int, traceOn);
40 CkpvDeclare(int, traceOnPe);
41 CkpvDeclare(char*, traceRoot);
42 CkpvDeclare(char*, partitionRoot);
43 CkpvDeclare(int, traceRootBaseLength);
44 CkpvDeclare(char*, selective);
45 CkpvDeclare(bool, verbose);
46 CkpvDeclare(double, startUsefulWorkTimer);
47
48 typedef void (*mTFP)();                   // function pointer for
49 CpvStaticDeclare(mTFP, machineTraceFuncPtr);    // machine user event
50                                           // registration
51
52 int _threadMsg, _threadChare, _threadEP;
53 int _packMsg, _packChare, _packEP;
54 int _unpackMsg, _unpackChare, _unpackEP;
55 int _sdagMsg, _sdagChare, _sdagEP;
56
57 /// decide parameters from command line
58 static void traceCommonInit(char **argv)
59 {
60   CmiArgGroup("Charm++","Tracing");
61   DEBUGF(("[%d] in traceCommonInit.\n", CkMyPe()));
62   CkpvInitialize(double, traceInitTime);
63   CkpvAccess(traceInitTime) = CmiStartTimer();
64   CkpvInitialize(double, traceInitCpuTime);
65   CkpvAccess(traceInitCpuTime) = TRACE_CPUTIMER();
66   CkpvInitialize(double, startUsefulWorkTimer);
67   CkpvAccess(startUsefulWorkTimer) = TRACE_CPUTIMER();
68   CpvInitialize(int, traceOn);
69   CpvAccess(traceOn) = 0;
70   CpvInitialize(int, _traceCoreOn); //projector
71   CpvAccess(_traceCoreOn)=0; //projector
72   CpvInitialize(mTFP, machineTraceFuncPtr);
73   CpvAccess(machineTraceFuncPtr) = NULL;
74   CkpvInitialize(int, traceOnPe);
75   CkpvAccess(traceOnPe) = 1;
76   CkpvInitialize(bool, verbose);
77   if (CmiGetArgFlag(argv, "+traceWarn")) {
78     CkpvAccess(verbose) = true;
79   } else {
80     CkpvAccess(verbose) = false;
81   }
82
83   char *root;
84   char *temproot;
85   char *temproot2;
86   CkpvInitialize(char*, traceRoot);
87   CkpvInitialize(char*, partitionRoot);
88   CkpvInitialize(int, traceRootBaseLength);
89
90   char subdir[20];
91   if(CmiNumPartitions() > 1) {
92     sprintf(subdir, "prj.part%d%s", CmiMyPartition(), PATHSEPSTR);
93   } else {
94     subdir[0]='\0';
95   }
96
97   if (CmiGetArgStringDesc(argv, "+traceroot", &temproot, "Directory to write trace files to")) {
98     int i;
99     // Trying to decide if the traceroot path is absolute or not. If it is not
100     // then create an absolute pathname for it.
101     if (temproot[0] != PATHSEP) {
102       temproot2 = GETCWD(NULL,0);
103       root = (char *)malloc(strlen(temproot2)+1+strlen(temproot)+1);
104       strcpy(root, temproot2);
105       strcat(root, PATHSEPSTR);
106       strcat(root, temproot);
107     } else {
108       root = (char *)malloc(strlen(temproot)+1);
109       strcpy(root,temproot);
110     }
111     for (i=strlen(argv[0])-1; i>=0; i--) if (argv[0][i] == PATHSEP) break;
112     i++;
113     CkpvAccess(traceRootBaseLength) = strlen(root)+1;
114     CkpvAccess(traceRoot) = (char *)malloc(strlen(argv[0]+i) + strlen(root) + 2 +strlen(subdir));    _MEMCHECK(CkpvAccess(traceRoot));
115     CkpvAccess(partitionRoot) = (char *)malloc(strlen(argv[0]+i) + strlen(root) + 2 +strlen(subdir));    _MEMCHECK(CkpvAccess(partitionRoot));
116     strcpy(CkpvAccess(traceRoot), root);
117     strcat(CkpvAccess(traceRoot), PATHSEPSTR);
118     strcat(CkpvAccess(traceRoot), subdir);
119     strcpy(CkpvAccess(partitionRoot),CkpvAccess(traceRoot));
120     strcat(CkpvAccess(traceRoot), argv[0]+i);
121   }
122   else {
123     CkpvAccess(traceRoot) = (char *) malloc(strlen(argv[0])+1 +strlen(subdir));
124     _MEMCHECK(CkpvAccess(traceRoot));
125     CkpvAccess(partitionRoot) = (char *) malloc(strlen(argv[0])+1 +strlen(subdir));
126     _MEMCHECK(CkpvAccess(partitionRoot));
127     strcpy(CkpvAccess(traceRoot), subdir);
128     strcpy(CkpvAccess(partitionRoot),CkpvAccess(traceRoot));
129     strcat(CkpvAccess(traceRoot), argv[0]);
130   }
131   CkpvAccess(traceRootBaseLength)  +=  strlen(subdir);
132         /* added for TAU trace module. */
133   char *cwd;
134   CkpvInitialize(char*, selective);
135   if (CmiGetArgStringDesc(argv, "+selective", &temproot, "TAU's selective instrumentation file")) {
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 __BIGSIM__
161   if(BgNodeRank()==0) {
162 #else
163   if(CkMyRank()==0) {
164 #endif
165     _threadMsg = CkRegisterMsg("dummy_thread_msg", 0, 0, 0, 0);
166     _threadChare = CkRegisterChare("dummy_thread_chare", 0, TypeInvalid);
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, 0);
171     _packChare = CkRegisterChare("dummy_pack_chare", 0, TypeInvalid);
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, 0);
176     _unpackChare = CkRegisterChare("dummy_unpack_chare", 0, TypeInvalid);
177     CkRegisterChareInCharm(_unpackChare);
178     _unpackEP = CkRegisterEp("dummy_unpack_ep", 0, _unpackMsg,_unpackChare, 0+CK_EP_INTRINSIC);
179
180     _sdagMsg = CkRegisterMsg("sdag_msg", 0, 0, 0, 0);
181     _sdagChare = CkRegisterChare("SDAG", 0, TypeInvalid);
182     CkRegisterChareInCharm(_sdagChare);
183     _sdagEP = CkRegisterEp("SDAG_RTS", 0, _sdagMsg, _sdagChare, 0+CK_EP_INTRINSIC);
184   }
185 }
186
187 /** Write out the common parts of the .sts file. */
188 void traceWriteSTS(FILE *stsfp,int nUserEvents) {
189   fprintf(stsfp, "MACHINE %s\n",CMK_MACHINE_NAME);
190 #if CMK_SMP_TRACE_COMMTHREAD
191   //Assuming there's only 1 comm thread now! --Chao Mei
192   //considering the extra comm thread per node
193   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes()+CkNumNodes());  
194   fprintf(stsfp, "SMPMODE %d %d\n", CkMyNodeSize(), CkNumNodes());
195 #else   
196   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes());
197 #endif  
198   fprintf(stsfp, "TOTAL_CHARES %d\n", (int)_chareTable.size());
199   fprintf(stsfp, "TOTAL_EPS %d\n", (int)_entryTable.size());
200   fprintf(stsfp, "TOTAL_MSGS %d\n", (int)_msgTable.size());
201   fprintf(stsfp, "TOTAL_PSEUDOS %d\n", (int)0);
202   fprintf(stsfp, "TOTAL_EVENTS %d\n", (int)nUserEvents);
203   size_t i;
204   for(i=0;i<_chareTable.size();i++)
205     fprintf(stsfp, "CHARE %d %s\n", (int)i, _chareTable[i]->name);
206   for(i=0;i<_entryTable.size();i++)
207     fprintf(stsfp, "ENTRY CHARE %d %s %d %d\n", (int)i, _entryTable[i]->name,
208                  (int)_entryTable[i]->chareIdx, (int)_entryTable[i]->msgIdx);
209   for(i=0;i<_msgTable.size();i++)
210     fprintf(stsfp, "MESSAGE %d %u\n", (int)i, (int)_msgTable[i]->size);
211 }
212
213 extern "C"
214 void traceCommonBeginIdle(void *proj,double curWallTime)
215 {
216   ((TraceArray *)proj)->beginIdle(curWallTime);
217 }
218  
219 extern "C"
220 void traceCommonEndIdle(void *proj,double curWallTime)
221 {
222   ((TraceArray *)proj)->endIdle(curWallTime);
223 }
224
225 void TraceArray::traceBegin() {
226   if (n==0) return; // No tracing modules registered.
227 #if ! CMK_TRACE_IN_CHARM
228   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
229   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
230 #endif
231   ALLDO(traceBegin());
232 }
233
234 void TraceArray::traceBeginOnCommThread() {
235 #if CMK_SMP_TRACE_COMMTHREAD
236   if (n==0) return; // No tracing modules registered.
237 /*#if ! CMK_TRACE_IN_CHARM      
238   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
239   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
240 #endif*/
241   ALLDO(traceBeginOnCommThread());
242 #endif
243 }
244
245 void TraceArray::traceEnd() {
246   if (n==0) return; // No tracing modules registered.
247   ALLDO(traceEnd());
248 #if ! CMK_TRACE_IN_CHARM
249   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
250   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
251 #endif
252 }
253
254 void TraceArray::traceEndOnCommThread() {
255 #if CMK_SMP_TRACE_COMMTHREAD
256   if (n==0) return; // No tracing modules registered.
257   ALLDO(traceEndOnCommThread());
258 /*#if ! CMK_TRACE_IN_CHARM
259   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
260   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
261 #endif*/
262 #endif
263 }
264
265 #if CMK_MULTICORE
266 extern int Cmi_commthread;
267 #endif
268
269 /*Install the beginIdle/endIdle condition handlers.*/
270 extern "C" void traceBegin(void) {
271 #if CMK_TRACE_ENABLED
272   DEBUGF(("[%d] traceBegin called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
273   
274 #if CMK_SMP_TRACE_COMMTHREAD
275   //the first core of this node controls the condition of comm thread
276 #if CMK_MULTICORE
277   if (Cmi_commthread)
278 #endif
279   if(CmiMyRank()==0){
280         if(CpvAccessOther(traceOn, CmiMyNodeSize())!=1){
281                 CkpvAccessOther(_traces, CmiMyNodeSize())->traceBeginOnCommThread();            
282                 CpvAccessOther(traceOn, CmiMyNodeSize()) = 1;
283         }
284   }
285 #endif
286   if (CpvAccess(traceOn)==1) return;
287   CkpvAccess(_traces)->traceBegin();
288   CpvAccess(traceOn) = 1;
289 #endif
290 }
291
292 /*Cancel the beginIdle/endIdle condition handlers.*/
293 extern "C" void traceEnd(void) {
294 #if CMK_TRACE_ENABLED
295   DEBUGF(("[%d] traceEnd called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
296
297 #if CMK_SMP_TRACE_COMMTHREAD
298 //the first core of this node controls the condition of comm thread
299 #if CMK_MULTICORE
300   if (Cmi_commthread)
301 #endif
302   if(CmiMyRank()==0){
303         if(CkpvAccessOther(traceOn, CmiMyNodeSize())!=0){
304                 CkpvAccessOther(_traces, CmiMyNodeSize())->traceEndOnCommThread();
305                 CkpvAccessOther(traceOn, CmiMyNodeSize()) = 0;
306         }
307 }
308 #endif
309         
310         
311   if (CpvAccess(traceOn)==0) return;
312   if (CkpvAccess(_traces) == NULL) {
313     CmiPrintf("Warning: did you mix compilation with and without -DCMK_TRACE_ENABLED? \n");
314   }
315   CkpvAccess(_traces)->traceEnd();
316   CpvAccess(traceOn) = 0;
317 #endif
318 }
319
320 static int checkTraceOnPe(char **argv)
321 {
322   int traceOnPE = 1;
323   char *procs = NULL;
324 #if CMK_BIGSIM_CHARM
325   // check bgconfig file for settings
326   traceOnPE=0;
327   if (BgTraceProjectionOn(CkMyPe())) traceOnPE = 1;
328 #endif
329   if (CmiGetArgStringDesc(argv, "+traceprocessors", &procs, "A list of processors to trace, e.g. 0,10,20-30"))
330   {
331     CkListString procList(procs);
332     traceOnPE = procList.includes(CkMyPe());
333   }
334   // must include pe 0, otherwise sts file is not generated
335   if (CkMyPe()==0) traceOnPE = 1;
336 #if !CMK_TRACE_IN_CHARM
337 #if !CMK_SMP_TRACE_COMMTHREAD
338   /* skip communication thread */
339   traceOnPE = traceOnPE && (CkMyRank() != CkMyNodeSize());
340 #endif
341 #endif
342   return traceOnPE;
343 }
344
345 /// defined in moduleInit.C
346 void _createTraces(char **argv);
347
348
349 bool enableCPTracing; // A global variable specifying whether or not the control point tracing module should be active in the run
350 extern void _registerTraceControlPoints();
351 extern void _createTracecontrolPoints(char **argv);
352
353
354 /**
355     traceInit:          called at Converse level
356     traceCharmInit:     called at Charm++ level
357 */
358 /// initialize trace framework, also create the trace module(s).
359 static inline void _traceInit(char **argv) 
360 {
361   CkpvInitialize(TraceArray *, _traces);
362   CkpvAccess(_traces) = new TraceArray;
363
364   // common init
365   traceCommonInit(argv);
366
367   // check if trace is turned on/off for this pe
368   CkpvAccess(traceOnPe) = checkTraceOnPe(argv);
369
370   // defined in moduleInit.C
371   _createTraces(argv);
372
373   // Now setup the control point tracing module if desired. It is always compiled/linked in, but is not always enabled
374   // FIXME: make sure it is safe to use argv in SMP version 
375   // because CmiGetArgFlagDesc is destructive and this is called on all PEs.
376   if( CmiGetArgFlagDesc(argv,"+CPEnableMeasurements","Enable recording of measurements for Control Points") ){
377     enableCPTracing = true;
378     _createTracecontrolPoints(argv);   
379   } else {
380     enableCPTracing = false;
381   }
382   
383
384   // set trace on/off
385   CkpvAccess(_traces)->setTraceOnPE(CkpvAccess(traceOnPe));
386
387 #if CMK_SMP_TRACE_COMMTHREAD
388 /**
389  * In traceBegin(), CkpvAccessOther will be used which means
390  * this core needs to access to some cpv variable on another 
391  * core in the same memory address space. It's possible the
392  * variable on the other core has not been initialized, which
393  * implies the CpvAcessOther will cause a bad memory access.
394  * Therefore, we need a barrier here for the traceCommonInit to
395  * finish here. -Chao Mei
396  */
397    CmiBarrier();
398 #endif
399
400   if (CkpvAccess(_traces)->length()) {
401     if (CkMyPe() == 0) 
402       CmiPrintf("Trace: traceroot: %s\n", CkpvAccess(traceRoot));
403     if (!CmiGetArgFlagDesc(argv,"+traceoff","Disable tracing"))
404       traceBegin();
405   }
406 }
407
408 /// Converse version
409 extern "C" void traceInit(char **argv) 
410 {
411 #if ! CMK_TRACE_IN_CHARM
412   _traceInit(argv);
413   initTraceCore(argv);
414 #endif
415 }
416
417 /// Charm++ version
418 extern "C" void traceCharmInit(char **argv) 
419 {
420 #if CMK_TRACE_IN_CHARM
421   _traceInit(argv);
422 #endif
423 }
424
425 // CMK_TRACE_ENABLED is already guarded in convcore.c
426 extern "C"
427 void traceMessageRecv(char *msg, int pe)
428 {
429 #if ! CMK_TRACE_IN_CHARM
430   CkpvAccessOther(_traces, CmiRankOf(pe))->messageRecv(msg, pe);
431 #endif
432 }
433
434 extern "C" 
435 void traceBeginIdle()
436 {
437     _TRACE_ONLY(CkpvAccess(_traces)->beginIdle(CmiWallTimer()));
438 }
439
440 extern "C" 
441 void traceEndIdle()
442 {
443     _TRACE_ONLY(CkpvAccess(_traces)->endIdle(CmiWallTimer()));
444 }
445
446 // CMK_TRACE_ENABLED is already guarded in convcore.c
447 // converse thread tracing is not supported in blue gene simulator
448 // in BigSim, threads need to be traced manually (because virtual processors
449 // themselves are implemented as threads and we don't want them to be traced
450 // In BigSim, so far, only AMPI threads are traced.
451 extern "C"
452 void traceResume(CmiObjId *tid)
453 {
454     _TRACE_ONLY(CkpvAccess(_traces)->beginExecute(tid));
455     if(CpvAccess(_traceCoreOn))
456             resumeTraceCore();
457 }
458
459 extern "C"
460 void traceSuspend(void)
461 {
462   _TRACE_ONLY(CkpvAccess(_traces)->endExecute());
463 }
464
465 extern "C"
466 void traceAwaken(CthThread t)
467 {
468   CkpvAccess(_traces)->creation(0, _threadEP);
469 }
470
471 extern "C"
472 void traceUserEvent(int e)
473 {
474 #if CMK_TRACE_ENABLED
475   if (CpvAccess(traceOn))
476     CkpvAccess(_traces)->userEvent(e);
477 #endif
478 }
479
480 extern "C" 
481 void traceStartUsefulWork()
482 {
483 #if CMK_TRACE_ENABLED
484     CkpvAccess(startUsefulWorkTimer) = TraceTimer();
485 #endif
486 }
487
488 extern "C" 
489 void traceStopUsefulWork()
490 {
491 #if CMK_TRACE_ENABLED
492     if (CpvAccess(traceOn) && CkpvAccess(_traces))
493     {
494         CkpvAccess(_traces)->appWork(1, CkpvAccess(startUsefulWorkTimer), TraceTimer());
495     }
496 #endif
497 }
498
499 extern "C"
500 void traceUserBracketEvent(int e, double beginT, double endT)
501 {
502 #if CMK_TRACE_ENABLED
503   if (CpvAccess(traceOn) && CkpvAccess(_traces))
504     CkpvAccess(_traces)->userBracketEvent(e, beginT, endT);
505 #endif
506 }
507
508 extern "C"
509 void traceUserSuppliedData(int d)
510 {
511 #if CMK_TRACE_ENABLED
512   if (CpvAccess(traceOn) && CkpvAccess(_traces))
513     CkpvAccess(_traces)->userSuppliedData(d);
514 #endif
515 }
516
517 extern "C"
518 void traceUserSuppliedNote(char * note)
519 {
520 #if CMK_TRACE_ENABLED
521   if (CpvAccess(traceOn) && CkpvAccess(_traces))
522     CkpvAccess(_traces)->userSuppliedNote(note);
523 #endif
524 }
525
526
527 extern "C"
528 void traceUserSuppliedBracketedNote(char *note, int eventID, double bt, double et)
529 {
530   //CkPrintf("traceUserSuppliedBracketedNote(char *note, int eventID, double bt, double et)\n");
531 #if CMK_TRACE_ENABLED
532   if (CpvAccess(traceOn) && CkpvAccess(_traces))
533     CkpvAccess(_traces)->userSuppliedBracketedNote(note, eventID, bt, et);
534 #endif
535 }
536
537
538 extern "C"
539 void traceMemoryUsage()
540 {
541 #if CMK_TRACE_ENABLED
542   double d = CmiMemoryUsage()*1.0;
543
544   if (CpvAccess(traceOn) && CkpvAccess(_traces))
545     CkpvAccess(_traces)->memoryUsage(d);
546 #endif
547 }
548
549 extern "C"
550 void tracePhaseEnd()
551 {
552   _TRACE_ONLY(CkpvAccess(_traces)->endPhase());
553 }
554
555 extern "C"
556 void registerMachineUserEventsFunction(void (*eventRegistrationFunc)()) {
557   CmiAssert(CpvInitialized(machineTraceFuncPtr));
558   CpvAccess(machineTraceFuncPtr) = eventRegistrationFunc;
559 }
560
561 extern "C"
562 void (*registerMachineUserEvents())() {
563   CmiAssert(CpvInitialized(machineTraceFuncPtr));
564   if (CpvAccess(machineTraceFuncPtr) != NULL) {
565     return CpvAccess(machineTraceFuncPtr);
566   } else {
567     return NULL;
568   }
569 }
570
571 extern "C"
572 int traceRegisterUserEvent(const char*x, int e)
573 {
574 #if CMK_TRACE_ENABLED
575   return CkpvAccess(_traces)->traceRegisterUserEvent(x, e);
576 #else
577   return 0;
578 #endif
579 }
580
581 extern "C"
582 void traceClearEps(void)
583 {
584   OPTIMIZE_WARNING
585   CkpvAccess(_traces)->traceClearEps();
586 }
587
588 extern "C"
589 void traceWriteSts(void)
590 {
591   OPTIMIZE_WARNING
592   CkpvAccess(_traces)->traceWriteSts();
593 }
594
595 extern "C"
596 void traceFlushLog(void)
597 {
598   OPTIMIZE_WARNING
599   CkpvAccess(_traces)->traceFlushLog();
600 }
601
602 /**
603     traceClose:         this function is called at Converse
604     traceCharmClose:    called at Charm++ level
605 */
606 extern "C"
607 void traceClose(void)
608 {
609 #if ! CMK_BIGSIM_CHARM
610   OPTIMIZE_WARNING
611   CkpvAccess(_traces)->traceClose();
612 #endif   
613 }
614
615 extern "C"
616 void traceCharmClose(void)
617 {
618 #if CMK_BIGSIM_CHARM
619   OPTIMIZE_WARNING
620   CkpvAccess(_traces)->traceClose();
621 #endif
622 }
623
624 /* **CW** This is the API called from user code to support CCS operations 
625    if supported by the underlying trace module.
626  */
627 extern "C"
628 void traceEnableCCS(void)
629 {
630   OPTIMIZE_WARNING
631   CkpvAccess(_traces)->traceEnableCCS();  
632 }
633
634 /* **CW** Support for thread listeners. This makes a call to each
635    trace module which must support the call.
636 */
637 extern "C"
638 void traceAddThreadListeners(CthThread tid, envelope *e) {
639   _TRACE_ONLY(CkpvAccess(_traces)->traceAddThreadListeners(tid, e));
640 }
641
642 #if 1
643 // helper functions
644 extern int _charmHandlerIdx;
645 class CkCoreState;
646 extern void _processHandler(void *, CkCoreState*);
647 extern "C" int isCharmEnvelope(void *msg);
648 int CkIsCharmMessage(char *msg)
649 {
650 //CmiPrintf("[%d] CkIsCharmMessage: %d %p %d %p\n", CkMyPe(),CmiGetHandler(msg), CmiGetHandlerFunction(msg), _charmHandlerIdx, _processHandler);
651   if ((CmiGetHandler(msg) == _charmHandlerIdx) &&
652          (CmiGetHandlerFunction(msg) == (CmiHandlerEx)_processHandler))
653     return 1;
654   if (CmiGetXHandler(msg) == _charmHandlerIdx) return isCharmEnvelope(msg);
655   return 0;
656 }
657 #endif
658
659 // return 1 if any one of tracing modules is linked.
660 int  traceAvailable()
661 {
662 #if ! CMK_TRACE_ENABLED
663   return 0;
664 #else
665   return CkpvAccess(_traces)->length()>0;
666 #endif
667 }
668
669 double CmiTraceTimer()
670 {
671   return TraceTimer();
672 }
673
674 void TraceArray::creation(envelope *env, int ep, int num)
675
676     if (_entryTable[ep]->traceEnabled)
677         ALLDO(creation(env, ep, num));
678 }
679
680 void TraceArray::creationMulticast(envelope *env, int ep, int num,
681                                    int *pelist)
682 {
683   if (_entryTable[ep]->traceEnabled)
684     ALLDO(creationMulticast(env, ep, num, pelist));
685 }
686
687 /*
688 extern "C" 
689 void registerFunction(char *name){
690         _TRACE_ONLY(CkpvAccess(_traces)->regFunc(name));
691 }
692 */
693
694 extern "C"
695 int traceRegisterFunction(const char* name, int idx) {
696 #if CMK_TRACE_ENABLED
697   if(idx==-999){
698     CkpvAccess(_traces)->regFunc(name, idx);
699   } else {
700     CkpvAccess(_traces)->regFunc(name, idx, 1);
701   }
702   return idx;
703 #else
704   return 0;
705 #endif
706 }
707
708 extern "C" 
709 void traceBeginFuncProj(char *name,char *file,int line){
710          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(name,file,line));
711 }
712
713 extern "C"
714 void traceBeginFuncIndexProj(int idx,char *file,int line){
715          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(idx,file,line));
716 }
717
718 extern "C" 
719 void traceEndFuncProj(char *name){
720          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(name));
721 }
722
723 extern "C" 
724 void traceEndFuncIndexProj(int idx){
725          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(idx));
726 }
727
728 #if CMK_SMP_TRACE_COMMTHREAD
729 extern "C"
730 int traceBeginCommOp(char *msg){
731 #if CMK_TRACE_ENABLED
732   if (CpvAccess(traceOn) && CkpvAccess(_traces) && CkIsCharmMessage(msg)) {
733     CkpvAccess(_traces)->beginExecute(msg);
734     return 1;
735   }
736   return 0;
737 #endif
738 }
739
740 extern "C"
741 void traceEndCommOp(char *msg){
742 #if CMK_TRACE_ENABLED
743   if (CpvAccess(traceOn) && CkpvAccess(_traces) && CkIsCharmMessage(msg))
744     CkpvAccess(_traces)->endExecute(msg);
745 #endif
746 }
747
748 extern "C"
749 void traceSendMsgComm(char *msg){
750 #if CMK_TRACE_ENABLED
751   if (CpvAccess(traceOn) && CkpvAccess(_traces) && CkIsCharmMessage(msg))
752     CkpvAccess(_traces)->creation(msg);
753 #endif
754 }
755
756 extern "C"
757 void traceCommSetMsgID(char *msg){
758 #if CMK_TRACE_ENABLED
759   if (CpvAccess(traceOn) && CkpvAccess(_traces) && CkIsCharmMessage(msg))
760     CkpvAccess(_traces)->traceCommSetMsgID(msg);
761 #endif
762 }
763
764 #endif
765
766 extern "C"
767 void traceGetMsgID(char *msg, int *pe, int *event)
768 {
769 #if CMK_TRACE_ENABLED
770   if (CpvAccess(traceOn) && CkpvAccess(_traces) && CkIsCharmMessage(msg))
771     CkpvAccess(_traces)->traceGetMsgID(msg, pe, event);
772 #endif
773 }
774
775 extern "C"
776 void traceSetMsgID(char *msg, int pe, int event)
777 {
778 #if CMK_TRACE_ENABLED
779   if (CpvAccess(traceOn) && CkpvAccess(_traces) && CkIsCharmMessage(msg))
780     CkpvAccess(_traces)->traceSetMsgID(msg, pe, event);
781 #endif
782 }
783
784
785 extern "C"
786 void traceChangeLastTimestamp(double ts){
787 #if CMK_TRACE_ENABLED
788   if (CpvAccess(traceOn) && CkpvAccess(_traces))
789     CkpvAccess(_traces)->changeLastEntryTimestamp(ts);
790 #endif
791 }
792
793 #if CMK_HAS_COUNTER_PAPI
794 CkpvDeclare(int, papiEventSet);
795 CkpvDeclare(LONG_LONG_PAPI*, papiValues);
796 CkpvDeclare(int, papiStarted);
797 CkpvDeclare(int, papiStopped);
798 #ifdef USE_SPP_PAPI
799 int papiEvents[NUMPAPIEVENTS];
800 #else
801 int papiEvents[NUMPAPIEVENTS] = { PAPI_L2_DCM, PAPI_FP_OPS };
802 #endif
803 #endif // CMK_HAS_COUNTER_PAPI
804
805 #if CMK_HAS_COUNTER_PAPI
806 void initPAPI() {
807 #if CMK_HAS_COUNTER_PAPI
808   // We initialize and create the event sets for use with PAPI here.
809   int papiRetValue;
810   if(CkMyRank()==0){
811       papiRetValue = PAPI_is_initialized();
812       if(papiRetValue != PAPI_NOT_INITED)
813           return;
814       CkpvInitialize(int, papiStarted);
815       CkpvAccess(papiStarted) = 0;
816       CkpvInitialize(int, papiStopped);
817       CkpvAccess(papiStopped) = 0;
818     papiRetValue = PAPI_library_init(PAPI_VER_CURRENT);
819     if (papiRetValue != PAPI_VER_CURRENT) {
820       CmiAbort("PAPI Library initialization failure!\n");
821     }
822 #if CMK_SMP
823     if(PAPI_thread_init(pthread_self) != PAPI_OK){
824       CmiAbort("PAPI could not be initialized in SMP mode!\n");
825     }
826 #endif
827   }
828
829 #if CMK_SMP
830   //PAPI_thread_init has to finish before calling PAPI_create_eventset
831   #if CMK_SMP_TRACE_COMMTHREAD
832       CmiNodeAllBarrier();
833   #else
834       CmiNodeBarrier();
835   #endif
836 #endif
837   // PAPI 3 mandates the initialization of the set to PAPI_NULL
838   CkpvInitialize(int, papiEventSet); 
839   CkpvAccess(papiEventSet) = PAPI_NULL; 
840   if (PAPI_create_eventset(&CkpvAccess(papiEventSet)) != PAPI_OK) {
841     CmiAbort("PAPI failed to create event set!\n");
842   }
843 #ifdef USE_SPP_PAPI
844   //  CmiPrintf("Using SPP counters for PAPI\n");
845   if(PAPI_query_event(PAPI_FP_OPS)==PAPI_OK) {
846     papiEvents[0] = PAPI_FP_OPS;
847   }else{
848     if(CmiMyPe()==0){
849       CmiAbort("WARNING: PAPI_FP_OPS doesn't exist on this platform!");
850     }
851   }
852   if(PAPI_query_event(PAPI_TOT_INS)==PAPI_OK) {
853     papiEvents[1] = PAPI_TOT_INS;
854   }else{
855     CmiAbort("WARNING: PAPI_TOT_INS doesn't exist on this platform!");
856   }
857   int EventCode;
858   int ret;
859   ret=PAPI_event_name_to_code("perf::PERF_COUNT_HW_CACHE_LL:MISS",&EventCode);
860   if(PAPI_query_event(EventCode)==PAPI_OK) {
861     papiEvents[2] = EventCode;
862   }else{
863     CmiAbort("WARNING: perf::PERF_COUNT_HW_CACHE_LL:MISS doesn't exist on this platform!");
864   }
865   ret=PAPI_event_name_to_code("DATA_PREFETCHER:ALL",&EventCode);
866   if(PAPI_query_event(EventCode)==PAPI_OK) {
867     papiEvents[3] = EventCode;
868   }else{
869     CmiAbort("WARNING: DATA_PREFETCHER:ALL doesn't exist on this platform!");
870   }
871   if(PAPI_query_event(PAPI_L1_DCA)==PAPI_OK) {
872     papiEvents[4] = PAPI_L1_DCA;
873   }else{
874     CmiAbort("WARNING: PAPI_L1_DCA doesn't exist on this platform!");
875   }
876   if(PAPI_query_event(PAPI_TOT_CYC)==PAPI_OK) {
877     papiEvents[5] = PAPI_TOT_CYC;
878   }else{
879     CmiAbort("WARNING: PAPI_TOT_CYC doesn't exist on this platform!");
880   }
881 #else
882   // just uses { PAPI_L2_DCM, PAPI_FP_OPS } the 2 initialized PAPI_EVENTS
883 #endif
884   papiRetValue = PAPI_add_events(CkpvAccess(papiEventSet), papiEvents, NUMPAPIEVENTS);
885   if (papiRetValue < 0) {
886     if (papiRetValue == PAPI_ECNFLCT) {
887       CmiAbort("PAPI events conflict! Please re-assign event types!\n");
888     } else {
889       char error_str[PAPI_MAX_STR_LEN];
890       PAPI_perror(error_str);
891       //PAPI_perror(papiRetValue,error_str,PAPI_MAX_STR_LEN);
892       CmiPrintf("PAPI failed with error %s val %d\n",error_str,papiRetValue);
893       CmiAbort("PAPI failed to add designated events!\n");
894     }
895   }
896   if(CkMyPe()==0)
897     {
898       CmiPrintf("Registered %d PAPI counters:",NUMPAPIEVENTS);
899       char nameBuf[PAPI_MAX_STR_LEN];
900       for(int i=0;i<NUMPAPIEVENTS;i++)
901         {
902           PAPI_event_code_to_name(papiEvents[i], nameBuf);
903           CmiPrintf("%s ",nameBuf);
904         }
905       CmiPrintf("\n");
906     }
907   CkpvInitialize(LONG_LONG_PAPI*, papiValues);
908   CkpvAccess(papiValues) = (LONG_LONG_PAPI*)malloc(NUMPAPIEVENTS*sizeof(LONG_LONG_PAPI));
909   memset(CkpvAccess(papiValues), 0, NUMPAPIEVENTS*sizeof(LONG_LONG_PAPI));
910 #endif
911 }
912 #endif
913
914 /*@}*/