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