Added a new flag for message logging and team-based support.
[charm.git] / src / ck-core / envelope.h
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7 /**
8  @defgroup CkEnvelope
9  \brief  Charm++ message header.
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 /**
40     \addtogroup CriticalPathFramework 
41     @{
42 */
43
44 /** A class that is used to track the entry points and other information 
45     about a critical path as a charm++ program executes.
46
47     This class won't do useful things unless USE_CRITICAL_PATH_HEADER_ARRAY is defined
48 */
49 class PathHistoryEnvelope {
50  protected:
51   // When passing paths forward, store information on PEs, in backward pass, lookup necessary information
52   int sender_history_table_idx;
53   double totalTime;
54  public:
55   double getTotalTime() const{ return totalTime; }
56   int get_sender_history_table_idx() const{ return sender_history_table_idx; }
57   void set_sender_history_table_idx(int i) { sender_history_table_idx = i; }
58   PathHistoryEnvelope(){ reset(); }
59   double getTime() const{ return totalTime; }
60   void setTime(double t){ totalTime = t; }
61   void pup(PUP::er &p) {
62     p | sender_history_table_idx;
63     p | totalTime;
64   } 
65   void reset();
66   void print() const;
67   /// Write a description of the path into the beginning of the provided buffer. The buffer ought to be large enough.
68   void printHTMLToString(char* buf) const{
69     buf[0] = '\0';
70     sprintf(buf+strlen(buf), "Path Time=%lf<br> Sender idx=%d", (double)totalTime, (int)sender_history_table_idx);
71   }
72   /// The number of available EP counts 
73   int getNumUsed() const;
74   /// Return the count value for the idx'th available EP  
75   int getUsedCount(int idx) const;
76   /// Return the idx'th available EP 
77   int getUsedEp(int idx) const;
78   int getEpCount(int ep) const;
79   void incrementTotalTime(double time);
80   //  void createPath(envelope *originatingMsg);
81   void setDebug100();
82 };
83 /** @} */
84
85
86
87 typedef unsigned int   UInt;
88 typedef unsigned short UShort;
89 typedef unsigned char  UChar;
90
91 #include "charm.h" // for CkGroupID, and CkEnvelopeType
92 #ifdef _FAULT_MLOG_
93 #include "ckobjid.h" //for the ckobjId
94 #endif
95
96 /**
97 @addtogroup CkEnvelope
98 @{
99 The class envelope defines a Charm++ message's header. The first
100 'CmiReservedHeaderSize' bytes of memory is exclusively reserved for Converse
101 header, which is defined in convere.h and platform specific config files.
102
103 After Charm++ envelope comes the payload, i.e. a variable-length amount of user
104 data. Following the user data, optionally, a variable number of bits of
105 priority data can be stored at the end. Function
106 envelope::alloc(msgtype,size,prio) is always used to allocate the whole
107 message. Note that this memory layout must be observed.
108
109 The following are a few terms that are used often:
110
111 <pre>
112  Envelope pointer        \
113  Converse message pointer -> [ [ Converse envelope ]       ]
114                              [       Charm envelope        ] 
115  User message pointer     -> [ User data/payload ... ]
116  Priority pointer         -> [ Priority ints ... ]
117 </pre>
118
119 The "message pointers" passed to and from users bypass the envelope and point
120 *directly* to the user data--the routine "EnvToUsr" below adjusts an envelope
121 (or converse message) pointer into this user message pointer.  There is a
122 corresponding routine "UsrToEnv" which takes the user data pointer and returns
123 a pointer to the envelope/converse message.
124
125 Unfortunately, in the guts of Charm++ it's not always clear whether you've been
126 given a converse or user message pointer, as both tend to be passed as void *.
127 Confusing the two will invariably result in data corruption and bizarre
128 crashes.
129
130 FIXME: Make CkMessage inherit from envelope,
131 which would unify converse, envelope, and 
132 user message pointers.
133 */
134 class envelope {
135   private:
136     /// Converse message envelope, Must be first field in this class
137     char   core[CmiReservedHeaderSize];
138 public:
139  /**
140    This union stores the type-specific message information.
141    Keeping this in a union allows the different kinds of messages 
142    to have different fields/types, in an alignment-safe way, 
143    without wasting any storage.
144  */
145     union u_type {
146       struct s_chare { //NewChareMsg, NewVChareMsg, ForChareMsg, ForVidMsg, FillVidMsg
147         void *ptr;       ///< object pointer
148         UInt forAnyPe;   ///< Used only by newChare
149       } chare;
150       struct s_group {
151         CkGroupID g;           ///< GroupID
152         CkNodeGroupID rednMgr; ///< Reduction manager for this group (constructor only!)
153         int epoch;             ///< "epoch" this group was created during (0--mainchare, 1--later)
154         UShort arrayEp;        ///< Used only for array broadcasts
155       } group;
156       struct s_array{               ///< For arrays only
157         CkArrayIndexStruct index;   ///< Array element index
158         int listenerData[CK_ARRAYLISTENER_MAXLEN]; ///< For creation
159         CkGroupID arr;              ///< Array manager GID
160         UChar hopCount;             ///< number of times message has been routed
161         UChar ifNotThere;           ///< what to do if array element is missing
162       } array;
163       struct s_roData {        ///< RODataMsg for readonly data type
164         UInt count;
165       } roData;
166       struct s_roMsg {         ///< ROMsgMsg for readonlys defined in ci files
167         UInt roIdx;
168       } roMsg;
169     };
170     struct s_attribs {        // Packed bitwise struct
171         UChar msgIdx;         ///< Usertype of message (determines pack routine)
172         UChar mtype;          ///< e.g., ForBocMsg
173         UChar queueing:4;     ///< Queueing strategy (FIFO, LIFO, PFIFO, ...)
174         UChar isPacked:1;     ///< If true, message must be unpacked before use
175         UChar isUsed:1;       ///< Marker bit to prevent message re-send.
176     };
177 #ifdef _FAULT_MLOG_
178     CkObjID sender;
179     CkObjID recver;
180     MCount SN;
181     MCount TN;
182     MlogEntry *localMlogEntry;
183         bool freeMsg;
184 #endif
185 private:
186     u_type type;           ///< Depends on message type (attribs.mtype)
187     UShort ref;            ///< Used by futures
188     s_attribs attribs;
189     UChar align[CkMsgAlignOffset(CmiReservedHeaderSize+sizeof(u_type)+sizeof(UShort)+sizeof(s_attribs))];    ///< padding to make sure sizeof(double) alignment
190     
191     //This struct should now be sizeof(void*) aligned.
192     UShort priobits;   ///< Number of bits of priority data after user data
193     UShort epIdx;      ///< Entry point to call
194     UInt   pe;         ///< source processor
195     UInt   event;      ///< used by projections
196     UInt   totalsize;  ///< Byte count from envelope start to end of priobits
197     
198   public:
199 #ifdef _FAULT_MLOG_
200     UInt piggyBcastIdx;
201 #endif
202     void pup(PUP::er &p);
203     UInt   getEvent(void) const { return event; }
204     void   setEvent(const UInt e) { event = e; }
205     UInt   getRef(void) const { return ref; }
206     void   setRef(const UShort r) { ref = r; }
207     UChar  getQueueing(void) const { return attribs.queueing; }
208     void   setQueueing(const UChar q) { attribs.queueing=q; }
209     UChar  getMsgtype(void) const { return attribs.mtype; }
210     void   setMsgtype(const UChar m) { attribs.mtype = m; }
211 #ifndef CMK_OPTIMIZE
212     UChar  isUsed(void) { return attribs.isUsed; }
213     void   setUsed(const UChar u) { attribs.isUsed=u; }
214 #else /* CMK_OPTIMIZE */
215     inline void setUsed(const UChar u) {}
216 #endif
217     UChar  getMsgIdx(void) const { return attribs.msgIdx; }
218     void   setMsgIdx(const UChar idx) { attribs.msgIdx = idx; }
219     UInt   getTotalsize(void) const { return totalsize; }
220     void   setTotalsize(const UInt s) { totalsize = s; }
221     UInt   getUsersize(void) const { return totalsize - priobits - sizeof(envelope); }
222     UChar  isPacked(void) const { return attribs.isPacked; }
223     void   setPacked(const UChar p) { attribs.isPacked = p; }
224     UShort getPriobits(void) const { return priobits; }
225     void   setPriobits(const UShort p) { priobits = p; }
226     UShort getPrioWords(void) const { return CkPriobitsToInts(priobits); }
227     UShort getPrioBytes(void) const { return getPrioWords()*sizeof(int); }
228     void*  getPrioPtr(void) const { 
229       return (void *)((char *)this + totalsize - getPrioBytes());
230     }
231     static envelope *alloc(const UChar type, const UInt size=0, const UShort prio=0)
232     {
233       CkAssert(type>=NewChareMsg && type<=ForArrayEltMsg);
234       register UInt tsize = sizeof(envelope)+ 
235             CkMsgAlignLength(size)+
236             sizeof(int)*CkPriobitsToInts(prio);
237       register envelope *env = (envelope *)CmiAlloc(tsize);
238       env->setMsgtype(type);
239       env->totalsize = tsize;
240       env->priobits = prio;
241       env->setPacked(0);
242       _SET_USED(env, 0);
243       //for record-replay
244       env->setEvent(0);
245       env->setRef(0);
246
247 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
248       env->pathHistory.reset();
249 #endif
250
251 #ifdef _FAULT_MLOG_
252       env->sender.type = TypeInvalid;
253       env->recver.type = TypeInvalid;
254       env->SN = 0;
255       env->TN = 0;
256       env->localMlogEntry = NULL;
257 #endif
258
259       return env;
260     }
261     UShort getEpIdx(void) const { return epIdx; }
262     void   setEpIdx(const UShort idx) { epIdx = idx; }
263     UInt   getSrcPe(void) const { return pe; }
264     void   setSrcPe(const UInt s) { pe = s; }
265     static void setSrcPe(char *env, const UInt s) { ((envelope*)env)->setSrcPe(s); }
266
267 // Readonly-specific fields
268     UInt   getCount(void) const { 
269       CkAssert(getMsgtype()==RODataMsg); return type.roData.count; 
270     }
271     void   setCount(const UInt c) { 
272       CkAssert(getMsgtype()==RODataMsg); type.roData.count = c; 
273     }
274     UInt   getRoIdx(void) const { 
275       CkAssert(getMsgtype()==ROMsgMsg); return type.roMsg.roIdx; 
276     }
277     void   setRoIdx(const UInt r) { 
278       CkAssert(getMsgtype()==ROMsgMsg); type.roMsg.roIdx = r; 
279     }
280     
281  // Chare-specific fields
282     UInt isForAnyPE(void) { 
283       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
284       return type.chare.forAnyPe; 
285     }
286     void setForAnyPE(UInt f) { 
287       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
288       type.chare.forAnyPe = f; 
289     }
290     void*  getVidPtr(void) const {
291       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
292           || getMsgtype()==FillVidMsg);
293       return type.chare.ptr;
294     }
295     void   setVidPtr(void *p) {
296       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
297           || getMsgtype()==FillVidMsg);
298       type.chare.ptr = p;
299     }
300     void*  getObjPtr(void) const { 
301       CkAssert(getMsgtype()==ForChareMsg); return type.chare.ptr; 
302     }
303     void   setObjPtr(void *p) { 
304       CkAssert(getMsgtype()==ForChareMsg); type.chare.ptr = p; 
305     }
306
307 // Group-specific fields
308     CkGroupID   getGroupNum(void) const {
309       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
310           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
311       return type.group.g;
312     }
313     void   setGroupNum(const CkGroupID g) {
314       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
315           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
316       type.group.g = g;
317     }
318     void setGroupEpoch(int epoch) { type.group.epoch=epoch; }
319     int getGroupEpoch(void) { return type.group.epoch; }
320     void setRednMgr(CkNodeGroupID r){ type.group.rednMgr = r; }
321     CkNodeGroupID getRednMgr(){ return type.group.rednMgr; }
322
323 // Array-specific fields
324     CkGroupID &getsetArrayMgr(void) {return type.array.arr;}
325     int getArrayMgrIdx(void) const {return type.array.arr.idx;}
326     UShort &getsetArrayEp(void) {return epIdx;}
327     UShort &getsetArrayBcastEp(void) {return type.group.arrayEp;}
328     UInt &getsetArraySrcPe(void) {return pe;}
329     UChar &getsetArrayHops(void) {return type.array.hopCount;}
330     int getArrayIfNotThere(void) {return type.array.ifNotThere;}
331     void setArrayIfNotThere(int nt) {type.array.ifNotThere=nt;}
332     int *getsetArrayListenerData(void) {return type.array.listenerData;}
333     CkArrayIndexMax &getsetArrayIndex(void) 
334         {return *(CkArrayIndexMax *)&type.array.index;}
335
336 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
337  public:
338     /** The information regarding the entry methods that executed along the path to this one.
339         \addtogroup CriticalPathFramework
340     */
341     PathHistoryEnvelope pathHistory;
342 #endif
343
344 };
345
346
347 inline envelope *UsrToEnv(const void *const msg) {
348   return (((envelope *) msg)-1);
349 }
350
351 inline void *EnvToUsr(const envelope *const env) {
352   return ((void *)(env+1));
353 }
354
355 inline envelope *_allocEnv(const int msgtype, const int size=0, const int prio=0) {
356   return envelope::alloc(msgtype,size,prio);
357 }
358
359 inline void *_allocMsg(const int msgtype, const int size, const int prio=0) {
360   return EnvToUsr(envelope::alloc(msgtype,size,prio));
361 }
362
363 /** @} */
364
365 extern UChar   _defaultQueueing;
366
367 extern void CkPackMessage(envelope **pEnv);
368 extern void CkUnpackMessage(envelope **pEnv);
369
370 class MsgPool: public SafePool<void *> {
371 private:
372     static void *_alloc(void) {
373       /* CkAllocSysMsg() called in .def.h is not thread of sigio safe */
374       register envelope *env = _allocEnv(ForChareMsg,0,0);
375       env->setQueueing(_defaultQueueing);
376       env->setMsgIdx(0);
377       return EnvToUsr(env);
378     }
379 public:
380     MsgPool():SafePool<void*>(_alloc, CkFreeMsg) {}
381 #ifdef _FAULT_MLOG_
382         void *get(void){
383             return allocfn();
384         }
385         void put(void *m){
386         }
387 #endif
388 };
389
390 CkpvExtern(MsgPool*, _msgPool);
391
392 #endif