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