Fixed a bug in commlib which was cauing it to hang if a strategy was used to send...
[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   //considering the extra comm thread per node
179   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes()+CkNumNodes());
180 #else   
181   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes());
182 #endif  
183   fprintf(stsfp, "TOTAL_CHARES %d\n", (int)_chareTable.size());
184   fprintf(stsfp, "TOTAL_EPS %d\n", (int)_entryTable.size());
185   fprintf(stsfp, "TOTAL_MSGS %d\n", (int)_msgTable.size());
186   fprintf(stsfp, "TOTAL_PSEUDOS %d\n", (int)0);
187   fprintf(stsfp, "TOTAL_EVENTS %d\n", (int)nUserEvents);
188   size_t i;
189   for(i=0;i<_chareTable.size();i++)
190     fprintf(stsfp, "CHARE %d %s\n", (int)i, _chareTable[i]->name);
191   for(i=0;i<_entryTable.size();i++)
192     fprintf(stsfp, "ENTRY CHARE %d %s %d %d\n", (int)i, _entryTable[i]->name,
193                  (int)_entryTable[i]->chareIdx, (int)_entryTable[i]->msgIdx);
194   for(i=0;i<_msgTable.size();i++)
195     fprintf(stsfp, "MESSAGE %d %u\n", (int)i, (int)_msgTable[i]->size);
196 }
197
198 extern "C"
199 void traceCommonBeginIdle(void *proj,double curWallTime)
200 {
201   ((TraceArray *)proj)->beginIdle(curWallTime);
202 }
203  
204 extern "C"
205 void traceCommonEndIdle(void *proj,double curWallTime)
206 {
207   ((TraceArray *)proj)->endIdle(curWallTime);
208 }
209
210 void TraceArray::traceBegin() {
211   if (n==0) return; // No tracing modules registered.
212 #if ! CMK_TRACE_IN_CHARM
213   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
214   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
215 #endif
216   ALLDO(traceBegin());
217 }
218
219 #if CMK_SMP_TRACE_COMMTHREAD
220 void TraceArray::traceBeginOnCommThread() {
221   if (n==0) return; // No tracing modules registered.
222 /*#if ! CMK_TRACE_IN_CHARM      
223   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
224   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
225 #endif*/
226   ALLDO(traceBeginOnCommThread());
227 }
228 #endif
229
230 void TraceArray::traceEnd() {
231   if (n==0) return; // No tracing modules registered.
232   ALLDO(traceEnd());
233 #if ! CMK_TRACE_IN_CHARM
234   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
235   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
236 #endif
237 }
238
239 #if CMK_SMP_TRACE_COMMTHREAD
240 void TraceArray::traceEndOnCommThread() {
241   if (n==0) return; // No tracing modules registered.
242   ALLDO(traceEndOnCommThread());
243 /*#if ! CMK_TRACE_IN_CHARM
244   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
245   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
246 #endif*/
247 }
248 #endif
249
250
251 /*Install the beginIdle/endIdle condition handlers.*/
252 extern "C" void traceBegin(void) {
253 #if CMK_TRACE_ENABLED
254   DEBUGF(("[%d] traceBegin called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
255   
256 #if CMK_SMP_TRACE_COMMTHREAD
257   //the first core of this node controls the condition of comm thread
258   if(CmiMyRank()==0){
259         if(CkpvAccessOther(traceOn, CmiMyNodeSize())!=1){
260                 CkpvAccessOther(_traces, CmiMyNodeSize())->traceBeginOnCommThread();            
261                 CkpvAccessOther(traceOn, CmiMyNodeSize()) = 1;
262         }
263   }
264 #endif
265   if (CpvAccess(traceOn)==1) return;
266   CkpvAccess(_traces)->traceBegin();
267   CpvAccess(traceOn) = 1;
268 #endif
269 }
270
271 /*Cancel the beginIdle/endIdle condition handlers.*/
272 extern "C" void traceEnd(void) {
273 #if CMK_TRACE_ENABLED
274   DEBUGF(("[%d] traceEnd called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
275
276 #if CMK_SMP_TRACE_COMMTHREAD
277 //the first core of this node controls the condition of comm thread
278 if(CmiMyRank()==0){
279         if(CkpvAccessOther(traceOn, CmiMyNodeSize())!=0){
280                 CkpvAccessOther(_traces, CmiMyNodeSize())->traceEndOnCommThread();
281                 CkpvAccessOther(traceOn, CmiMyNodeSize()) = 0;
282         }
283 }
284 #endif
285         
286         
287   if (CpvAccess(traceOn)==0) return;
288   if (CkpvAccess(_traces) == NULL) {
289     CmiPrintf("Warning: did you mix compilation with and without -DCMK_TRACE_ENABLED? \n");
290   }
291   CkpvAccess(_traces)->traceEnd();
292   CpvAccess(traceOn) = 0;
293 #endif
294 }
295
296 static int checkTraceOnPe(char **argv)
297 {
298   int traceOnPE = 1;
299   char *procs = NULL;
300 #if CMK_BLUEGENE_CHARM
301   // check bgconfig file for settings
302   traceOnPE=0;
303   if (BgTraceProjectionOn(CkMyPe())) traceOnPE = 1;
304 #endif
305   if (CmiGetArgStringDesc(argv, "+traceprocessors", &procs, "A list of processors to trace, e.g. 0,10,20-30"))
306   {
307     CkListString procList(procs);
308     traceOnPE = procList.includes(CkMyPe());
309   }
310   // must include pe 0, otherwise sts file is not generated
311   if (CkMyPe()==0) traceOnPE = 1;
312 #if !CMK_TRACE_IN_CHARM
313 #if !CMK_SMP_TRACE_COMMTHREAD
314   /* skip communication thread */
315   traceOnPE = traceOnPE && (CkMyRank() != CkMyNodeSize());
316 #endif
317 #endif
318   return traceOnPE;
319 }
320
321 /// defined in moduleInit.C
322 void _createTraces(char **argv);
323
324
325 bool enableCPTracing; // A global variable specifying whether or not the control point tracing module should be active in the run
326 extern void _registerTraceControlPoints();
327 extern void _createTracecontrolPoints(char **argv);
328
329
330 /**
331     traceInit:          called at Converse level
332     traceCharmInit:     called at Charm++ level
333 */
334 /// initialize trace framework, also create the trace module(s).
335 static inline void _traceInit(char **argv) 
336 {
337   CkpvInitialize(TraceArray *, _traces);
338   CkpvAccess(_traces) = new TraceArray;
339
340   // common init
341   traceCommonInit(argv);
342
343   // check if trace is turned on/off for this pe
344   CkpvAccess(traceOnPe) = checkTraceOnPe(argv);
345
346   // defined in moduleInit.C
347   _createTraces(argv);
348
349   // Now setup the control point tracing module if desired. It is always compiled/linked in, but is not always enabled
350   // FIXME: make sure it is safe to use argv in SMP version 
351   // because CmiGetArgFlagDesc is destructive and this is called on all PEs.
352   if( CmiGetArgFlagDesc(argv,"+CPEnableMeasurements","Enable recording of measurements for Control Points") ){
353     enableCPTracing = true;
354     _createTracecontrolPoints(argv);   
355   } else {
356     enableCPTracing = false;
357   }
358   
359
360   // set trace on/off
361   CkpvAccess(_traces)->setTraceOnPE(CkpvAccess(traceOnPe));
362
363 #if CMK_SMP_TRACE_COMMTHREAD
364 /**
365  * In traceBegin(), CkpvAccessOther will be used which means
366  * this core needs to access to some cpv variable on another 
367  * core in the same memory address space. It's possible the
368  * variable on the other core has not been initialized, which
369  * implies the CpvAcessOther will cause a bad memory access.
370  * Therefore, we need a barrier here for the traceCommonInit to
371  * finish here. -Chao Mei
372  */
373    CmiBarrier();
374 #endif
375
376   if (CkpvAccess(_traces)->length() && !CmiGetArgFlagDesc(argv,"+traceoff","Disable tracing"))
377     traceBegin();
378 }
379
380 /// Converse version
381 extern "C" void traceInit(char **argv) 
382 {
383 #if ! CMK_TRACE_IN_CHARM
384   _traceInit(argv);
385   initTraceCore(argv);
386 #endif
387 }
388
389 /// Charm++ version
390 extern "C" void traceCharmInit(char **argv) 
391 {
392 #if CMK_TRACE_IN_CHARM
393   _traceInit(argv);
394 #endif
395 }
396
397 // CMK_TRACE_ENABLED is already guarded in convcore.c
398 extern "C"
399 void traceMessageRecv(char *msg, int pe)
400 {
401 #if ! CMK_TRACE_IN_CHARM
402   CkpvAccessOther(_traces, CmiRankOf(pe))->messageRecv(msg, pe);
403 #endif
404 }
405
406 // CMK_TRACE_ENABLED is already guarded in convcore.c
407 // converse thread tracing is not supported in blue gene simulator
408 // in BigSim, threads need to be traced manually (because virtual processors
409 // themselves are implemented as threads and we don't want them to be traced
410 // In BigSim, so far, only AMPI threads are traced.
411 extern "C"
412 void traceResume(CmiObjId *tid)
413 {
414     _TRACE_ONLY(CkpvAccess(_traces)->beginExecute(tid));
415     if(CpvAccess(_traceCoreOn))
416             resumeTraceCore();
417 }
418
419 extern "C"
420 void traceSuspend(void)
421 {
422   _TRACE_ONLY(CkpvAccess(_traces)->endExecute());
423 }
424
425 extern "C"
426 void traceAwaken(CthThread t)
427 {
428   CkpvAccess(_traces)->creation(0, _threadEP);
429 }
430
431 extern "C"
432 void traceUserEvent(int e)
433 {
434 #if CMK_TRACE_ENABLED
435   if (CpvAccess(traceOn))
436     CkpvAccess(_traces)->userEvent(e);
437 #endif
438 }
439
440 extern "C"
441 void traceUserBracketEvent(int e, double beginT, double endT)
442 {
443 #if CMK_TRACE_ENABLED
444   if (CpvAccess(traceOn) && CkpvAccess(_traces))
445     CkpvAccess(_traces)->userBracketEvent(e, beginT, endT);
446 #endif
447 }
448
449 extern "C"
450 void traceUserSuppliedData(int d)
451 {
452 #if CMK_TRACE_ENABLED
453   if (CpvAccess(traceOn) && CkpvAccess(_traces))
454     CkpvAccess(_traces)->userSuppliedData(d);
455 #endif
456 }
457
458 extern "C"
459 void traceUserSuppliedNote(char * note)
460 {
461 #if CMK_TRACE_ENABLED
462   if (CpvAccess(traceOn) && CkpvAccess(_traces))
463     CkpvAccess(_traces)->userSuppliedNote(note);
464 #endif
465 }
466
467
468 extern "C"
469 void traceUserSuppliedBracketedNote(char *note, int eventID, double bt, double et)
470 {
471   //CkPrintf("traceUserSuppliedBracketedNote(char *note, int eventID, double bt, double et)\n");
472 #if CMK_TRACE_ENABLED
473   if (CpvAccess(traceOn) && CkpvAccess(_traces))
474     CkpvAccess(_traces)->userSuppliedBracketedNote(note, eventID, bt, et);
475 #endif
476 }
477
478
479 extern "C"
480 void traceMemoryUsage()
481 {
482 #if CMK_TRACE_ENABLED
483   double d = CmiMemoryUsage()*1.0;
484
485   if (CpvAccess(traceOn) && CkpvAccess(_traces))
486     CkpvAccess(_traces)->memoryUsage(d);
487 #endif
488 }
489
490 extern "C"
491 void tracePhaseEnd()
492 {
493   _TRACE_ONLY(CkpvAccess(_traces)->endPhase());
494 }
495
496 extern "C"
497 void registerMachineUserEventsFunction(void (*eventRegistrationFunc)()) {
498   CmiAssert(CpvInitialized(machineTraceFuncPtr));
499   CpvAccess(machineTraceFuncPtr) = eventRegistrationFunc;
500 }
501
502 extern "C"
503 void (*registerMachineUserEvents())() {
504   CmiAssert(CpvInitialized(machineTraceFuncPtr));
505   if (CpvAccess(machineTraceFuncPtr) != NULL) {
506     return CpvAccess(machineTraceFuncPtr);
507   } else {
508     return NULL;
509   }
510 }
511
512 extern "C"
513 int traceRegisterUserEvent(const char*x, int e)
514 {
515 #if CMK_TRACE_ENABLED
516   return CkpvAccess(_traces)->traceRegisterUserEvent(x, e);
517 #else
518   return 0;
519 #endif
520 }
521
522 extern "C"
523 void traceClearEps(void)
524 {
525   OPTIMIZE_WARNING
526   CkpvAccess(_traces)->traceClearEps();
527 }
528
529 extern "C"
530 void traceWriteSts(void)
531 {
532   OPTIMIZE_WARNING
533   CkpvAccess(_traces)->traceWriteSts();
534 }
535
536 extern "C"
537 void traceFlushLog(void)
538 {
539   OPTIMIZE_WARNING
540   CkpvAccess(_traces)->traceFlushLog();
541 }
542
543 /**
544     traceClose:         this function is called at Converse
545     traceCharmClose:    called at Charm++ level
546 */
547 extern "C"
548 void traceClose(void)
549 {
550 #if ! CMK_BLUEGENE_CHARM
551   OPTIMIZE_WARNING
552   CkpvAccess(_traces)->traceClose();
553 #endif   
554 }
555
556 extern "C"
557 void traceCharmClose(void)
558 {
559 #if CMK_BLUEGENE_CHARM
560   OPTIMIZE_WARNING
561   CkpvAccess(_traces)->traceClose();
562 #endif
563 }
564
565 /* **CW** This is the API called from user code to support CCS operations 
566    if supported by the underlying trace module.
567  */
568 extern "C"
569 void traceEnableCCS(void)
570 {
571   OPTIMIZE_WARNING
572   CkpvAccess(_traces)->traceEnableCCS();  
573 }
574
575 /* **CW** Support for thread listeners. This makes a call to each
576    trace module which must support the call.
577 */
578 extern "C"
579 void traceAddThreadListeners(CthThread tid, envelope *e) {
580   _TRACE_ONLY(CkpvAccess(_traces)->traceAddThreadListeners(tid, e));
581 }
582
583 #if 0
584 // helper functions
585 int CkIsCharmMessage(char *msg)
586 {
587 //CmiPrintf("getMsgtype: %d %d %d %d %d\n", ((envelope *)msg)->getMsgtype(), CmiGetHandler(msg), CmiGetXHandler(msg), _charmHandlerIdx, index_skipCldHandler);
588   if ((CmiGetHandler(msg) == _charmHandlerIdx) &&
589          (CmiGetHandlerFunction(msg) == (CmiHandler)_processHandler))
590     return 1;
591   if (CmiGetXHandler(msg) == _charmHandlerIdx) return 1;
592   return 0;
593 }
594 #endif
595
596 // return 1 if any one of tracing modules is linked.
597 int  traceAvailable()
598 {
599 #if ! CMK_TRACE_ENABLED
600   return 0;
601 #else
602   return CkpvAccess(_traces)->length()>0;
603 #endif
604 }
605
606 double CmiTraceTimer()
607 {
608   return TraceTimer();
609 }
610
611 void TraceArray::creation(envelope *env, int ep, int num)
612
613     if (_entryTable[ep]->traceEnabled)
614         ALLDO(creation(env, ep, num));
615 }
616
617 void TraceArray::creationMulticast(envelope *env, int ep, int num,
618                                    int *pelist)
619 {
620   if (_entryTable[ep]->traceEnabled)
621     ALLDO(creationMulticast(env, ep, num, pelist));
622 }
623
624 /*
625 extern "C" 
626 void registerFunction(char *name){
627         _TRACE_ONLY(CkpvAccess(_traces)->regFunc(name));
628 }
629 */
630
631 extern "C"
632 int traceRegisterFunction(const char* name, int idx) {
633 #if CMK_TRACE_ENABLED
634   if(idx==-999){
635     CkpvAccess(_traces)->regFunc(name, idx);
636   } else {
637     CkpvAccess(_traces)->regFunc(name, idx, 1);
638   }
639   return idx;
640 #else
641   return 0;
642 #endif
643 }
644
645 extern "C" 
646 void traceBeginFuncProj(char *name,char *file,int line){
647          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(name,file,line));
648 }
649
650 extern "C"
651 void traceBeginFuncIndexProj(int idx,char *file,int line){
652          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(idx,file,line));
653 }
654
655 extern "C" 
656 void traceEndFuncProj(char *name){
657          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(name));
658 }
659
660 extern "C" 
661 void traceEndFuncIndexProj(int idx){
662          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(idx));
663 }
664
665 #if CMK_SMP_TRACE_COMMTHREAD
666 extern "C"
667 void traceBeginCommOp(char *msg){
668 #if CMK_TRACE_ENABLED
669   if (CpvAccess(traceOn) && CkpvAccess(_traces))
670     CkpvAccess(_traces)->beginExecute((envelope *)msg);
671 #endif
672 }
673
674 extern "C"
675 void traceEndCommOp(char *msg){
676 #if CMK_TRACE_ENABLED
677   if (CpvAccess(traceOn) && CkpvAccess(_traces))
678     CkpvAccess(_traces)->endExecute();
679 #endif
680 }
681 #endif
682
683 extern "C"
684 void traceChangeLastTimestamp(double ts){
685 #if CMK_TRACE_ENABLED
686   if (CpvAccess(traceOn) && CkpvAccess(_traces))
687     CkpvAccess(_traces)->changeLastEntryTimestamp(ts);
688 #endif
689 }
690
691 /*@}*/