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