Merge branch 'charm' of charmgit:charm into charm
[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 // cannot include charm++.h because trace-common.o is part of libconv-core.a
14 #include "charm.h"
15 #include "middle.h"
16 #include "cklists.h"
17 #include "ckliststring.h"
18
19 #include "trace.h"
20 #include "trace-common.h"
21 #include "allEvents.h"          //projector
22 #include "register.h" // for _entryTable
23
24 CpvCExtern(int, _traceCoreOn);   // projector
25
26 #if ! CMK_TRACE_ENABLED
27 static int warned = 0;
28 #define OPTIMIZE_WARNING if (!warned) { warned=1;  CmiPrintf("\n\n!!!! Warning: tracing not available without CMK_TRACE_ENABLED!\n");  return;  }
29 #else
30 #define OPTIMIZE_WARNING /*empty*/
31 #endif
32
33 #define DEBUGF(x)          // CmiPrintf x
34
35 CkpvDeclare(TraceArray*, _traces);              // lists of all trace modules
36
37 /* trace for bluegene */
38 class TraceBluegene;
39 CkpvDeclare(TraceBluegene*, _tracebg);
40 int traceBluegeneLinked=0;                      // if trace-bluegene is linked
41
42 CkpvDeclare(double, traceInitTime);
43 CkpvDeclare(double, traceInitCpuTime);
44 CpvDeclare(int, traceOn);
45 CkpvDeclare(int, traceOnPe);
46 CkpvDeclare(char*, traceRoot);
47 CkpvDeclare(int, traceRootBaseLength);
48 CkpvDeclare(char*, selective);
49 CkpvDeclare(bool, verbose);
50
51 typedef void (*mTFP)();                   // function pointer for
52 CpvStaticDeclare(mTFP, machineTraceFuncPtr);    // machine user event
53                                           // registration
54
55 int _threadMsg, _threadChare, _threadEP;
56 int _packMsg, _packChare, _packEP;
57 int _unpackMsg, _unpackChare, _unpackEP;
58 int _dummyMsg, _dummyChare, _dummyEP;
59
60 /// decide parameters from command line
61 static void traceCommonInit(char **argv)
62 {
63   CmiArgGroup("Charm++","Tracing");
64   DEBUGF(("[%d] in traceCommonInit.\n", CkMyPe()));
65   CkpvInitialize(double, traceInitTime);
66   CkpvAccess(traceInitTime) = CmiStartTimer();
67   CkpvInitialize(double, traceInitCpuTime);
68   CkpvAccess(traceInitCpuTime) = TRACE_CPUTIMER();
69   CpvInitialize(int, traceOn);
70   CpvAccess(traceOn) = 0;
71   CpvInitialize(int, _traceCoreOn); //projector
72   CpvAccess(_traceCoreOn)=0; //projector
73   CpvInitialize(mTFP, machineTraceFuncPtr);
74   CpvAccess(machineTraceFuncPtr) = NULL;
75   CkpvInitialize(int, traceOnPe);
76   CkpvAccess(traceOnPe) = 1;
77
78   CkpvInitialize(bool, verbose);
79   if (CmiGetArgFlag(argv, "+traceWarn")) {
80     CkpvAccess(verbose) = true;
81   } else {
82     CkpvAccess(verbose) = false;
83   }
84
85   char *root;
86   char *temproot;
87   char *temproot2;
88   CkpvInitialize(char*, traceRoot);
89   CkpvInitialize(int, traceRootBaseLength);
90   if (CmiGetArgStringDesc(argv, "+traceroot", &temproot, "Directory to write trace files to")) {
91     int i;
92     // Trying to decide if the traceroot path is absolute or not. If it is not
93     // then create an absolute pathname for it.
94     if (temproot[0] != PATHSEP) {
95       temproot2 = GETCWD(NULL,0);
96       root = (char *)malloc(strlen(temproot2)+1+strlen(temproot)+1);
97       strcpy(root, temproot2);
98       strcat(root, PATHSEPSTR);
99       strcat(root, temproot);
100     } else {
101       root = (char *)malloc(strlen(temproot)+1);
102       strcpy(root,temproot);
103     }
104     for (i=strlen(argv[0])-1; i>=0; i--) if (argv[0][i] == PATHSEP) break;
105     i++;
106     CkpvAccess(traceRootBaseLength) = strlen(root)+1;
107     CkpvAccess(traceRoot) = (char *)malloc(strlen(argv[0]+i) + strlen(root) + 2);    _MEMCHECK(CkpvAccess(traceRoot));
108     strcpy(CkpvAccess(traceRoot), root);
109     strcat(CkpvAccess(traceRoot), PATHSEPSTR);
110     strcat(CkpvAccess(traceRoot), argv[0]+i);
111     if (CkMyPe() == 0) 
112       CmiPrintf("Trace: traceroot: %s\n", CkpvAccess(traceRoot));
113   }
114   else {
115     CkpvAccess(traceRoot) = (char *) malloc(strlen(argv[0])+1);
116     _MEMCHECK(CkpvAccess(traceRoot));
117     strcpy(CkpvAccess(traceRoot), argv[0]);
118   }
119         /* added for TAU trace module. */
120         char *cwd;
121   CkpvInitialize(char*, selective);
122   if (CmiGetArgStringDesc(argv, "+selective", &temproot, "TAU's selective instrumentation file")) {
123     // Trying to decide if the traceroot path is absolute or not. If it is not
124     // then create an absolute pathname for it.
125     if (temproot[0] != PATHSEP) {
126       cwd = GETCWD(NULL,0);
127       root = (char *)malloc(strlen(cwd)+strlen(temproot)+2);
128       strcpy(root, cwd);
129       strcat(root, PATHSEPSTR);
130       strcat(root, temproot);
131     } else {
132       root = (char *)malloc(strlen(temproot)+1);
133       strcpy(root,temproot);
134     }
135     CkpvAccess(selective) = (char *) malloc(strlen(root)+1);
136     _MEMCHECK(CkpvAccess(selective));
137     strcpy(CkpvAccess(selective), root);
138     if (CkMyPe() == 0) 
139       CmiPrintf("Trace: selective: %s\n", CkpvAccess(selective));
140   }
141   else {
142     CkpvAccess(selective) = (char *) malloc(3);
143     _MEMCHECK(CkpvAccess(selective));
144     strcpy(CkpvAccess(selective), "");
145   }
146   
147 #ifdef __BLUEGENE__
148   if(BgNodeRank()==0) {
149 #else
150   if(CkMyRank()==0) {
151 #endif
152     _threadMsg = CkRegisterMsg("dummy_thread_msg", 0, 0, 0, 0);
153     _threadChare = CkRegisterChare("dummy_thread_chare", 0, TypeInvalid);
154     CkRegisterChareInCharm(_threadChare);
155     _threadEP = CkRegisterEp("dummy_thread_ep", 0, _threadMsg,_threadChare, 0+CK_EP_INTRINSIC);
156
157     _packMsg = CkRegisterMsg("dummy_pack_msg", 0, 0, 0, 0);
158     _packChare = CkRegisterChare("dummy_pack_chare", 0, TypeInvalid);
159     CkRegisterChareInCharm(_packChare);
160     _packEP = CkRegisterEp("dummy_pack_ep", 0, _packMsg,_packChare, 0+CK_EP_INTRINSIC);
161
162     _unpackMsg = CkRegisterMsg("dummy_unpack_msg", 0, 0, 0, 0);
163     _unpackChare = CkRegisterChare("dummy_unpack_chare", 0, TypeInvalid);
164     CkRegisterChareInCharm(_unpackChare);
165     _unpackEP = CkRegisterEp("dummy_unpack_ep", 0, _unpackMsg,_unpackChare, 0+CK_EP_INTRINSIC);
166
167     _dummyMsg = CkRegisterMsg("dummy_msg", 0, 0, 0, 0);
168     _dummyChare = CkRegisterChare("dummy_chare", 0, TypeInvalid);
169     CkRegisterChareInCharm(_dummyChare);
170     _dummyEP = CkRegisterEp("dummy_ep", 0, _dummyMsg,_dummyChare, 0+CK_EP_INTRINSIC);
171   }
172 }
173
174 /** Write out the common parts of the .sts file. */
175 extern void traceWriteSTS(FILE *stsfp,int nUserEvents) {
176   fprintf(stsfp, "MACHINE %s\n",CMK_MACHINE_NAME);
177 #if CMK_SMP_TRACE_COMMTHREAD
178   //Assuming there's only 1 comm thread now! --Chao Mei
179   //considering the extra comm thread per node
180   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes()+CkNumNodes());  
181   fprintf(stsfp, "SMPMODE %d %d\n", CkMyNodeSize(), CkNumNodes());
182 #else   
183   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes());
184 #endif  
185   fprintf(stsfp, "TOTAL_CHARES %d\n", (int)_chareTable.size());
186   fprintf(stsfp, "TOTAL_EPS %d\n", (int)_entryTable.size());
187   fprintf(stsfp, "TOTAL_MSGS %d\n", (int)_msgTable.size());
188   fprintf(stsfp, "TOTAL_PSEUDOS %d\n", (int)0);
189   fprintf(stsfp, "TOTAL_EVENTS %d\n", (int)nUserEvents);
190   size_t i;
191   for(i=0;i<_chareTable.size();i++)
192     fprintf(stsfp, "CHARE %d %s\n", (int)i, _chareTable[i]->name);
193   for(i=0;i<_entryTable.size();i++)
194     fprintf(stsfp, "ENTRY CHARE %d %s %d %d\n", (int)i, _entryTable[i]->name,
195                  (int)_entryTable[i]->chareIdx, (int)_entryTable[i]->msgIdx);
196   for(i=0;i<_msgTable.size();i++)
197     fprintf(stsfp, "MESSAGE %d %u\n", (int)i, (int)_msgTable[i]->size);
198 }
199
200 extern "C"
201 void traceCommonBeginIdle(void *proj,double curWallTime)
202 {
203   ((TraceArray *)proj)->beginIdle(curWallTime);
204 }
205  
206 extern "C"
207 void traceCommonEndIdle(void *proj,double curWallTime)
208 {
209   ((TraceArray *)proj)->endIdle(curWallTime);
210 }
211
212 void TraceArray::traceBegin() {
213   if (n==0) return; // No tracing modules registered.
214 #if ! CMK_TRACE_IN_CHARM
215   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
216   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
217 #endif
218   ALLDO(traceBegin());
219 }
220
221 #if CMK_SMP_TRACE_COMMTHREAD
222 void TraceArray::traceBeginOnCommThread() {
223   if (n==0) return; // No tracing modules registered.
224 /*#if ! CMK_TRACE_IN_CHARM      
225   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
226   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
227 #endif*/
228   ALLDO(traceBeginOnCommThread());
229 }
230 #endif
231
232 void TraceArray::traceEnd() {
233   if (n==0) return; // No tracing modules registered.
234   ALLDO(traceEnd());
235 #if ! CMK_TRACE_IN_CHARM
236   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
237   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
238 #endif
239 }
240
241 #if CMK_SMP_TRACE_COMMTHREAD
242 void TraceArray::traceEndOnCommThread() {
243   if (n==0) return; // No tracing modules registered.
244   ALLDO(traceEndOnCommThread());
245 /*#if ! CMK_TRACE_IN_CHARM
246   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
247   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
248 #endif*/
249 }
250 #endif
251
252
253 /*Install the beginIdle/endIdle condition handlers.*/
254 extern "C" void traceBegin(void) {
255 #if CMK_TRACE_ENABLED
256   DEBUGF(("[%d] traceBegin called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
257   
258 #if CMK_SMP_TRACE_COMMTHREAD
259   //the first core of this node controls the condition of comm thread
260   if(CmiMyRank()==0){
261         if(CkpvAccessOther(traceOn, CmiMyNodeSize())!=1){
262                 CkpvAccessOther(_traces, CmiMyNodeSize())->traceBeginOnCommThread();            
263                 CkpvAccessOther(traceOn, CmiMyNodeSize()) = 1;
264         }
265   }
266 #endif
267   if (CpvAccess(traceOn)==1) return;
268   CkpvAccess(_traces)->traceBegin();
269   CpvAccess(traceOn) = 1;
270 #endif
271 }
272
273 /*Cancel the beginIdle/endIdle condition handlers.*/
274 extern "C" void traceEnd(void) {
275 #if CMK_TRACE_ENABLED
276   DEBUGF(("[%d] traceEnd called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
277
278 #if CMK_SMP_TRACE_COMMTHREAD
279 //the first core of this node controls the condition of comm thread
280 if(CmiMyRank()==0){
281         if(CkpvAccessOther(traceOn, CmiMyNodeSize())!=0){
282                 CkpvAccessOther(_traces, CmiMyNodeSize())->traceEndOnCommThread();
283                 CkpvAccessOther(traceOn, CmiMyNodeSize()) = 0;
284         }
285 }
286 #endif
287         
288         
289   if (CpvAccess(traceOn)==0) return;
290   if (CkpvAccess(_traces) == NULL) {
291     CmiPrintf("Warning: did you mix compilation with and without -DCMK_TRACE_ENABLED? \n");
292   }
293   CkpvAccess(_traces)->traceEnd();
294   CpvAccess(traceOn) = 0;
295 #endif
296 }
297
298 static int checkTraceOnPe(char **argv)
299 {
300   int traceOnPE = 1;
301   char *procs = NULL;
302 #if CMK_BLUEGENE_CHARM
303   // check bgconfig file for settings
304   traceOnPE=0;
305   if (BgTraceProjectionOn(CkMyPe())) traceOnPE = 1;
306 #endif
307   if (CmiGetArgStringDesc(argv, "+traceprocessors", &procs, "A list of processors to trace, e.g. 0,10,20-30"))
308   {
309     CkListString procList(procs);
310     traceOnPE = procList.includes(CkMyPe());
311   }
312   // must include pe 0, otherwise sts file is not generated
313   if (CkMyPe()==0) traceOnPE = 1;
314 #if !CMK_TRACE_IN_CHARM
315 #if !CMK_SMP_TRACE_COMMTHREAD
316   /* skip communication thread */
317   traceOnPE = traceOnPE && (CkMyRank() != CkMyNodeSize());
318 #endif
319 #endif
320   return traceOnPE;
321 }
322
323 /// defined in moduleInit.C
324 void _createTraces(char **argv);
325
326
327 bool enableCPTracing; // A global variable specifying whether or not the control point tracing module should be active in the run
328 extern void _registerTraceControlPoints();
329 extern void _createTracecontrolPoints(char **argv);
330
331
332 /**
333     traceInit:          called at Converse level
334     traceCharmInit:     called at Charm++ level
335 */
336 /// initialize trace framework, also create the trace module(s).
337 static inline void _traceInit(char **argv) 
338 {
339   CkpvInitialize(TraceArray *, _traces);
340   CkpvAccess(_traces) = new TraceArray;
341
342   // common init
343   traceCommonInit(argv);
344
345   // check if trace is turned on/off for this pe
346   CkpvAccess(traceOnPe) = checkTraceOnPe(argv);
347
348   // defined in moduleInit.C
349   _createTraces(argv);
350
351   // Now setup the control point tracing module if desired. It is always compiled/linked in, but is not always enabled
352   // FIXME: make sure it is safe to use argv in SMP version 
353   // because CmiGetArgFlagDesc is destructive and this is called on all PEs.
354   if( CmiGetArgFlagDesc(argv,"+CPEnableMeasurements","Enable recording of measurements for Control Points") ){
355     enableCPTracing = true;
356     _createTracecontrolPoints(argv);   
357   } else {
358     enableCPTracing = false;
359   }
360   
361
362   // set trace on/off
363   CkpvAccess(_traces)->setTraceOnPE(CkpvAccess(traceOnPe));
364
365 #if CMK_SMP_TRACE_COMMTHREAD
366 /**
367  * In traceBegin(), CkpvAccessOther will be used which means
368  * this core needs to access to some cpv variable on another 
369  * core in the same memory address space. It's possible the
370  * variable on the other core has not been initialized, which
371  * implies the CpvAcessOther will cause a bad memory access.
372  * Therefore, we need a barrier here for the traceCommonInit to
373  * finish here. -Chao Mei
374  */
375    CmiBarrier();
376 #endif
377
378   if (CkpvAccess(_traces)->length() && !CmiGetArgFlagDesc(argv,"+traceoff","Disable tracing"))
379     traceBegin();
380 }
381
382 /// Converse version
383 extern "C" void traceInit(char **argv) 
384 {
385 #if ! CMK_TRACE_IN_CHARM
386   _traceInit(argv);
387   initTraceCore(argv);
388 #endif
389 }
390
391 /// Charm++ version
392 extern "C" void traceCharmInit(char **argv) 
393 {
394 #if CMK_TRACE_IN_CHARM
395   _traceInit(argv);
396 #endif
397 }
398
399 // CMK_TRACE_ENABLED is already guarded in convcore.c
400 extern "C"
401 void traceMessageRecv(char *msg, int pe)
402 {
403 #if ! CMK_TRACE_IN_CHARM
404   CkpvAccessOther(_traces, CmiRankOf(pe))->messageRecv(msg, pe);
405 #endif
406 }
407
408 // CMK_TRACE_ENABLED is already guarded in convcore.c
409 // converse thread tracing is not supported in blue gene simulator
410 // in BigSim, threads need to be traced manually (because virtual processors
411 // themselves are implemented as threads and we don't want them to be traced
412 // In BigSim, so far, only AMPI threads are traced.
413 extern "C"
414 void traceResume(CmiObjId *tid)
415 {
416     _TRACE_ONLY(CkpvAccess(_traces)->beginExecute(tid));
417     if(CpvAccess(_traceCoreOn))
418             resumeTraceCore();
419 }
420
421 extern "C"
422 void traceSuspend(void)
423 {
424   _TRACE_ONLY(CkpvAccess(_traces)->endExecute());
425 }
426
427 extern "C"
428 void traceAwaken(CthThread t)
429 {
430   CkpvAccess(_traces)->creation(0, _threadEP);
431 }
432
433 extern "C"
434 void traceUserEvent(int e)
435 {
436 #if CMK_TRACE_ENABLED
437   if (CpvAccess(traceOn))
438     CkpvAccess(_traces)->userEvent(e);
439 #endif
440 }
441
442 extern "C"
443 void traceUserBracketEvent(int e, double beginT, double endT)
444 {
445 #if CMK_TRACE_ENABLED
446   if (CpvAccess(traceOn) && CkpvAccess(_traces))
447     CkpvAccess(_traces)->userBracketEvent(e, beginT, endT);
448 #endif
449 }
450
451 extern "C"
452 void traceUserSuppliedData(int d)
453 {
454 #if CMK_TRACE_ENABLED
455   if (CpvAccess(traceOn) && CkpvAccess(_traces))
456     CkpvAccess(_traces)->userSuppliedData(d);
457 #endif
458 }
459
460 extern "C"
461 void traceUserSuppliedNote(char * note)
462 {
463 #if CMK_TRACE_ENABLED
464   if (CpvAccess(traceOn) && CkpvAccess(_traces))
465     CkpvAccess(_traces)->userSuppliedNote(note);
466 #endif
467 }
468
469
470 extern "C"
471 void traceUserSuppliedBracketedNote(char *note, int eventID, double bt, double et)
472 {
473   //CkPrintf("traceUserSuppliedBracketedNote(char *note, int eventID, double bt, double et)\n");
474 #if CMK_TRACE_ENABLED
475   if (CpvAccess(traceOn) && CkpvAccess(_traces))
476     CkpvAccess(_traces)->userSuppliedBracketedNote(note, eventID, bt, et);
477 #endif
478 }
479
480
481 extern "C"
482 void traceMemoryUsage()
483 {
484 #if CMK_TRACE_ENABLED
485   double d = CmiMemoryUsage()*1.0;
486
487   if (CpvAccess(traceOn) && CkpvAccess(_traces))
488     CkpvAccess(_traces)->memoryUsage(d);
489 #endif
490 }
491
492 extern "C"
493 void tracePhaseEnd()
494 {
495   _TRACE_ONLY(CkpvAccess(_traces)->endPhase());
496 }
497
498 extern "C"
499 void registerMachineUserEventsFunction(void (*eventRegistrationFunc)()) {
500   CmiAssert(CpvInitialized(machineTraceFuncPtr));
501   CpvAccess(machineTraceFuncPtr) = eventRegistrationFunc;
502 }
503
504 extern "C"
505 void (*registerMachineUserEvents())() {
506   CmiAssert(CpvInitialized(machineTraceFuncPtr));
507   if (CpvAccess(machineTraceFuncPtr) != NULL) {
508     return CpvAccess(machineTraceFuncPtr);
509   } else {
510     return NULL;
511   }
512 }
513
514 extern "C"
515 int traceRegisterUserEvent(const char*x, int e)
516 {
517 #if CMK_TRACE_ENABLED
518   return CkpvAccess(_traces)->traceRegisterUserEvent(x, e);
519 #else
520   return 0;
521 #endif
522 }
523
524 extern "C"
525 void traceClearEps(void)
526 {
527   OPTIMIZE_WARNING
528   CkpvAccess(_traces)->traceClearEps();
529 }
530
531 extern "C"
532 void traceWriteSts(void)
533 {
534   OPTIMIZE_WARNING
535   CkpvAccess(_traces)->traceWriteSts();
536 }
537
538 extern "C"
539 void traceFlushLog(void)
540 {
541   OPTIMIZE_WARNING
542   CkpvAccess(_traces)->traceFlushLog();
543 }
544
545 /**
546     traceClose:         this function is called at Converse
547     traceCharmClose:    called at Charm++ level
548 */
549 extern "C"
550 void traceClose(void)
551 {
552 #if ! CMK_BLUEGENE_CHARM
553   OPTIMIZE_WARNING
554   CkpvAccess(_traces)->traceClose();
555 #endif   
556 }
557
558 extern "C"
559 void traceCharmClose(void)
560 {
561 #if CMK_BLUEGENE_CHARM
562   OPTIMIZE_WARNING
563   CkpvAccess(_traces)->traceClose();
564 #endif
565 }
566
567 /* **CW** This is the API called from user code to support CCS operations 
568    if supported by the underlying trace module.
569  */
570 extern "C"
571 void traceEnableCCS(void)
572 {
573   OPTIMIZE_WARNING
574   CkpvAccess(_traces)->traceEnableCCS();  
575 }
576
577 /* **CW** Support for thread listeners. This makes a call to each
578    trace module which must support the call.
579 */
580 extern "C"
581 void traceAddThreadListeners(CthThread tid, envelope *e) {
582   _TRACE_ONLY(CkpvAccess(_traces)->traceAddThreadListeners(tid, e));
583 }
584
585 #if 0
586 // helper functions
587 int CkIsCharmMessage(char *msg)
588 {
589 //CmiPrintf("getMsgtype: %d %d %d %d %d\n", ((envelope *)msg)->getMsgtype(), CmiGetHandler(msg), CmiGetXHandler(msg), _charmHandlerIdx, index_skipCldHandler);
590   if ((CmiGetHandler(msg) == _charmHandlerIdx) &&
591          (CmiGetHandlerFunction(msg) == (CmiHandler)_processHandler))
592     return 1;
593   if (CmiGetXHandler(msg) == _charmHandlerIdx) return 1;
594   return 0;
595 }
596 #endif
597
598 // return 1 if any one of tracing modules is linked.
599 int  traceAvailable()
600 {
601 #if ! CMK_TRACE_ENABLED
602   return 0;
603 #else
604   return CkpvAccess(_traces)->length()>0;
605 #endif
606 }
607
608 double CmiTraceTimer()
609 {
610   return TraceTimer();
611 }
612
613 void TraceArray::creation(envelope *env, int ep, int num)
614
615     if (_entryTable[ep]->traceEnabled)
616         ALLDO(creation(env, ep, num));
617 }
618
619 void TraceArray::creationMulticast(envelope *env, int ep, int num,
620                                    int *pelist)
621 {
622   if (_entryTable[ep]->traceEnabled)
623     ALLDO(creationMulticast(env, ep, num, pelist));
624 }
625
626 /*
627 extern "C" 
628 void registerFunction(char *name){
629         _TRACE_ONLY(CkpvAccess(_traces)->regFunc(name));
630 }
631 */
632
633 extern "C"
634 int traceRegisterFunction(const char* name, int idx) {
635 #if CMK_TRACE_ENABLED
636   if(idx==-999){
637     CkpvAccess(_traces)->regFunc(name, idx);
638   } else {
639     CkpvAccess(_traces)->regFunc(name, idx, 1);
640   }
641   return idx;
642 #else
643   return 0;
644 #endif
645 }
646
647 extern "C" 
648 void traceBeginFuncProj(char *name,char *file,int line){
649          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(name,file,line));
650 }
651
652 extern "C"
653 void traceBeginFuncIndexProj(int idx,char *file,int line){
654          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(idx,file,line));
655 }
656
657 extern "C" 
658 void traceEndFuncProj(char *name){
659          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(name));
660 }
661
662 extern "C" 
663 void traceEndFuncIndexProj(int idx){
664          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(idx));
665 }
666
667 #if CMK_SMP_TRACE_COMMTHREAD
668 extern "C"
669 void traceBeginCommOp(char *msg){
670 #if CMK_TRACE_ENABLED
671   if (CpvAccess(traceOn) && CkpvAccess(_traces))
672     CkpvAccess(_traces)->beginExecute(msg);
673 #endif
674 }
675
676 extern "C"
677 void traceEndCommOp(char *msg){
678 #if CMK_TRACE_ENABLED
679   if (CpvAccess(traceOn) && CkpvAccess(_traces))
680     CkpvAccess(_traces)->endExecute(msg);
681 #endif
682 }
683
684 extern "C"
685 void traceSendMsgComm(char *msg){
686 #if CMK_TRACE_ENABLED
687   if (CpvAccess(traceOn) && CkpvAccess(_traces))
688     CkpvAccess(_traces)->creation(msg);
689 #endif
690 }
691 #endif
692
693 extern "C"
694 void traceChangeLastTimestamp(double ts){
695 #if CMK_TRACE_ENABLED
696   if (CpvAccess(traceOn) && CkpvAccess(_traces))
697     CkpvAccess(_traces)->changeLastEntryTimestamp(ts);
698 #endif
699 }
700
701 /*@}*/