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