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