62d7fa9c06feff155b182fc9a4c27606214d65a3
[charm.git] / src / langs / bluegene / blue_impl.h
1 #ifndef BLUE_IMPL_H
2 #define BLUE_IMPL_H
3
4 #include "conv-mach.h"
5 #include <stdlib.h>
6
7 #include "ckliststring.h"
8
9 #include "blue_types.h"
10 #include "bigsim_timing.h"
11 #include "bigsim_network.h"
12
13 /* alway use handler table per node */
14 #if ! defined(CMK_BLUEGENE_NODE) && ! defined(CMK_BLUEGENE_THREAD)
15 #define CMK_BLUEGENE_THREAD   1
16 #endif
17
18 /* define system parameters */
19 #define INBUFFER_SIZE   32
20
21 /* end of system parameters */
22
23 #define MAX_HANDLERS    100
24
25 class BGMach {
26 public:
27   int x, y, z;             /* size of bluegene nodes in cube */
28   int numCth, numWth;      /* number of threads */
29   int stacksize;           /* bg thread stack size */
30   int timingMethod;        /* timing method */
31   double cpufactor;        /* cpu factor to multiply to the time for walltime */
32   double fpfactor;         /* fp time factor */
33   double timercost;        /* cost of timer */
34   int    record, recordnode, replay, replaynode;   /* record/replay */
35   CkListString recordprocs;
36   CkListString recordnodes;
37   char *traceroot;         /* bgTraceFile prefix */
38   BigSimNetwork *network;  /* network setup */
39   CkListString procList;   /* a list of processor numbers with projections */
40 public:
41   BGMach() {  nullify(); }
42   ~BGMach() { if (network) delete network; }
43   void nullify() { 
44         x=y=z=0; 
45         numCth=numWth=1; stacksize=0; 
46         record=recordnode=replay=replaynode=-1;
47         timingMethod = BG_WALLTIME; cpufactor=1.0; fpfactor=0.0;
48         traceroot=NULL; 
49         network=new BlueGeneNetwork;
50         timercost = 0.0;
51   }
52   void setSize(int xx, int yy, int zz) 
53         { x=xx; y=yy; z=zz; }
54   void getSize(int *xx, int *yy, int *zz) 
55         { *xx=x; *yy=y; *zz=z; }
56   int numTh()
57         { return numCth + numWth; }
58   int getNodeSize()  { return x*y*z; }
59   int isWorkThread(int tid) { return tid>=0 && tid<numWth; }
60   int read(char *file);
61   void pup(PUP::er &p) { 
62         p|x; p|y; p|z; p|numCth; p|numWth; 
63         p|stacksize; p|timingMethod; 
64        }
65   int traceProejctions(int pe);
66   void setNetworkModel(char *model);
67   int inReplayMode() { return replay != -1 || replaynode != -1; }
68 };
69
70 // simulation state
71 // one copy per host machine processor  (Cpv)
72 class SimState {
73 public:
74   // converse handlers
75   int msgHandler;
76   int nBcastMsgHandler;
77   int tBcastMsgHandler;
78   int exitHandler;
79   int beginExitHandler;
80   int bgStatCollectHandler;
81   // state variables
82   int inEmulatorInit;
83   // simulation start timer
84   double simStartTime;
85 };
86
87 CpvExtern(BGMach, bgMach);      /* BG machine size */
88 CpvExtern(SimState, simState);  /* simulation state variables */
89 CpvExtern(int, numNodes);       /* number of bg nodes on this PE */
90
91 typedef char ThreadType;
92 const char UNKNOWN_THREAD=0, COMM_THREAD=1, WORK_THREAD=2;
93
94 typedef bgQueue<int>        threadIDQueue;
95 typedef bgQueue<CthThread>  threadQueue;
96 typedef bgQueue<char *>     msgQueue;
97 //typedef CkQ<char *>       ckMsgQueue;
98 // use a queue sorted by recv time
99 typedef minMsgHeap          ckMsgQueue;
100 typedef CkQ<bgCorrectionMsg *>      bgCorrectionQ;
101 //typedef minHeap<bgCorrectionMsg *>        bgCorrectionQ;
102
103 /**
104   definition of Handler Table;
105   there are two kinds of handle tables: 
106   one is node level, the other is at thread level
107 */
108 class HandlerTable {
109 public:
110   int          handlerTableCount; 
111   BgHandlerInfo *  handlerTable;     
112 public:
113   HandlerTable();
114   inline int registerHandler(BgHandler h);
115   inline void numberHandler(int idx, BgHandler h);
116   inline void numberHandlerEx(int idx, BgHandlerEx h, void *userPtr);
117   inline BgHandlerInfo* getHandle(int handler);
118 #if 0
119   HandlerTable()
120   {
121     handlerTableCount = 1;
122     handlerTable = (BgHandler *)malloc(MAX_HANDLERS * sizeof(BgHandler));
123     for (int i=0; i<MAX_HANDLERS; i++) handlerTable[i] = defaultBgHandler;
124   }
125   inline int registerHandler(BgHandler h)
126   {
127     ASSERT(!cva(inEmulatorInit));
128     /* leave 0 as blank, so it can report error luckily */
129     int cur = handlerTableCount++;
130     if (cur >= MAX_HANDLERS)
131       CmiAbort("BG> HandlerID exceed the maximum.\n");
132     handlerTable[cur] = h;
133     return cur;
134   }
135   inline void numberHandler(int idx, BgHandler h)
136   {
137     ASSERT(!cva(inEmulatorInit));
138     if (idx >= handlerTableCount || idx < 1)
139       CmiAbort("BG> HandlerID exceed the maximum!\n");
140     handlerTable[idx] = h;
141   }
142   inline BgHandlerInfo getHandle(int handler)
143   {
144 #if 0
145     if (handler >= handlerTableCount) {
146       CmiPrintf("[%d] handler: %d handlerTableCount:%d. \n", tMYNODEID, handler, handlerTableCount);
147       CmiAbort("Invalid handler!");
148     }
149 #endif
150     if (handler >= handlerTableCount) return NULL;
151     return handlerTable[handler];
152   }
153 #endif
154 };
155
156
157 #define cva CpvAccess
158 #define cta CtvAccess
159
160 class threadInfo;
161 CtvExtern(threadInfo *, threadinfo); 
162 class nodeInfo;
163 CpvExtern(nodeInfo *, nodeinfo); 
164 extern double (*timerFunc) (void);
165
166 #define tMYID           cta(threadinfo)->id
167 #define tMYGLOBALID     cta(threadinfo)->globalId
168 #define tTHREADTYPE     cta(threadinfo)->type
169 #define tMYNODE         cta(threadinfo)->myNode
170 #define tSTARTTIME      tMYNODE->startTime
171 #define tTIMERON        tMYNODE->timeron_flag
172 #define tCURRTIME       cta(threadinfo)->currTime
173 #define tHANDLETAB      cta(threadinfo)->handlerTable
174 #define tHANDLETABFNPTR cta(threadinfo)->handlerTable.fnPtr
175 #define tHANDLETABUSERPTR       cta(threadinfo)->handlerTable.userPtr
176 #define tMYX            tMYNODE->x
177 #define tMYY            tMYNODE->y
178 #define tMYZ            tMYNODE->z
179 #define tMYNODEID       tMYNODE->id
180 #define tTIMELINEREC    tMYNODE->timelines[tMYID]
181 #define tTIMELINE       tMYNODE->timelines[tMYID].timeline
182 #define tINBUFFER       tMYNODE->inBuffer
183 #define tUSERDATA       tMYNODE->udata
184 #define tTHREADTABLE    tMYNODE->threadTable
185 #define tSTARTED        tMYNODE->started
186
187 extern int _bgSize;
188
189 /*****************************************************************************
190    used internally, define BG Node to real Processor mapping
191 *****************************************************************************/
192
193 class BlockMapInfo {
194 public:
195   /* return the number of bg nodes on this physical emulator PE */
196   inline static int numLocalNodes()
197   {
198     int n, m;
199     n = _bgSize / CmiNumPes();
200     m = _bgSize % CmiNumPes();
201     if (CmiMyPe() < m) n++;
202     return n;
203   }
204
205     /* map global serial number to (x,y,z) ++++ */
206   inline static void Global2XYZ(int seq, int *x, int *y, int *z) {
207     /** OLD SCHEME:
208     *x = seq / (cva(bgMach).y * cva(bgMach).z);
209     *y = (seq - *x * cva(bgMach).y * cva(bgMach).z) / cva(bgMach).z;
210     *z = (seq - *x * cva(bgMach).y * cva(bgMach).z) % cva(bgMach).z; */
211
212     /* assumed TXYZ */
213     *x = seq % cva(bgMach).x;
214     *y = (seq % (cva(bgMach).x * cva(bgMach).y)) / cva(bgMach).x;
215     *z = seq / (cva(bgMach).x * cva(bgMach).y);
216   }
217
218
219     /* calculate global serial number of (x,y,z) ++++ */
220   inline static int XYZ2Global(int x, int y, int z) {
221     /** OLD SCHEME:
222     return x*(cva(bgMach).y * cva(bgMach).z) + y*cva(bgMach).z + z; */
223
224     /* assumed TXYZ */
225     return x + y*cva(bgMach).x + z*(cva(bgMach).x * cva(bgMach).y);
226   }
227
228     /* map (x,y,z) to emulator PE ++++ */
229   inline static int XYZ2RealPE(int x, int y, int z) {
230     return Global2PE(XYZ2Global(x,y,z));
231   }
232
233   inline static int XYZ2Local(int x, int y, int z) {
234     return Global2Local(XYZ2Global(x,y,z));
235   }
236
237     /* local node index number to x y z ++++ */
238   inline static void Local2XYZ(int num, int *x, int *y, int *z)  {
239     Global2XYZ(Local2Global(num), x, y, z);
240   }
241
242 #define NOT_FAST_CODE 1
243     /* map global serial node number to real PE ++++ */
244   inline static int Global2PE(int num) { 
245 #if NOT_FAST_CODE
246     int n = _bgSize/CmiNumPes();
247     int bn = _bgSize%CmiNumPes();
248     int start = 0; 
249     int end = 0;
250     for (int i=0; i< CmiNumPes(); i++) {
251       end = start + n-1;
252       if (i<bn) end++;
253       if (num >= start && num <= end) return i;
254       start = end+1;
255     }
256     CmiAbort("Global2PE: unknown pe!");
257     return -1;
258 #else
259    int avgNs = _bgSize/CmiNumPes();
260    int remains = _bgSize%CmiNumPes();
261    /*
262     * the bg nodes are mapped like the following:
263     * avgNs+1, avgNs+1, ..., avgNs+1 (of remains proccessors)
264     * avgNs, ..., avgNs (of CmiNumPes()-remains processors)
265     */
266
267    int middleCnt = (avgNs+1)*remains;
268    if(num < middleCnt){
269       //in the first part of emulating processors
270       int ret = num/(avgNs+1);
271    #if CMK_ERROR_CHECKING
272       if(ret<0){
273           CmiAbort("Global2PE: unknown pe!");
274           return -1;
275       }
276    #endif
277       return ret;
278    }else{
279       //in the second part of emulating processors
280       int ret = (num-middleCnt)/avgNs+remains;
281    #if CMK_ERROR_CHECKING
282       if(ret>=CmiNumPes()){
283           CmiAbort("Global2PE: unknown pe!");
284           return -1;
285       }
286    #endif
287       return ret;
288    }
289 #endif
290   }
291
292     /* map global serial node ID to local node array index  ++++ */
293   inline static int Global2Local(int num) { 
294     int n = _bgSize/CmiNumPes();
295     int bn = _bgSize%CmiNumPes();
296     int start = 0; 
297     int end = 0;
298     for (int i=0; i< CmiNumPes(); i++) {
299       end = start + n-1;
300       if (i<bn) end++;
301       if (num >= start && num <= end) return num-start;
302       start = end+1;
303     }
304     CmiAbort("Global2Local:unknown pe!");
305     return -1;
306   }
307
308     /* map local node index to global serial node id ++++ */
309   inline static int Local2Global(int num) { 
310     int n = _bgSize/CmiNumPes();
311     int bn = _bgSize%CmiNumPes();
312     int start = 0; 
313     int end = 0;
314     for (int i=0; i< CmiMyPe(); i++) {
315       end = start + n-1;
316       if (i<bn) end++;
317       start = end+1;
318     }
319     return start+num;
320   }
321
322   inline static int FileOffset(int pe, int numWth, int numEmulatingPes, int totalWorkerProcs, int &fileNum, int &offset) {
323     fileNum = offset = -1;
324     return -1;                   /* fix me */
325   }
326 };
327
328 class CyclicMapInfo {
329 public:
330   /* return the number of bg nodes on this physical emulator PE */
331   inline static int numLocalNodes()
332   {
333     int n, m;
334     n = _bgSize / CmiNumPes();
335     m = _bgSize % CmiNumPes();
336     if (CmiMyPe() < m) n++;
337     return n;
338   }
339
340     /* map global serial node number to (x,y,z) ++++ */
341   inline static void Global2XYZ(int seq, int *x, int *y, int *z) {
342     /** OLD SCHEME:
343     *x = seq / (cva(bgMach).y * cva(bgMach).z);
344     *y = (seq - *x * cva(bgMach).y * cva(bgMach).z) / cva(bgMach).z;
345     *z = (seq - *x * cva(bgMach).y * cva(bgMach).z) % cva(bgMach).z; */
346
347     /* assumed TXYZ */
348     *x = seq % cva(bgMach).x;
349     *y = (seq % (cva(bgMach).x * cva(bgMach).y)) / cva(bgMach).x;
350     *z = seq / (cva(bgMach).x * cva(bgMach).y);
351   }
352
353
354     /* calculate global serial number of (x,y,z) ++++ */
355   inline static int XYZ2Global(int x, int y, int z) {
356     /** OLD SCHEME:
357     return x*(cva(bgMach).y * cva(bgMach).z) + y*cva(bgMach).z + z; */
358
359     /* assumed TXYZ */
360     return x + y*cva(bgMach).x + z*(cva(bgMach).x * cva(bgMach).y);
361   }
362
363     /* map (x,y,z) to emulator PE ++++ */
364   inline static int XYZ2RealPE(int x, int y, int z) {
365     return Global2PE(XYZ2Global(x,y,z));
366   }
367
368   inline static int XYZ2Local(int x, int y, int z) {
369     return Global2Local(XYZ2Global(x,y,z));
370   }
371
372     /* local node index number to x y z ++++ */
373   inline static void Local2XYZ(int num, int *x, int *y, int *z)  {
374     Global2XYZ(Local2Global(num), x, y, z);
375   }
376
377     /* map global serial node number to PE ++++ */
378   inline static int Global2PE(int num) { return num % CmiNumPes(); }
379
380     /* map global serial node ID to local node array index  ++++ */
381   inline static int Global2Local(int num) { return num/CmiNumPes(); }
382
383     /* map local node index to global serial node id ++++ */
384   inline static int Local2Global(int num) { return CmiMyPe()+num*CmiNumPes();}
385
386     /* timeline for each worker thread is dump to a bgTrace file.
387        All nodes on a emulating processor is dumped to a single file
388        this function identify the sequence number of a given PE. 
389     */
390   inline static int FileOffset(int pe, int numWth, int numEmulatingPes, int totalWorkerProcs, int &fileNum, int &offset) {
391     int nodeNum = pe/numWth;
392     int numNodes = totalWorkerProcs/numWth;
393     fileNum = nodeNum%numEmulatingPes;
394     offset=0;
395
396     for(int i=0;i<fileNum;i++)
397       offset += (numNodes/numEmulatingPes + ((i < numNodes%numEmulatingPes)?1:0))*numWth;
398
399     offset += (nodeNum/numEmulatingPes)*numWth + pe%numWth;
400     return 1;
401   }
402 };
403
404
405 /*****************************************************************************
406       NodeInfo:
407         including a group of functions defining the mapping, terms used here:
408         XYZ: (x,y,z)
409         Global:  map (x,y,z) to a global serial number
410         Local:   local index of this nodeinfo in the emulator's node 
411 *****************************************************************************/
412 class nodeInfo: public CyclicMapInfo  {
413 public:
414   int id;
415   int x,y,z;
416   msgQueue     inBuffer;        /* emulate the fix-size inbuffer */
417   CmmTable     msgBuffer;       /* buffer when inBuffer is full */
418   CthThread   *threadTable;     /* thread table for both work and comm threads*/
419   threadInfo  **threadinfo;
420   threadQueue *commThQ;         /* suspended comm threads queue */
421   ckMsgQueue   nodeQ;           /* non-affinity msg queue */
422   ckMsgQueue  *affinityQ;       /* affinity msg queue for each work thread */
423   double       startTime;       /* start time for a thread */
424   double       nodeTime;        /* node time to coordinate thread times */
425   short        lastW;           /* last worker thread assigned msg */
426   char         started;         /* flag indicate if this node is started */
427   char        *udata;           /* node specific data pointer */
428   char         timeron_flag;    /* true if timer started */
429  
430   HandlerTable handlerTable; /* node level handler table */
431 #if BLUEGENE_TIMING
432   // for timing
433   BgTimeLineRec *timelines;
434   bgCorrectionQ cmsg;
435 #endif
436 public:
437   nodeInfo();
438   void initThreads(int _id);            /* init threads */
439   ~nodeInfo();
440   /**
441    *  add a message to this bluegene node's inbuffer queue
442    */
443   void addBgNodeInbuffer(char *msgPtr);
444   /**
445    *  add a message to this bluegene node's non-affinity queue
446    */
447   void addBgNodeMessage(char *msgPtr);
448   /**
449    *  called by comm thread to poll inBuffer
450    */
451   char * getFullBuffer();
452 };      // end of nodeInfo
453
454 /*****************************************************************************
455       ThreadInfo:  each thread has a thread private threadInfo structure.
456       It has a local id, a global serial id. 
457       myNode: point to the nodeInfo it belongs to.
458       currTime: is the elapse time for this thread;
459       me:   point to the CthThread converse thread handler.
460 *****************************************************************************/
461
462 class BgMessageWatcher;
463
464 class threadInfo {
465 public:
466   short id;
467   int globalId;
468   ThreadType  type;             /* worker or communication thread */
469   CthThread me;                 /* Converse thread handler */
470   nodeInfo *myNode;             /* the node belonged to */
471   double  currTime;             /* thread timer */
472
473   BgMessageWatcher *watcher;
474   int     cth_serialNo;         /* for record/replay */
475
476   /*
477    * It is needed for out-of-core scheduling
478    * If it is set to 0, then we know its core file is not on disk
479    * and it is first time for this thread to process a msg
480    * thus no need to bring it into memory.
481    * It is initialized to be 0;
482    * It is should be set to 1 when it is taken out of memory to disk
483    * and set to 0 when it is brought into memory
484    */
485     int isCoreOnDisk;
486     
487     double memUsed;            /* thread's memory footprint (unit is MB) */ 
488    
489     //Used for AMPI programs
490     int startOutOfCore;
491     int startOOCChanged;
492
493 #if BIGSIM_OUT_OF_CORE && BIGSIM_OOC_PREFETCH
494     //the index into the global array (thdsOOCPreStatus) that records
495     //the prefetch status of each worker thread
496     int preStsIdx;
497 #endif
498
499 #if  CMK_BLUEGENE_THREAD
500   HandlerTable   handlerTable;      /* thread level handler table */
501 #endif
502
503 public:
504   threadInfo(int _id, ThreadType _type, nodeInfo *_node): 
505         id(_id), globalId(-1), type(_type), myNode(_node), currTime(0.0), 
506         watcher(NULL), cth_serialNo(2),
507         isCoreOnDisk(0), memUsed(0.0),
508         startOutOfCore(1), startOOCChanged(0){}
509   inline void setThread(CthThread t) { me = t; }
510   inline CthThread getThread() const { return me; }
511   virtual void run() { CmiAbort("run not imlplemented"); }
512
513   //=====Begin of stuff related with out-of-core scheduling===========
514   void broughtIntoMem();
515   void takenOutofMem();
516   //=====End of stuff related with out-of-core scheduling=============
517
518
519 }; 
520
521 class workThreadInfo : public threadInfo {
522 private:
523   int CsdStopFlag;
524 public:
525   void* reduceMsg;
526   
527   workThreadInfo(int _id, nodeInfo *_node): 
528         threadInfo(_id, WORK_THREAD, _node), reduceMsg(NULL) { 
529     CsdStopFlag=0; 
530     watcher = NULL;
531     if (_id != -1) {
532       globalId = nodeInfo::Local2Global(_node->id)*(cva(bgMach).numWth)+_id;
533     }
534 #if BIGSIM_OUT_OF_CORE && BIGSIM_OOC_PREFETCH
535     preStsIdx = _node->id * cva(bgMach).numWth + _id;
536 #endif
537   }
538   void addAffMessage(char *msgPtr);        ///  add msg to affinity queue
539   void run();
540   void scheduler(int count);
541   void stopScheduler() { CsdStopFlag++; }
542 };
543
544 class commThreadInfo : public threadInfo {
545 public:
546   commThreadInfo(int _id, nodeInfo *_node): 
547      threadInfo(_id, COMM_THREAD, _node) {}
548   void run();
549 };
550
551 // functions
552
553 double BgGetCurTime();
554 char ** BgGetArgv();
555 int     BgGetArgc();
556 void    startVTimer();
557 void    stopVTimer();
558 void    resetVTime();
559
560 char * getFullBuffer();
561 void   addBgNodeMessage(char *msgPtr);
562 void   addBgThreadMessage(char *msgPtr, int threadID);
563 void   BgProcessMessageDefault(threadInfo *t, char *msg);
564 extern void (*BgProcessMessage)(threadInfo *t, char *msg);
565
566
567 /* blue gene debug */
568
569 #define BLUEGENE_DEBUG 0
570
571 #if BLUEGENE_DEBUG
572 /**Controls amount of debug messages: 1 (the lowest priority) is 
573 extremely verbose, 2 shows most procedure entrance/exits, 
574 3 shows most communication, and 5 only shows rare or unexpected items.
575 Displaying lower priority messages doesn't stop higher priority ones.
576 */
577 #define BLUEGENE_DEBUG_PRIO 2
578 #define BLUEGENE_DEBUG_LOG 1 /**Controls whether output goes to log file*/
579
580 extern FILE *bgDebugLog;
581 # define BGSTATE_I(prio,args) if ((prio)>=BLUEGENE_DEBUG_PRIO) {\
582         fprintf args ; fflush(bgDebugLog); }
583 # define BGSTATE(prio,str) \
584         BGSTATE_I(prio,(bgDebugLog,"[%.3f]> "str"\n",CmiWallTimer()))
585 # define BGSTATE1(prio,str,a) \
586         BGSTATE_I(prio,(bgDebugLog,"[%.3f]> "str"\n",CmiWallTimer(),a))
587 # define BGSTATE2(prio,str,a,b) \
588         BGSTATE_I(prio,(bgDebugLog,"[%.3f]> "str"\n",CmiWallTimer(),a,b))
589 # define BGSTATE3(prio,str,a,b,c) \
590         BGSTATE_I(prio,(bgDebugLog,"[%.3f]> "str"\n",CmiWallTimer(),a,b,c))
591 # define BGSTATE4(prio,str,a,b,c,d) \
592         BGSTATE_I(prio,(bgDebugLog,"[%.3f]> "str"\n",CmiWallTimer(),a,b,c,d))
593 #else
594 # define BLUEGENE_DEBUG_LOG 0
595 # define BGSTATE(n,x) /*empty*/
596 # define BGSTATE1(n,x,a) /*empty*/
597 # define BGSTATE2(n,x,a,b) /*empty*/
598 # define BGSTATE3(n,x,a,b,c) /*empty*/
599 # define BGSTATE4(n,x,a,b,c,d) /*empty*/
600 #endif
601
602 #endif