changed a few things in order to link with application.
[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
15 // cannot include charm++.h because trace-common.o is part of libconv-core.a
16 #include "charm.h"
17 #include "middle.h"
18 #include "cklists.h"
19 #include "ckliststring.h"
20
21 #include "trace.h"
22 #include "trace-common.h"
23 #include "allEvents.h"          //projector
24 #include "register.h" // for _entryTable
25
26 CpvCExtern(int, _traceCoreOn);   // projector
27
28 #define DEBUGF(x)          // CmiPrintf x
29
30 #define LogBufSize      10000
31
32 #ifdef CMK_OPTIMIZE
33 static int warned = 0;
34 #define OPTIMIZE_WARNING if (!warned) { warned=1;  CmiPrintf("\n\n!!!! Warning: tracing not available with CMK_OPTIMIZE!\n");  return;  }
35 #else
36 #define OPTIMIZE_WARNING /*empty*/
37 #endif
38
39 CkpvDeclare(TraceArray*, _traces);              // lists of all trace modules
40
41 /* trace for bluegene */
42 class TraceBluegene;
43 CkpvDeclare(TraceBluegene*, _tracebg);
44 int traceBluegeneLinked=0;                      // if trace-bluegene is linked
45
46 CkpvDeclare(double, traceInitTime);
47 CkpvDeclare(double, traceInitCpuTime);
48 CpvDeclare(int, traceOn);
49 CkpvDeclare(int, traceOnPe);
50
51 CkpvDeclare(int, CtrLogBufSize);
52 CkpvDeclare(char*, traceRoot);
53
54 int _threadMsg, _threadChare, _threadEP;
55 int _packMsg, _packChare, _packEP;
56 int _unpackMsg, _unpackChare, _unpackEP;
57 int _dummyMsg, _dummyChare, _dummyEP;
58
59 /// decide parameters from command line
60 static void traceCommonInit(char **argv)
61 {
62   CmiArgGroup("Charm++","Tracing");
63   DEBUGF(("[%d] in traceCommonInit.\n", CkMyPe()));
64   CkpvInitialize(double, traceInitTime);
65   CkpvAccess(traceInitTime) = CmiStartTimer();
66   CkpvInitialize(double, traceInitCpuTime);
67   CkpvAccess(traceInitCpuTime) = TRACE_CPUTIMER();
68   CpvInitialize(int, traceOn);
69   CpvInitialize(int, _traceCoreOn); //projector
70   CkpvInitialize(int, CtrLogBufSize);
71   CkpvInitialize(char*, traceRoot);
72   CpvAccess(traceOn) = 0;
73   CpvAccess(_traceCoreOn)=0; //projector
74   CkpvInitialize(int, traceOnPe);
75   CkpvAccess(traceOnPe) = 1;
76   CkpvAccess(CtrLogBufSize) = LogBufSize;
77   if (CmiGetArgIntDesc(argv,"+logsize",&CkpvAccess(CtrLogBufSize), "Log entries to buffer per I/O"))
78     if (CkMyPe() == 0) 
79       CmiPrintf("Trace: logsize: %d\n", CkpvAccess(CtrLogBufSize));
80   char *root;
81   if (CmiGetArgStringDesc(argv, "+traceroot", &root, "Directory to write trace files to")) {
82     int i;
83     for (i=strlen(argv[0])-1; i>=0; i--) if (argv[0][i] == '/') break;
84     i++;
85     CkpvAccess(traceRoot) = (char *)malloc(strlen(argv[0]+i) + strlen(root) + 2);    _MEMCHECK(CkpvAccess(traceRoot));
86     strcpy(CkpvAccess(traceRoot), root);
87     strcat(CkpvAccess(traceRoot), "/");
88     strcat(CkpvAccess(traceRoot), argv[0]+i);
89     if (CkMyPe() == 0) 
90       CmiPrintf("Trace: traceroot: %s\n", CkpvAccess(traceRoot));
91   }
92   else {
93     CkpvAccess(traceRoot) = (char *) malloc(strlen(argv[0])+1);
94     _MEMCHECK(CkpvAccess(traceRoot));
95     strcpy(CkpvAccess(traceRoot), argv[0]);
96   }
97   
98 #ifdef __BLUEGENE__
99   if(BgNodeRank()==0) {
100 #else
101   if(CkMyRank()==0) {
102 #endif
103     _threadMsg = CkRegisterMsg("dummy_thread_msg", 0, 0, 0);
104     _threadChare = CkRegisterChare("dummy_thread_chare", 0);
105     _threadEP = CkRegisterEp("dummy_thread_ep", 0, _threadMsg,_threadChare, 0+CK_EP_INTRINSIC);
106
107     _packMsg = CkRegisterMsg("dummy_pack_msg", 0, 0, 0);
108     _packChare = CkRegisterChare("dummy_pack_chare", 0);
109     _packEP = CkRegisterEp("dummy_pack_ep", 0, _packMsg,_packChare, 0+CK_EP_INTRINSIC);
110
111     _unpackMsg = CkRegisterMsg("dummy_unpack_msg", 0, 0, 0);
112     _unpackChare = CkRegisterChare("dummy_unpack_chare", 0);
113     _unpackEP = CkRegisterEp("dummy_unpack_ep", 0, _unpackMsg,_unpackChare, 0+CK_EP_INTRINSIC);
114
115     _dummyMsg = CkRegisterMsg("dummy_msg", 0, 0, 0);
116     _dummyChare = CkRegisterChare("dummy_chare", 0);
117     _dummyEP = CkRegisterEp("dummy_ep", 0, _dummyMsg,_dummyChare, 0+CK_EP_INTRINSIC);
118   }
119 }
120
121 /** Write out the common parts of the .sts file. */
122 extern void traceWriteSTS(FILE *stsfp,int nUserEvents) {
123   fprintf(stsfp, "MACHINE %s\n",CMK_MACHINE_NAME);
124   fprintf(stsfp, "PROCESSORS %d\n", CkNumPes());
125   fprintf(stsfp, "TOTAL_CHARES %d\n", _chareTable.size());
126   fprintf(stsfp, "TOTAL_EPS %d\n", _entryTable.size());
127   fprintf(stsfp, "TOTAL_MSGS %d\n", _msgTable.size());
128   fprintf(stsfp, "TOTAL_PSEUDOS %d\n", 0);
129   fprintf(stsfp, "TOTAL_EVENTS %d\n", nUserEvents);
130   int i;
131   for(i=0;i<_chareTable.size();i++)
132     fprintf(stsfp, "CHARE %d %s\n", i, _chareTable[i]->name);
133   for(i=0;i<_entryTable.size();i++)
134     fprintf(stsfp, "ENTRY CHARE %d %s %d %d\n", i, _entryTable[i]->name,
135                  _entryTable[i]->chareIdx, _entryTable[i]->msgIdx);
136   for(i=0;i<_msgTable.size();i++)
137     fprintf(stsfp, "MESSAGE %d %d\n", i, _msgTable[i]->size);
138 }
139
140 extern "C"
141 void traceCommonBeginIdle(void *proj,double curWallTime)
142 {
143   ((TraceArray *)proj)->beginIdle(curWallTime);
144 }
145  
146 extern "C"
147 void traceCommonEndIdle(void *proj,double curWallTime)
148 {
149   ((TraceArray *)proj)->endIdle(curWallTime);
150 }
151
152 void TraceArray::traceBegin() {
153   if (n==0) return; // No tracing modules registered.
154 #if ! CMK_TRACE_IN_CHARM
155   cancel_beginIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)traceCommonBeginIdle,this);
156   cancel_endIdle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)traceCommonEndIdle,this);
157 #endif
158   ALLDO(traceBegin());
159 }
160
161 void TraceArray::traceEnd() {
162   if (n==0) return; // No tracing modules registered.
163   ALLDO(traceEnd());
164 #if ! CMK_TRACE_IN_CHARM
165   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE, cancel_beginIdle);
166   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY, cancel_endIdle);
167 #endif
168 }
169
170 /*Install the beginIdle/endIdle condition handlers.*/
171 extern "C" void traceBegin(void) {
172   OPTIMIZE_WARNING
173   DEBUGF(("[%d] traceBegin called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
174   if (CpvAccess(traceOn)==1) return;
175   CkpvAccess(_traces)->traceBegin();
176   CpvAccess(traceOn) = 1;
177 }
178
179 /*Cancel the beginIdle/endIdle condition handlers.*/
180 extern "C" void traceEnd(void) {
181   OPTIMIZE_WARNING
182   DEBUGF(("[%d] traceEnd called with %d at %f\n", CkMyPe(), CpvAccess(traceOn), TraceTimer()));
183   if (CpvAccess(traceOn)==0) return;
184   CkpvAccess(_traces)->traceEnd();
185   CpvAccess(traceOn) = 0;
186 }
187
188 static int checkTraceOnPe(char **argv)
189 {
190   int i;
191   int traceOnPE = 1;
192   char *procs = NULL;
193 #if CMK_BLUEGENE_CHARM
194   // check bgconfig file for settings
195   traceOnPE=0;
196   if (BgTraceProjectionOn(CkMyPe())) traceOnPE = 1;
197 #endif
198   if (CmiGetArgStringDesc(argv, "+traceprocessors", &procs, "A list of processors to trace, e.g. 0,10,20-30"))
199   {
200     CkListString procList(strdup(procs));
201     traceOnPE = procList.includes(CkMyPe());
202   }
203   // must include pe 0, otherwise sts file is not generated
204   if (CkMyPe()==0) traceOnPE = 1;
205 #if !CMK_TRACE_IN_CHARM
206   /* skip communication thread */
207   traceOnPE = traceOnPE && (CkMyRank() != CkMyNodeSize());
208 #endif
209   return traceOnPE;
210 }
211
212 /// defined in moduleInit.C
213 void _createTraces(char **argv);
214
215 /**
216     traceInit:          called at Converse level
217     traceCharmInit:     called at Charm++ level
218 */
219 /// initialize trace framework, also create the trace module(s).
220 static inline void _traceInit(char **argv) 
221 {
222   CkpvInitialize(TraceArray *, _traces);
223   CkpvAccess(_traces) = new TraceArray;
224
225   // common init
226   traceCommonInit(argv);
227
228   // check if trace is turned on/off for this pe
229   CkpvAccess(traceOnPe) = checkTraceOnPe(argv);
230
231   // defined in moduleInit.C
232   _createTraces(argv);
233
234   // set trace on/off
235   CkpvAccess(_traces)->setTraceOnPE(CkpvAccess(traceOnPe));
236
237   if (CkpvAccess(_traces)->length() && !CmiGetArgFlagDesc(argv,"+traceoff","Disable tracing"))
238     traceBegin();
239 }
240
241 /// Converse version
242 extern "C" void traceInit(char **argv) 
243 {
244 #if ! CMK_TRACE_IN_CHARM
245   _traceInit(argv);
246 #endif
247   initTraceCore(argv);
248 }
249
250 /// Charm++ version
251 extern "C" void traceCharmInit(char **argv) 
252 {
253 #if CMK_TRACE_IN_CHARM
254   _traceInit(argv);
255 #endif
256 }
257
258 // CMK_OPTIMIZE is already guarded in convcore.c
259 extern "C"
260 void traceMessageRecv(char *msg, int pe)
261 {
262 #if ! CMK_TRACE_IN_CHARM
263   CkpvAccessOther(_traces, CmiRankOf(pe))->messageRecv(msg, pe);
264 #endif
265 }
266
267 // CMK_OPTIMIZE is already guarded in convcore.c
268 // converse thread tracing is not supported in blue gene simulator
269 // in BigSim, threads need to be traced manually (because virtual processors
270 // themselves are implemented as threads and we don't want them to be traced
271 // In BigSim, so far, only AMPI threads are traced.
272 extern "C"
273 void traceResume(CmiObjId *tid)
274 {
275     _TRACE_ONLY(CkpvAccess(_traces)->beginExecute(tid));
276     if(CpvAccess(_traceCoreOn))
277             resumeTraceCore();
278 }
279
280 extern "C"
281 void traceSuspend(void)
282 {
283   _TRACE_ONLY(CkpvAccess(_traces)->endExecute());
284 }
285
286 extern "C"
287 void traceAwaken(CthThread t)
288 {
289   CkpvAccess(_traces)->creation(0, _threadEP);
290 }
291
292 extern "C"
293 void traceUserEvent(int e)
294 {
295 #ifndef CMK_OPTIMIZE
296   if (CpvAccess(traceOn))
297     CkpvAccess(_traces)->userEvent(e);
298 #endif
299 }
300
301 extern "C"
302 void traceUserBracketEvent(int e, double beginT, double endT)
303 {
304 #ifndef CMK_OPTIMIZE
305   if (CpvAccess(traceOn) && CkpvAccess(_traces))
306     CkpvAccess(_traces)->userBracketEvent(e, beginT, endT);
307 #endif
308 }
309
310 extern "C"
311 int traceRegisterUserEvent(const char*x, int e)
312 {
313 #ifndef CMK_OPTIMIZE
314   return CkpvAccess(_traces)->traceRegisterUserEvent(x, e);
315 #else
316   return 0;
317 #endif
318 }
319
320 extern "C"
321 void traceClearEps(void)
322 {
323   OPTIMIZE_WARNING
324   CkpvAccess(_traces)->traceClearEps();
325 }
326
327 extern "C"
328 void traceWriteSts(void)
329 {
330   OPTIMIZE_WARNING
331   CkpvAccess(_traces)->traceWriteSts();
332 }
333
334 extern "C"
335 void traceFlushLog(void)
336 {
337   OPTIMIZE_WARNING
338   CkpvAccess(_traces)->traceFlushLog();
339 }
340
341 /**
342     traceClose:         this function is called at Converse
343     traceCharmClose:    called at Charm++ level
344 */
345 extern "C"
346 void traceClose(void)
347 {
348 #if ! CMK_BLUEGENE_CHARM
349   OPTIMIZE_WARNING
350   CkpvAccess(_traces)->traceClose();
351 #endif   
352 }
353
354 extern "C"
355 void traceCharmClose(void)
356 {
357 #if CMK_BLUEGENE_CHARM
358   OPTIMIZE_WARNING
359   CkpvAccess(_traces)->traceClose();
360 #endif
361 }
362
363 /* **CW** Support for thread listeners. This makes a call to each
364    trace module which must support the call.
365 */
366 extern "C"
367 void traceAddThreadListeners(CthThread tid, envelope *e) {
368   _TRACE_ONLY(CkpvAccess(_traces)->traceAddThreadListeners(tid, e));
369 }
370
371 #if 0
372 // helper functions
373 int CkIsCharmMessage(char *msg)
374 {
375 //CmiPrintf("getMsgtype: %d %d %d %d %d\n", ((envelope *)msg)->getMsgtype(), CmiGetHandler(msg), CmiGetXHandler(msg), _charmHandlerIdx, index_skipCldHandler);
376   if ((CmiGetHandler(msg) == _charmHandlerIdx) &&
377          (CmiGetHandlerFunction(msg) == (CmiHandler)_processHandler))
378     return 1;
379   if (CmiGetXHandler(msg) == _charmHandlerIdx) return 1;
380   return 0;
381 }
382 #endif
383
384 // return 1 if any one of tracing modules is linked.
385 int  traceAvailable()
386 {
387 #ifdef CMK_OPTIMIZE
388   return 0;
389 #else
390   return CkpvAccess(_traces)->length()>0;
391 #endif
392 }
393
394 double CmiTraceTimer()
395 {
396   return TraceTimer();
397 }
398
399 void TraceArray::creation(envelope *env, int ep, int num)
400
401     if (_entryTable[ep]->traceEnabled)
402         ALLDO(creation(env, ep, num));
403 }
404
405 void TraceArray::creationMulticast(envelope *env, int ep, int num,
406                                    int *pelist)
407 {
408   if (_entryTable[ep]->traceEnabled)
409     ALLDO(creationMulticast(env, ep, num, pelist));
410 }
411
412 /*
413 extern "C" 
414 void registerFunction(char *name){
415         _TRACE_ONLY(CkpvAccess(_traces)->regFunc(name));
416 }
417 */
418
419 extern "C"
420 int traceRegisterFunction(const char* name) {
421 #ifndef CMK_OPTIMIZE
422   int idx;
423   CkpvAccess(_traces)->regFunc(name, idx);
424   return idx;
425 #else
426   return 0;
427 #endif
428 }
429
430 extern "C" 
431 void traceBeginFuncProj(char *name,char *file,int line){
432          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(name,file,line));
433 }
434
435 extern "C"
436 void traceBeginFuncIndexProj(int idx,char *file,int line){
437          _TRACE_ONLY(CkpvAccess(_traces)->beginFunc(idx,file,line));
438 }
439
440 extern "C" 
441 void traceEndFuncProj(char *name){
442          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(name));
443 }
444
445 extern "C" 
446 void traceEndFuncIndexProj(int idx){
447          _TRACE_ONLY(CkpvAccess(_traces)->endFunc(idx));
448 }
449
450 /*@}*/