d2270a540c7e066fab6100bb2596eb73fd05ba71
[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 #endif
184 private:
185     u_type type;           ///< Depends on message type (attribs.mtype)
186     UShort ref;            ///< Used by futures
187     s_attribs attribs;
188     UChar align[CkMsgAlignOffset(CmiReservedHeaderSize+sizeof(u_type)+sizeof(UShort)+sizeof(s_attribs))];    ///< padding to make sure sizeof(double) alignment
189     
190     //This struct should now be sizeof(void*) aligned.
191     UShort priobits;   ///< Number of bits of priority data after user data
192     UShort epIdx;      ///< Entry point to call
193     UInt   pe;         ///< source processor
194     UInt   event;      ///< used by projections
195     UInt   totalsize;  ///< Byte count from envelope start to end of priobits
196     
197   public:
198 #ifdef _FAULT_MLOG_
199     UInt piggyBcastIdx;
200 #endif
201     void pup(PUP::er &p);
202     UInt   getEvent(void) const { return event; }
203     void   setEvent(const UInt e) { event = e; }
204     UInt   getRef(void) const { return ref; }
205     void   setRef(const UShort r) { ref = r; }
206     UChar  getQueueing(void) const { return attribs.queueing; }
207     void   setQueueing(const UChar q) { attribs.queueing=q; }
208     UChar  getMsgtype(void) const { return attribs.mtype; }
209     void   setMsgtype(const UChar m) { attribs.mtype = m; }
210 #ifndef CMK_OPTIMIZE
211     UChar  isUsed(void) { return attribs.isUsed; }
212     void   setUsed(const UChar u) { attribs.isUsed=u; }
213 #else /* CMK_OPTIMIZE */
214     inline void setUsed(const UChar u) {}
215 #endif
216     UChar  getMsgIdx(void) const { return attribs.msgIdx; }
217     void   setMsgIdx(const UChar idx) { attribs.msgIdx = idx; }
218     UInt   getTotalsize(void) const { return totalsize; }
219     void   setTotalsize(const UInt s) { totalsize = s; }
220     UInt   getUsersize(void) const { return totalsize - priobits - sizeof(envelope); }
221     UChar  isPacked(void) const { return attribs.isPacked; }
222     void   setPacked(const UChar p) { attribs.isPacked = p; }
223     UShort getPriobits(void) const { return priobits; }
224     void   setPriobits(const UShort p) { priobits = p; }
225     UShort getPrioWords(void) const { return CkPriobitsToInts(priobits); }
226     UShort getPrioBytes(void) const { return getPrioWords()*sizeof(int); }
227     void*  getPrioPtr(void) const { 
228       return (void *)((char *)this + totalsize - getPrioBytes());
229     }
230     static envelope *alloc(const UChar type, const UInt size=0, const UShort prio=0)
231     {
232       CkAssert(type>=NewChareMsg && type<=ForArrayEltMsg);
233       register UInt tsize = sizeof(envelope)+ 
234             CkMsgAlignLength(size)+
235             sizeof(int)*CkPriobitsToInts(prio);
236       register envelope *env = (envelope *)CmiAlloc(tsize);
237       env->setMsgtype(type);
238       env->totalsize = tsize;
239       env->priobits = prio;
240       env->setPacked(0);
241       _SET_USED(env, 0);
242       //for record-replay
243       env->setEvent(0);
244       env->setRef(0);
245
246 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
247       env->pathHistory.reset();
248 #endif
249
250 #ifdef _FAULT_MLOG_
251       env->sender.type = TypeInvalid;
252       env->recver.type = TypeInvalid;
253       env->SN = 0;
254       env->TN = 0;
255       env->localMlogEntry = NULL;
256 #endif
257
258       return env;
259     }
260     UShort getEpIdx(void) const { return epIdx; }
261     void   setEpIdx(const UShort idx) { epIdx = idx; }
262     UInt   getSrcPe(void) const { return pe; }
263     void   setSrcPe(const UInt s) { pe = s; }
264     static void setSrcPe(char *env, const UInt s) { ((envelope*)env)->setSrcPe(s); }
265
266 // Readonly-specific fields
267     UInt   getCount(void) const { 
268       CkAssert(getMsgtype()==RODataMsg); return type.roData.count; 
269     }
270     void   setCount(const UInt c) { 
271       CkAssert(getMsgtype()==RODataMsg); type.roData.count = c; 
272     }
273     UInt   getRoIdx(void) const { 
274       CkAssert(getMsgtype()==ROMsgMsg); return type.roMsg.roIdx; 
275     }
276     void   setRoIdx(const UInt r) { 
277       CkAssert(getMsgtype()==ROMsgMsg); type.roMsg.roIdx = r; 
278     }
279     
280  // Chare-specific fields
281     UInt isForAnyPE(void) { 
282       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
283       return type.chare.forAnyPe; 
284     }
285     void setForAnyPE(UInt f) { 
286       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
287       type.chare.forAnyPe = f; 
288     }
289     void*  getVidPtr(void) const {
290       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
291           || getMsgtype()==FillVidMsg);
292       return type.chare.ptr;
293     }
294     void   setVidPtr(void *p) {
295       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
296           || getMsgtype()==FillVidMsg);
297       type.chare.ptr = p;
298     }
299     void*  getObjPtr(void) const { 
300       CkAssert(getMsgtype()==ForChareMsg); return type.chare.ptr; 
301     }
302     void   setObjPtr(void *p) { 
303       CkAssert(getMsgtype()==ForChareMsg); type.chare.ptr = p; 
304     }
305
306 // Group-specific fields
307     CkGroupID   getGroupNum(void) const {
308       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
309           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
310       return type.group.g;
311     }
312     void   setGroupNum(const CkGroupID g) {
313       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
314           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
315       type.group.g = g;
316     }
317     void setGroupEpoch(int epoch) { type.group.epoch=epoch; }
318     int getGroupEpoch(void) { return type.group.epoch; }
319     void setRednMgr(CkNodeGroupID r){ type.group.rednMgr = r; }
320     CkNodeGroupID getRednMgr(){ return type.group.rednMgr; }
321
322 // Array-specific fields
323     CkGroupID &getsetArrayMgr(void) {return type.array.arr;}
324     int getArrayMgrIdx(void) const {return type.array.arr.idx;}
325     UShort &getsetArrayEp(void) {return epIdx;}
326     UShort &getsetArrayBcastEp(void) {return type.group.arrayEp;}
327     UInt &getsetArraySrcPe(void) {return pe;}
328     UChar &getsetArrayHops(void) {return type.array.hopCount;}
329     int getArrayIfNotThere(void) {return type.array.ifNotThere;}
330     void setArrayIfNotThere(int nt) {type.array.ifNotThere=nt;}
331     int *getsetArrayListenerData(void) {return type.array.listenerData;}
332     CkArrayIndexMax &getsetArrayIndex(void) 
333         {return *(CkArrayIndexMax *)&type.array.index;}
334
335 #ifdef USE_CRITICAL_PATH_HEADER_ARRAY
336  public:
337     /** The information regarding the entry methods that executed along the path to this one.
338         \addtogroup CriticalPathFramework
339     */
340     PathHistoryEnvelope pathHistory;
341 #endif
342
343 };
344
345
346 inline envelope *UsrToEnv(const void *const msg) {
347   return (((envelope *) msg)-1);
348 }
349
350 inline void *EnvToUsr(const envelope *const env) {
351   return ((void *)(env+1));
352 }
353
354 inline envelope *_allocEnv(const int msgtype, const int size=0, const int prio=0) {
355   return envelope::alloc(msgtype,size,prio);
356 }
357
358 inline void *_allocMsg(const int msgtype, const int size, const int prio=0) {
359   return EnvToUsr(envelope::alloc(msgtype,size,prio));
360 }
361
362 /** @} */
363
364 extern UChar   _defaultQueueing;
365
366 extern void CkPackMessage(envelope **pEnv);
367 extern void CkUnpackMessage(envelope **pEnv);
368
369 class MsgPool: public SafePool<void *> {
370 private:
371     static void *_alloc(void) {
372       /* CkAllocSysMsg() called in .def.h is not thread of sigio safe */
373       register envelope *env = _allocEnv(ForChareMsg,0,0);
374       env->setQueueing(_defaultQueueing);
375       env->setMsgIdx(0);
376       return EnvToUsr(env);
377     }
378 public:
379     MsgPool():SafePool<void*>(_alloc, CkFreeMsg) {}
380 #ifdef _FAULT_MLOG_
381         void *get(void){
382             return allocfn();
383         }
384         void put(void *m){
385         }
386 #endif
387 };
388
389 CkpvExtern(MsgPool*, _msgPool);
390
391 #endif