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