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