82ca3295304ac659e550292ad8413b98a5326825
[charm.git] / src / ck-core / envelope.h
1 /**
2  @defgroup CkEnvelope
3  \brief  Charm++ message header.
4 */
5 #ifndef _ENVELOPE_H
6 #define _ENVELOPE_H
7
8 #include <pup.h>
9 #include <charm.h>
10 #include <middle.h>
11 #include <ckarrayindex.h>
12 #include <cklists.h>
13 #include <objid.h>
14
15 #ifndef CkIntbits
16 #define CkIntbits (sizeof(int)*8)
17 #endif
18
19 #if CMK_ERROR_CHECKING
20 #define _SET_USED(env, x) (env)->setUsed((x))
21 #define _CHECK_USED(env) do { if(env->isUsed()) \
22                            CmiAbort("Message being re-sent. Aborting...\n"); \
23                          } while(0)
24 #else
25 #define _SET_USED(env, x) do{}while(0)
26 #define _CHECK_USED(env) do{}while(0)
27 #endif
28
29 #define CkMsgAlignLength(x)     ALIGN_DEFAULT(x)
30 #define CkMsgAlignOffset(x)     (CkMsgAlignLength(x)-(x))
31 #define CkPriobitsToInts(nBits)    ((nBits+CkIntbits-1)/CkIntbits)
32
33 #if CMK_MESSAGE_LOGGING
34 #define CK_FREE_MSG_MLOG        0x1
35 #define CK_BYPASS_DET_MLOG      0x2
36 #define CK_MULTICAST_MSG_MLOG   0x4
37 #define CK_REDUCTION_MSG_MLOG   0x8
38 #endif
39
40 //#define USE_CRITICAL_PATH_HEADER_ARRAY
41
42 /**
43     \addtogroup CriticalPathFramework 
44     @{
45 */
46
47 /** A class that is used to track the entry points and other information 
48     about a critical path as a charm++ program executes.
49
50     This class won't do useful things unless USE_CRITICAL_PATH_HEADER_ARRAY is defined
51 */
52 class PathHistoryEnvelope {
53  protected:
54   // When passing paths forward, store information on PEs, in backward pass, lookup necessary information
55   int sender_history_table_idx;
56   double totalTime;
57  public:
58   double getTotalTime() const{ return totalTime; }
59   int get_sender_history_table_idx() const{ return sender_history_table_idx; }
60   void set_sender_history_table_idx(int i) { sender_history_table_idx = i; }
61   PathHistoryEnvelope(){ 
62 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
63     reset(); 
64 #endif
65   }
66   double getTime() const{ return totalTime; }
67   void setTime(double t){ totalTime = t; }
68   void pup(PUP::er &p) {
69     p | sender_history_table_idx;
70     p | totalTime;
71   } 
72   void reset();
73   void print() const;
74   /// Write a description of the path into the beginning of the provided buffer. The buffer ought to be large enough.
75   void printHTMLToString(char* buf) const{
76     buf[0] = '\0';
77     sprintf(buf+strlen(buf), "Path Time=%lf<br> Sender idx=%d", (double)totalTime, (int)sender_history_table_idx);
78   }
79   /// The number of available EP counts 
80   int getNumUsed() const;
81   /// Return the count value for the idx'th available EP  
82   int getUsedCount(int idx) const;
83   /// Return the idx'th available EP 
84   int getUsedEp(int idx) const;
85   int getEpCount(int ep) const;
86   void incrementTotalTime(double time);
87   //  void createPath(envelope *originatingMsg);
88   void setDebug100();
89 };
90 /** @} */
91
92
93
94 typedef unsigned int   UInt;
95 typedef unsigned short UShort;
96 typedef unsigned char  UChar;
97
98 #include "charm.h" // for CkGroupID, and CkEnvelopeType
99 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
100 #include "ckobjid.h" //for the ckobjId
101 #endif
102
103 /**
104 @addtogroup CkEnvelope
105 */
106
107 CkpvExtern(int, envelopeEventID);
108
109 struct s_objid_o {
110   ck::ObjID id;              /// <ck::ObjID if it could be in a union
111 #if CMK_SMP_TRACE_COMMTHREAD
112   UInt srcpe;
113 #endif
114   UChar hopCount;           ///< number of times message has been routed
115   UChar ifNotThere;         ///< what to do if array element is missing
116 };
117
118
119 /**
120 @{
121 The class envelope defines a Charm++ message's header. The first
122 'CmiReservedHeaderSize' bytes of memory is exclusively reserved for Converse
123 header, which is defined in converse.h and platform specific config files.
124
125 After Charm++ envelope comes the payload, i.e. a variable-length amount of user
126 data. Following the user data, optionally, a variable number of bits of
127 priority data can be stored at the end. Function
128 envelope::alloc(msgtype,size,prio) is always used to allocate the whole
129 message. Note that this memory layout must be observed.
130
131 The following are a few terms that are used often:
132
133 <pre>
134  Envelope pointer        \
135  Converse message pointer -> [ [ Converse envelope ]       ]
136                              [       Charm envelope        ] 
137  User message pointer     -> [ User data/payload ... ]
138  Priority pointer         -> [ Priority ints ... ]
139 </pre>
140
141 The "message pointers" passed to and from users bypass the envelope and point
142 *directly* to the user data--the routine "EnvToUsr" below adjusts an envelope
143 (or converse message) pointer into this user message pointer.  There is a
144 corresponding routine "UsrToEnv" which takes the user data pointer and returns
145 a pointer to the envelope/converse message.
146
147 Unfortunately, in the guts of Charm++ it's not always clear whether you've been
148 given a converse or user message pointer, as both tend to be passed as void *.
149 Confusing the two will invariably result in data corruption and bizarre
150 crashes.
151
152 FIXME: Make CkMessage inherit from envelope,
153 which would unify converse, envelope, and 
154 user message pointers.
155 */
156
157 namespace ck {
158
159   namespace impl {
160     /**
161        These structures store the type-specific message information.
162     */
163     union u_type {
164       struct s_chare {  // NewChareMsg, NewVChareMsg, ForChareMsg, ForVidMsg, FillVidMsg
165         void *ptr;      ///< object pointer
166         UInt forAnyPe;  ///< Used only by newChare
167         int  bype;      ///< created by this pe
168       } chare;
169       struct s_group {         // NodeBocInitMsg, BocInitMsg, ForNodeBocMsg, ForBocMsg
170         CkGroupID g;           ///< GroupID
171         CkNodeGroupID rednMgr; ///< Reduction manager for this group (constructor only!)
172         CkGroupID dep;         ///< create after dep is created (constructor only!)
173         int epoch;             ///< "epoch" this group was created during (0--mainchare, 1--later)
174         UShort arrayEp;        ///< Used only for array broadcasts
175       } group;
176       struct s_array{             ///< For arrays only (ArrayEltInitMsg, ForArrayEltMsg)
177         CkArrayIndexBase index; ///< Array element index
178         int listenerData[CK_ARRAYLISTENER_MAXLEN]; ///< For creation
179         CkGroupID arr;            ///< Array manager GID
180 #if CMK_SMP_TRACE_COMMTHREAD
181         UInt srcpe;
182 #endif
183         UChar hopCount;           ///< number of times message has been routed
184         UChar ifNotThere;         ///< what to do if array element is missing
185       } array;
186       struct s_objid {
187         CmiUInt8 id;              /// <ck::ObjID if it could be in a union
188 #if CMK_SMP_TRACE_COMMTHREAD
189         UInt srcpe;
190 #endif
191         UChar hopCount;           ///< number of times message has been routed
192         UChar ifNotThere;         ///< what to do if array element is missing
193       } objid;
194       struct s_roData {    ///< RODataMsg for readonly data type
195         UInt count;
196       } roData;
197       struct s_roMsg {     ///< ROMsgMsg for readonlys defined in ci files
198         UInt roIdx;
199       } roMsg;
200     };
201
202     struct s_attribs {  // Packed bitwise struct
203       UChar msgIdx;     ///< Usertype of message (determines pack routine)
204       UChar mtype;      ///< e.g., ForBocMsg
205       UChar queueing:4; ///< Queueing strategy (FIFO, LIFO, PFIFO, ...)
206       UChar isPacked:1; ///< If true, message must be unpacked before use
207       UChar isUsed:1;   ///< Marker bit to prevent message re-send.
208     };
209
210   }
211 }
212
213 #if (defined(_FAULT_MLOG_) && !defined(_FAULT_CAUSAL_))
214 #define CMK_ENVELOPE_FT_FIELDS                           \
215   CkObjID sender;                                        \
216   CkObjID recver;                                        \
217   MCount SN;                                             \
218   int incarnation;                                       \
219   int flags;                                             \
220   UInt piggyBcastIdx;
221 #elif defined(_FAULT_CAUSAL_)
222 #define CMK_ENVELOPE_FT_FIELDS                           \
223   CkObjID sender;                                        \
224   CkObjID recver;                                        \
225   MCount SN;                                             \
226   MCount TN;                                             \
227   int incarnation;                                       \
228   int flags;                                             \
229   UInt piggyBcastIdx;
230 #else
231 #define CMK_ENVELOPE_FT_FIELDS
232 #endif
233
234 #if CMK_REPLAYSYSTEM || CMK_TRACE_ENABLED
235 #define CMK_ENVELOPE_OPTIONAL_FIELDS                                           \
236   UInt   event;        /* used by projections and record-replay */
237 #else
238 #define CMK_ENVELOPE_OPTIONAL_FIELDS
239 #endif
240
241 #define CMK_ENVELOPE_FIELDS                                                    \
242   /* Converse message envelope, Must be first field in this class */           \
243   char   core[CmiReservedHeaderSize];                                          \
244   ck::impl::u_type type; /* Depends on message type (attribs.mtype) */         \
245   UInt   pe;           /* source processor */                                  \
246   UInt   totalsize;    /* Byte count from envelope start to end of priobits */ \
247   CMK_ENVELOPE_OPTIONAL_FIELDS                                                 \
248   CMK_REFNUM_TYPE ref; /* Used by futures and SDAG */                          \
249   UShort priobits;     /* Number of bits of priority data after user data */   \
250   UShort epIdx;        /* Entry point to call */                               \
251   ck::impl::s_attribs attribs;
252
253 class envelope {
254 private:
255
256     class envelopeSizeHelper {
257       CMK_ENVELOPE_FIELDS
258       CMK_ENVELOPE_FT_FIELDS
259     };
260
261     CMK_ENVELOPE_FIELDS
262
263 public:
264
265     CMK_ENVELOPE_FT_FIELDS
266
267     // padding to ensure ALIGN_BYTES alignment
268     UChar align[CkMsgAlignOffset(sizeof(envelopeSizeHelper))];
269
270     void pup(PUP::er &p);
271 #if CMK_REPLAYSYSTEM || CMK_TRACE_ENABLED
272     UInt   getEvent(void) const { return event; }
273     void   setEvent(const UInt e) { event = e; }
274 #endif
275     CMK_REFNUM_TYPE   getRef(void) const { return ref; }
276     void   setRef(const CMK_REFNUM_TYPE r) { ref = r; }
277     UChar  getQueueing(void) const { return attribs.queueing; }
278     void   setQueueing(const UChar q) { attribs.queueing=q; }
279     UChar  getMsgtype(void) const { return attribs.mtype; }
280     void   setMsgtype(const UChar m) { attribs.mtype = m; }
281 #if CMK_ERROR_CHECKING
282     UChar  isUsed(void) { return attribs.isUsed; }
283     void   setUsed(const UChar u) { attribs.isUsed=u; }
284 #else /* CMK_ERROR_CHECKING */
285     inline void setUsed(const UChar u) {}
286 #endif
287     UChar  getMsgIdx(void) const { return attribs.msgIdx; }
288     void   setMsgIdx(const UChar idx) { attribs.msgIdx = idx; }
289     UInt   getTotalsize(void) const { return totalsize; }
290     void   setTotalsize(const UInt s) { totalsize = s; }
291     UInt   getUsersize(void) const { 
292       return totalsize - getPrioBytes() - sizeof(envelope); 
293     }
294     void   setUsersize(const UInt s) {
295       if (s == getUsersize()) {
296         return;
297       }
298       CkAssert(s < getUsersize());
299       UInt newPrioOffset = sizeof(envelope) + CkMsgAlignLength(s);
300       UInt newTotalsize = newPrioOffset + getPrioBytes();
301       void *newPrioPtr = (void *) ((char *) this + newPrioOffset); 
302       // use memmove instead of memcpy in case memory areas overlap
303       memmove(newPrioPtr, getPrioPtr(), getPrioBytes()); 
304       setTotalsize(newTotalsize); 
305     }
306
307     // s specifies number of bytes to remove from user portion of message
308     void shrinkUsersize(const UInt s) {
309       CkAssert(s <= getUsersize());
310       setUsersize(getUsersize() - s);
311     }
312
313     UChar  isPacked(void) const { return attribs.isPacked; }
314     void   setPacked(const UChar p) { attribs.isPacked = p; }
315     UShort getPriobits(void) const { return priobits; }
316     void   setPriobits(const UShort p) { priobits = p; }
317     UShort getPrioWords(void) const { return CkPriobitsToInts(priobits); }
318     UShort getPrioBytes(void) const { return getPrioWords()*sizeof(int); }
319     void*  getPrioPtr(void) const { 
320       return (void *)((char *)this + totalsize - getPrioBytes());
321     }
322     static envelope *alloc(const UChar type, const UInt size=0, const UShort prio=0)
323     {
324       CkAssert(type>=NewChareMsg && type<=ForArrayEltMsg);
325 #if CMK_USE_STL_MSGQ
326       // Ideally, this should be a static compile-time assert. However we need API changes for that
327       CkAssert(sizeof(CMK_MSG_PRIO_TYPE) >= sizeof(int)*CkPriobitsToInts(prio));
328 #endif
329
330       UInt tsize = sizeof(envelope)+ 
331             CkMsgAlignLength(size)+
332             sizeof(int)*CkPriobitsToInts(prio);
333       envelope *env = (envelope *)CmiAlloc(tsize);
334 #if CMK_REPLAYSYSTEM
335       //for record-replay
336       memset(env, 0, sizeof(envelope));
337       env->setEvent(++CkpvAccess(envelopeEventID));
338 #endif
339       env->setMsgtype(type);
340       env->totalsize = tsize;
341       env->priobits = prio;
342       env->setPacked(0);
343       env->type.group.dep.setZero();
344       _SET_USED(env, 0);
345       env->setRef(0);
346       env->setEpIdx(0);
347
348 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
349       env->pathHistory.reset();
350 #endif
351
352 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
353       env->sender.type = TypeInvalid;
354       env->recver.type = TypeInvalid;
355       env->SN = 0;
356       env->flags = 0;
357 #if defined(_FAULT_CAUSAL_)
358       env->TN = 0;
359 #endif
360           env->incarnation = -1;
361 #endif
362
363       return env;
364     }
365     void reset() {
366 #if CMK_REPLAYSYSTEM
367       setEvent(++CkpvAccess(envelopeEventID));
368 #endif
369       type.group.dep.setZero();
370     }
371     UShort getEpIdx(void) const { return epIdx; }
372     void   setEpIdx(const UShort idx) { epIdx = idx; }
373     UInt   getSrcPe(void) const { return pe; }
374     void   setSrcPe(const UInt s) { pe = s; }
375     static void setSrcPe(char *env, const UInt s) { ((envelope*)env)->setSrcPe(s); }
376
377 // Readonly-specific fields
378     UInt   getCount(void) const { 
379       CkAssert(getMsgtype()==RODataMsg); return type.roData.count; 
380     }
381     void   setCount(const UInt c) { 
382       CkAssert(getMsgtype()==RODataMsg); type.roData.count = c; 
383     }
384     UInt   getRoIdx(void) const { 
385       CkAssert(getMsgtype()==ROMsgMsg); return type.roMsg.roIdx; 
386     }
387     void   setRoIdx(const UInt r) { 
388       CkAssert(getMsgtype()==ROMsgMsg); type.roMsg.roIdx = r; 
389     }
390     
391  // Chare-specific fields
392     UInt isForAnyPE(void) { 
393       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
394       return type.chare.forAnyPe; 
395     }
396     void setForAnyPE(UInt f) { 
397       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
398       type.chare.forAnyPe = f; 
399     }
400     void*  getVidPtr(void) const {
401       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
402           || getMsgtype()==FillVidMsg ||  getMsgtype()==DeleteVidMsg);
403       return type.chare.ptr;
404     }
405     void   setVidPtr(void *p) {
406       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
407           || getMsgtype()==FillVidMsg ||  getMsgtype()==DeleteVidMsg);
408       type.chare.ptr = p;
409     }
410     void*  getObjPtr(void) const { 
411       CkAssert(getMsgtype()==ForChareMsg); return type.chare.ptr; 
412     }
413     void   setObjPtr(void *p) { 
414       CkAssert(getMsgtype()==ForChareMsg); type.chare.ptr = p; 
415     }
416     UInt getByPe(void) { 
417       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
418       return type.chare.bype; 
419     }
420     void setByPe(UInt pe) { 
421       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
422       type.chare.bype = pe; 
423     }
424
425 // Group-specific fields
426     CkGroupID   getGroupNum(void) const {
427       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
428           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
429       return type.group.g;
430     }
431     void   setGroupNum(const CkGroupID g) {
432       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
433           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
434       type.group.g = g;
435     }
436     void setGroupEpoch(int epoch) { CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==NodeBocInitMsg); type.group.epoch=epoch; }
437     int getGroupEpoch(void) { CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==NodeBocInitMsg); return type.group.epoch; }
438     void setRednMgr(CkNodeGroupID r){ CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
439           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
440  type.group.rednMgr = r; }
441     CkNodeGroupID getRednMgr(){       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
442           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
443  return type.group.rednMgr; }
444     CkGroupID getGroupDep(){       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
445           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
446  return type.group.dep; }
447     void setGroupDep(const CkGroupID &r){       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
448           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
449       type.group.dep = r; }
450
451 // Array-specific fields
452     CkGroupID getArrayMgr(void) const { 
453       if (getMsgtype() == ForArrayEltMsg || getMsgtype() == ArrayEltInitMsg)
454         return type.array.arr;
455       else if (getMsgtype() == ForIDedObjMsg)
456         return ((struct s_objid_o *) &type.objid)->id.getCollectionID();
457       else
458             CkAbort("Cannot return ArrayID from msg for non-array entity");
459         /* compiler appeasement, even though this will never be executed */
460       return type.array.arr;
461     }
462     void setArrayMgr(const CkGroupID gid) { CkAssert(getMsgtype() == ForArrayEltMsg || getMsgtype() == ArrayEltInitMsg);  type.array.arr = gid; }
463     int getArrayMgrIdx(void) const {CkAssert(getMsgtype() == ForArrayEltMsg || getMsgtype() == ArrayEltInitMsg);  return type.array.arr.idx;}
464     UShort &getsetArrayEp(void) {return epIdx;}
465     UShort &getsetArrayBcastEp(void) {return type.group.arrayEp;}
466 #if CMK_SMP_TRACE_COMMTHREAD
467     UInt &getsetArraySrcPe(void) {return type.array.srcpe;}
468 #else
469     UInt &getsetArraySrcPe(void) {return pe;}
470 #endif
471     UChar &getsetArrayHops(void) { CkAssert(getMsgtype() == ForArrayEltMsg || getMsgtype() == ArrayEltInitMsg); return type.array.hopCount;}
472     int getArrayIfNotThere(void) { CkAssert(getMsgtype() == ForArrayEltMsg || getMsgtype() == ArrayEltInitMsg); return type.array.ifNotThere;}
473     void setArrayIfNotThere(int nt) { CkAssert(getMsgtype() == ForArrayEltMsg || getMsgtype() == ArrayEltInitMsg); type.array.ifNotThere=nt;}
474     int *getsetArrayListenerData(void) {return type.array.listenerData;}
475     CkArrayIndex &getsetArrayIndex(void) 
476         { 
477           CkAssert(getMsgtype() == ForArrayEltMsg || getMsgtype() == ArrayEltInitMsg);
478           return *(CkArrayIndex *)&type.array.index;
479         }
480
481 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
482  public:
483     /** The information regarding the entry methods that executed along the path to this one.
484         \addtogroup CriticalPathFramework
485     */
486     PathHistoryEnvelope pathHistory;
487 #endif
488
489 };
490
491
492 inline envelope *UsrToEnv(const void *const msg) {
493   return (envelope *)((intptr_t)msg - sizeof(envelope));
494 }
495
496 inline void *EnvToUsr(const envelope *const env) {
497   return (void *)((intptr_t)env + sizeof(envelope));
498 }
499
500 inline envelope *_allocEnv(const int msgtype, const int size=0, const int prio=0) {
501   return envelope::alloc(msgtype,size,prio);
502 }
503
504 inline void *_allocMsg(const int msgtype, const int size, const int prio=0) {
505   return EnvToUsr(envelope::alloc(msgtype,size,prio));
506 }
507
508 inline void _resetEnv(envelope *env) {
509   env->reset();
510 }
511
512 #if CMK_REPLAYSYSTEM
513 inline void setEventID(envelope *env){
514   env->setEvent(++CkpvAccess(envelopeEventID));
515 }
516 #endif
517
518 /** @} */
519
520 extern UChar   _defaultQueueing;
521
522 extern void CkPackMessage(envelope **pEnv);
523 extern void CkUnpackMessage(envelope **pEnv);
524
525 class MsgPool: public SafePool<void *> {
526 private:
527     static void *_alloc(void) {
528       /* CkAllocSysMsg() called in .def.h is not thread of sigio safe */
529       envelope *env = _allocEnv(ForChareMsg,0,0);
530       env->setQueueing(_defaultQueueing);
531       env->setMsgIdx(0);
532       return EnvToUsr(env);
533     }
534     static void _reset(void* m) {
535       envelope *env = UsrToEnv(m);
536       _resetEnv(env);
537     }
538 public:
539     MsgPool():SafePool<void*>(_alloc, CkFreeMsg, _reset) {}
540 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
541         void *get(void){
542             return allocfn();
543         }
544         void put(void *m){
545         }
546 #endif
547 };
548
549 CkpvExtern(MsgPool*, _msgPool);
550
551 #endif