Adding optional support for critical path detection(currently disabled by default...
[charm.git] / src / ck-core / envelope.h
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7 /**
8 \file
9 \addtogroup CkEnvelope
10 */
11 #ifndef _ENVELOPE_H
12 #define _ENVELOPE_H
13
14 #ifndef CkIntbits
15 #define CkIntbits (sizeof(int)*8)
16 #endif
17
18 #ifndef CMK_OPTIMIZE
19 #define _SET_USED(env, x) (env)->setUsed((x))
20 #define _CHECK_USED(env) do { if(env->isUsed()) \
21                            CmiAbort("Message being re-sent. Aborting...\n"); \
22                          } while(0)
23 #else
24 #define _SET_USED(env, x) do{}while(0)
25 #define _CHECK_USED(env) do{}while(0)
26 #endif
27
28 #define CkMsgAlignmentMask     (sizeof(double)-1)
29 #define CkMsgAlignLength(x) (((x)+CkMsgAlignmentMask)&(~(CkMsgAlignmentMask)))
30 #define CkMsgAlignOffset(x)     (CkMsgAlignLength(x)-(x))
31 #define CkPriobitsToInts(nBits)    ((nBits+CkIntbits-1)/CkIntbits)
32 // silly ancient name: for backward compatability only.
33 #define PW(x) CkPriobitsToInts(x) 
34
35
36
37 // #define USE_CRITICAL_PATH_HEADER_ARRAY
38
39 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
40 // This critical path detection is still experimental
41 // Added by Isaac (Dec 2008)
42
43 // stores the pointer to the currently executing msg
44 // used in cklocation.C, ck.C
45 // TODO: convert to CkPv
46
47 extern envelope * currentlyExecutingMsg;
48 extern bool thisMethodSentAMessage;
49 extern double timeEntryMethodStarted;
50
51 // The methods provided by the control point framework to access 
52 // the most Critical path seen by this PE. 
53 // These ought not to be called by the user program.
54 // (defined in controlPoints.C)
55 extern void resetPECriticalPath();
56 extern void printPECriticalPath();
57 extern void registerTerminalEntryMethod();
58
59 // Reset the counts for the currently executing message, 
60 // and also reset the PE's critical path detection
61 // To be called by the user program
62 extern void resetCricitalPathDetection();
63
64 // Reset the counts for the currently executing message
65 extern void resetThisEntryPath();
66
67 #endif
68
69
70 /** static sizes for arrays in PathHistory objects */
71 #define numEpIdxs 150
72 #define numArrayIds 20
73
74 /** A class that is used to track the entry points and other information 
75     about a critical path as a charm++ program executes.
76
77     This class won't do useful things unless USE_CRITICAL_PATH_HEADER_ARRAY is defined
78
79 */
80 class PathHistory {
81  private:
82   int epIdxCount[numEpIdxs];
83   int arrayIdxCount[numArrayIds];
84   double totalTime;
85
86  public:
87   
88   const int* getEpIdxCount(){
89     return epIdxCount;
90   }
91   
92   const int* getArrayIdxCount(){
93     return arrayIdxCount;
94   }
95
96   int getEpIdxCount(int i) const {
97     return epIdxCount[i];
98   }
99   
100   int getArrayIdxCount(int i) const {
101     return arrayIdxCount[i];
102   }
103
104
105   double getTotalTime() const{
106     return totalTime;
107   }
108
109   
110   PathHistory(){
111     reset();
112   }
113
114   void pup(PUP::er &p) {
115     for(int i=0;i<numEpIdxs;i++)
116       p|epIdxCount[i];
117     for(int i=0;i<numArrayIds;i++)
118       p|arrayIdxCount[i];
119     p | totalTime;
120   } 
121   
122   double getTime(){
123     return totalTime;
124   }
125   
126   void reset(){
127     // CkPrintf("reset() currentlyExecutingMsg=%p\n", currentlyExecutingMsg);
128     
129     totalTime = 0.0;
130     
131     for(int i=0;i<numEpIdxs;i++){
132       epIdxCount[i] = 0;
133     }
134     for(int i=0;i<numArrayIds;i++){
135       arrayIdxCount[i]=0;
136     }
137   }
138   
139   int updateMax(const PathHistory & other){
140     if(other.totalTime > totalTime){
141       //          CkPrintf("[%d] Found a longer terminal path:\n", CkMyPe());
142       //          other.print();
143       
144       totalTime = other.totalTime;
145       for(int i=0;i<numEpIdxs;i++){
146         epIdxCount[i] = other.epIdxCount[i];
147       }
148       for(int i=0;i<numArrayIds;i++){
149         arrayIdxCount[i]=other.arrayIdxCount[i];
150       }
151       return 1;
152     }
153     return 0;
154   }
155   
156   
157   void print() const {
158     CkPrintf("Critical Path Time=%lf : ", (double)totalTime);
159     for(int i=0;i<numEpIdxs;i++){
160       if(epIdxCount[i]>0){
161         CkPrintf("EP %d count=%d : ", i, (int)epIdxCount[i]);
162       }
163     }
164     for(int i=0;i<numArrayIds;i++){
165       if(arrayIdxCount[i]>0){
166         CkPrintf("Array %d count=%d : ", i, (int)arrayIdxCount[i]);
167       }
168     }
169     CkPrintf("\n");
170   }
171   
172   void incrementTotalTime(double time){
173     totalTime += time;
174   }
175   
176
177 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
178   void createPath(PathHistory *parentPath){
179     // Note that we are likely sending a message
180     // FIXME: (this should be moved to the actual send point)
181     thisMethodSentAMessage = true;
182     double timeNow = CmiWallTimer();
183     
184     if(parentPath != NULL){
185       //          CkPrintf("createPath() totalTime = %lf + %lf\n",(double)currentlyExecutingMsg->pathHistory.totalTime, (double)timeNow-timeEntryMethodStarted);
186       totalTime = parentPath->totalTime + (timeNow-timeEntryMethodStarted);
187       
188       for(int i=0;i<numEpIdxs;i++){
189         epIdxCount[i] = parentPath->epIdxCount[i];
190       }
191       for(int i=0;i<numArrayIds;i++){
192         arrayIdxCount[i] = parentPath->arrayIdxCount[i];
193       }
194       
195     }
196     else {
197       totalTime = 0.0;
198       
199       for(int i=0;i<numEpIdxs;i++){
200         epIdxCount[i] = 0;
201       } 
202       for(int i=0;i<numArrayIds;i++){
203         arrayIdxCount[i]=0;
204       }
205     }
206         
207   }
208 #endif
209       
210   void incrementEpIdxCount(int ep){
211     epIdxCount[ep]++;
212   }
213
214   void incrementArrayIdxCount(int arr){
215     arrayIdxCount[arr]++;
216   }
217       
218 };
219
220
221
222
223 /**
224  This set of message type (mtype) constants
225  defines the basic class of charm++ message.
226  
227  It is very questionable whether bizarre stuff like
228  "ExitMsg", "StatMsg", "ROMsgMsg" should actually
229  share the envelope with regular user messages;
230  but it doesn't waste any space so it's probably OK.
231 */
232 typedef enum {
233   NewChareMsg    =1,
234   NewVChareMsg   =2,
235   BocInitMsg     =3,
236   ForChareMsg    =4,
237   ForBocMsg      =5,
238   ForVidMsg      =6,
239   FillVidMsg     =7,
240   RODataMsg      =8,
241   ROMsgMsg       =9,
242   ExitMsg        =10,
243   ReqStatMsg     =11,
244   StatMsg        =12,
245   NodeBocInitMsg =13,
246   ForNodeBocMsg  =14,
247   ArrayEltInitMsg =15,
248   ForArrayEltMsg  =16
249 } CkEnvelopeType;
250
251 typedef unsigned int   UInt;
252 typedef unsigned short UShort;
253 typedef unsigned char  UChar;
254
255 #include "charm.h" // for CkGroupID
256
257 /**
258 The "envelope" sits at the start of every Charm++
259 message. It stores information about the handler and
260 destination of the charm++ message that follows, and 
261 what to do with it on the receiving side.
262
263 A Charm++ message's memory layout has the 
264 Charm envelope ("envelope" class) first, which includes
265 a Converse envelope as its **first** field.  After the 
266 Charm envelope is a variable-length amount of user 
267 data, and finally the priority data stored as ints.
268
269 The converse layers modify the beginning of the envelope
270 without referencing the "envelope::core" member. The
271 envelope is treated as a void*, and the first 
272 CmiReservedHeaderSize bytes are available for the 
273 converse functions. Therefore, do not put any members
274 at the beginning of the envelope class.
275
276 <pre>
277  Envelope pointer        \
278  Converse message pointer -> [ [ Converse envelope ]       ]
279                              [       Charm envelope        ] 
280  User message pointer     -> [ User data ... ]
281  Priority pointer         -> [ Priority ints ... ]
282 </pre>
283
284 The "message pointers" passed to and from
285 users bypass the envelope and point *directly* to the 
286 user data--the routine "EnvToUsr" below adjusts an 
287 envelope (or converse message) pointer into this 
288 direct-to-user pointer.  There is a corresponding
289 routine "UsrToEnv" which takes the user data pointer
290 and returns a pointer to the envelope/converse message.
291
292 Unfortunately, in the guts of Charm++ it's not always 
293 clear whether you've been given a converse or user
294 message pointer, as both tend to be passed as void *.
295 Confusing the two will invariably result in data 
296 corruption and bizarre crashes.
297
298 FIXME: Make CkMessage inherit from envelope,
299 which would unify converse, envelope, and 
300 user message pointers.
301 */
302 class envelope {
303   private:
304     /// Converse message envelope, Must be first field in this class
305     char   core[CmiReservedHeaderSize];
306 public:
307  /**
308    This union stores the type-specific message information.
309    Keeing this in a union allows the different kinds of messages 
310    to have different fields/types, in an alignment-safe way, 
311    without wasting any storage.
312  */
313     union u_type {
314       struct s_chare { //NewChareMsg, NewVChareMsg, ForChareMsg, ForVidMsg, FillVidMsg
315         void *ptr;
316         UInt forAnyPe; ///< Used only by newChare
317       } chare;
318       struct s_group {
319         CkGroupID g; ///< GroupID
320         CkNodeGroupID rednMgr; ///< Reduction manager for this group (constructor only!)
321         int epoch; ///< "epoch" this group was created during (0--mainchare, 1--later)
322         UShort arrayEp; ///< Used only for array broadcasts
323       } group;
324       struct s_array{ ///< For arrays only
325         CkArrayIndexStruct index;///< Array element index
326         int listenerData[CK_ARRAYLISTENER_MAXLEN]; ///< For creation
327         CkGroupID arr; ///< Array manager GID
328         UChar hopCount;///< number of times message has been routed
329         UChar ifNotThere; ///< what to do if array element is missing
330       } array;
331       struct s_roData { ///< RODataMsg
332         UInt count;
333       } roData;
334       struct s_roMsg { ///< ROMsgMsg
335         UInt roIdx;
336       } roMsg;
337     };
338     struct s_attribs { //Packed bitwise struct
339         UChar msgIdx; ///< Usertype of message (determines pack routine)
340         UChar mtype; ///< e.g., ForBocMsg
341         UChar queueing:4; ///< Queueing strategy (FIFO, LIFO, PFIFO, ...)
342         UChar isPacked:1; ///< If true, message must be unpacked before use
343         UChar isUsed:1; ///< Marker bit to prevent message re-send.
344     };
345 private:
346     u_type type; ///< Depends on message type (attribs.mtype)
347     UShort ref; ///< Used by futures
348     s_attribs attribs;
349     UChar align[CkMsgAlignOffset(CmiReservedHeaderSize+sizeof(u_type)+sizeof(UShort)+sizeof(s_attribs))];
350     
351     //This struct should now be sizeof(void*) aligned.
352     UShort priobits; ///< Number of bits of priority data after user data
353     UShort epIdx;  ///< Entry point to call
354     UInt   pe;    ///< source processor
355     UInt   event; ///< used by projections
356     UInt   totalsize; ///< Byte count from envelope start to end of priobits
357     
358   public:
359     void pup(PUP::er &p);
360     UInt   getEvent(void) const { return event; }
361     void   setEvent(const UInt e) { event = e; }
362     UInt   getRef(void) const { return ref; }
363     void   setRef(const UShort r) { ref = r; }
364     UChar  getQueueing(void) const { return attribs.queueing; }
365     void   setQueueing(const UChar q) { attribs.queueing=q; }
366     UChar  getMsgtype(void) const { return attribs.mtype; }
367     void   setMsgtype(const UChar m) { attribs.mtype = m; }
368 #ifndef CMK_OPTIMIZE
369     UChar  isUsed(void) { return attribs.isUsed; }
370     void   setUsed(const UChar u) { attribs.isUsed=u; }
371 #else /* CMK_OPTIMIZE */
372     inline void setUsed(const UChar u) {}
373 #endif
374     UChar  getMsgIdx(void) const { return attribs.msgIdx; }
375     void   setMsgIdx(const UChar idx) { attribs.msgIdx = idx; }
376     UInt   getTotalsize(void) const { return totalsize; }
377     void   setTotalsize(const UInt s) { totalsize = s; }
378     UInt   getUsersize(void) const { return totalsize - priobits - sizeof(envelope); }
379     UChar  isPacked(void) const { return attribs.isPacked; }
380     void   setPacked(const UChar p) { attribs.isPacked = p; }
381     UShort getPriobits(void) const { return priobits; }
382     void   setPriobits(const UShort p) { priobits = p; }
383     UShort getPrioWords(void) const { return CkPriobitsToInts(priobits); }
384     UShort getPrioBytes(void) const { return getPrioWords()*sizeof(int); }
385     void*  getPrioPtr(void) const { 
386       return (void *)((char *)this + totalsize - getPrioBytes());
387     }
388     static envelope *alloc(const UChar type, const UInt size=0, const UShort prio=0)
389     {
390       CkAssert(type>=NewChareMsg && type<=ForArrayEltMsg);
391       register UInt tsize = sizeof(envelope)+ 
392             CkMsgAlignLength(size)+
393             sizeof(int)*CkPriobitsToInts(prio);
394       register envelope *env = (envelope *)CmiAlloc(tsize);
395       env->setMsgtype(type);
396       env->totalsize = tsize;
397       env->priobits = prio;
398       env->setPacked(0);
399       _SET_USED(env, 0);
400       //for record-replay
401       env->setEvent(0);
402       return env;
403     }
404     UShort getEpIdx(void) const { return epIdx; }
405     void   setEpIdx(const UShort idx) { epIdx = idx; }
406     UInt   getSrcPe(void) const { return pe; }
407     void   setSrcPe(const UInt s) { pe = s; }
408     static void setSrcPe(char *env, const UInt s) { ((envelope*)env)->setSrcPe(s); }
409
410 // Readonly-specific fields
411     UInt   getCount(void) const { 
412       CkAssert(getMsgtype()==RODataMsg); return type.roData.count; 
413     }
414     void   setCount(const UInt c) { 
415       CkAssert(getMsgtype()==RODataMsg); type.roData.count = c; 
416     }
417     UInt   getRoIdx(void) const { 
418       CkAssert(getMsgtype()==ROMsgMsg); return type.roMsg.roIdx; 
419     }
420     void   setRoIdx(const UInt r) { 
421       CkAssert(getMsgtype()==ROMsgMsg); type.roMsg.roIdx = r; 
422     }
423     
424  // Chare-specific fields
425     UInt isForAnyPE(void) { 
426       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
427       return type.chare.forAnyPe; 
428     }
429     void setForAnyPE(UInt f) { 
430       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
431       type.chare.forAnyPe = f; 
432     }
433     void*  getVidPtr(void) const {
434       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
435           || getMsgtype()==FillVidMsg);
436       return type.chare.ptr;
437     }
438     void   setVidPtr(void *p) {
439       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
440           || getMsgtype()==FillVidMsg);
441       type.chare.ptr = p;
442     }
443     void*  getObjPtr(void) const { 
444       CkAssert(getMsgtype()==ForChareMsg); return type.chare.ptr; 
445     }
446     void   setObjPtr(void *p) { 
447       CkAssert(getMsgtype()==ForChareMsg); type.chare.ptr = p; 
448     }
449
450 // Group-specific fields
451     CkGroupID   getGroupNum(void) const {
452       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
453           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
454       return type.group.g;
455     }
456     void   setGroupNum(const CkGroupID g) {
457       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
458           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
459       type.group.g = g;
460     }
461     void setGroupEpoch(int epoch) { type.group.epoch=epoch; }
462     int getGroupEpoch(void) { return type.group.epoch; }
463     void setRednMgr(CkNodeGroupID r){ type.group.rednMgr = r; }
464     CkNodeGroupID getRednMgr(){ return type.group.rednMgr; }
465
466 // Array-specific fields
467     CkGroupID &getsetArrayMgr(void) {return type.array.arr;}
468     UShort &getsetArrayEp(void) {return epIdx;}
469     UShort &getsetArrayBcastEp(void) {return type.group.arrayEp;}
470     UInt &getsetArraySrcPe(void) {return pe;}
471     UChar &getsetArrayHops(void) {return type.array.hopCount;}
472     int getArrayIfNotThere(void) {return type.array.ifNotThere;}
473     void setArrayIfNotThere(int nt) {type.array.ifNotThere=nt;}
474     int *getsetArrayListenerData(void) {return type.array.listenerData;}
475     CkArrayIndexMax &getsetArrayIndex(void) 
476         {return *(CkArrayIndexMax *)&type.array.index;}
477
478 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
479  public:
480
481     /// The information regarding the entry methods that executed along the path to this one.
482     PathHistory pathHistory;
483
484     void resetEpIdxHistory(){
485       pathHistory.reset();
486     }
487
488     /** Fill in the values for the path When creating a message in an entry method, 
489         deriving the values from the entry method's creation message */
490     void setEpIdxHistory(){
491       if(currentlyExecutingMsg){
492         pathHistory.createPath(& currentlyExecutingMsg->pathHistory);
493       } else {
494         pathHistory.createPath(NULL);
495       }
496     }
497
498     void printEpIdxHistory(){
499       pathHistory.print();
500     }
501       
502     /// Called when beginning to execute an entry method 
503     void updateCounts(){
504       pathHistory.incrementEpIdxCount(getEpIdx());
505       if(attribs.mtype==ForArrayEltMsg){
506         CkGroupID &a = type.array.arr;
507         pathHistory.incrementArrayIdxCount(a.idx);
508       }
509     }
510 #endif
511
512 };
513
514 inline envelope *UsrToEnv(const void *const msg) {
515   return (((envelope *) msg)-1);
516 }
517
518 inline void *EnvToUsr(const envelope *const env) {
519   return ((void *)(env+1));
520 }
521
522 inline envelope *_allocEnv(const int msgtype, const int size=0, const int prio=0) {
523   return envelope::alloc(msgtype,size,prio);
524 }
525
526 inline void *_allocMsg(const int msgtype, const int size, const int prio=0) {
527   return EnvToUsr(envelope::alloc(msgtype,size,prio));
528 }
529
530 extern UChar   _defaultQueueing;
531
532 extern void CkPackMessage(envelope **pEnv);
533 extern void CkUnpackMessage(envelope **pEnv);
534
535 class MsgPool: public SafePool<void *> {
536 private:
537     static void *_alloc(void) {
538       /* CkAllocSysMsg() called in .def.h is not thread of sigio safe */
539       register envelope *env = _allocEnv(ForChareMsg,0,0);
540       env->setQueueing(_defaultQueueing);
541       env->setMsgIdx(0);
542       return EnvToUsr(env);
543     }
544 public:
545     MsgPool():SafePool<void*>(_alloc, CkFreeMsg) {}
546 };
547
548 CkpvExtern(MsgPool*, _msgPool);
549
550
551
552 #endif