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