1. added output if using charm-level notification
[charm.git] / NodeHelper.h
1 #ifndef _NODEHELPER_H
2 #define _NODEHELPER_H
3 #include <assert.h>
4
5 #include "charm++.h"
6 #include "NodeHelperAPI.h"
7
8 #define USE_TREE_BROADCAST_THRESHOLD 8
9 #define TREE_BCAST_BRANCH (4)
10 #define CACHE_LINE_SIZE 64
11 /* 1. Using converse-level msg, then the msg is always of highest priority.
12  * And the notification msg comes from the singlehelper where the loop parallelization
13  * is initiated.
14  * 
15  * 2. Using charm-level msg, then the msg could be set with different priorities.
16  * However, the notification msg comes from the singlehelper where the parallelized
17  * loop is executed.
18  * 
19  * */
20 #define USE_CONVERSE_NOTIFICATION 1
21
22 class FuncSingleHelper;
23
24 class CurLoopInfo{
25     friend class FuncSingleHelper;
26     
27 private:
28     volatile int curChunkIdx;
29     int numChunks;
30     HelperFn fnPtr;
31     int lowerIndex;
32     int upperIndex;
33     int paramNum;
34     void *param;
35     //limitation: only allow single variable reduction of size numChunks!!!
36     void **redBufs;
37         char *bufSpace;
38
39     volatile int finishFlag;
40     
41     //a tag to indicate whether the task for this new loop has been inited
42     //this tag is needed to prevent other helpers to run the old task
43     int inited;
44     
45 public:    
46     CurLoopInfo(int maxChunks):numChunks(0),fnPtr(NULL), lowerIndex(-1), upperIndex(0), 
47     paramNum(0), param(NULL), curChunkIdx(-1), finishFlag(0), redBufs(NULL), bufSpace(NULL), inited(0) 
48         {
49                 redBufs = new void *[maxChunks];
50                 bufSpace = new char[maxChunks * CACHE_LINE_SIZE];
51         for(int i=0; i<maxChunks; i++) redBufs[i] = (void *)(bufSpace+i*CACHE_LINE_SIZE);
52         }
53     
54     ~CurLoopInfo() { 
55                 delete [] redBufs; 
56                 delete [] bufSpace;
57         }
58     
59     void set(int nc, HelperFn f, int lIdx, int uIdx, int numParams, void *p){        /*
60       * WARNING: there's a rare data-racing case here. The current loop is
61       * about to finish (just before setting inited to 0; A helper (say B) 
62       * just enters the stealWork and passes the inited check. The helper 
63       * (say A) is very fast, and starts the next loop, and happens enter
64       * into the middle of this function. Then helper B will face corrupted
65       * task info as it is trying to execute the old loop task!
66       * In reality for user cases, this case happens very rarely!! -Chao Mei
67       */
68         numChunks = nc;
69         fnPtr = f;
70         lowerIndex = lIdx;
71         upperIndex = uIdx;
72         paramNum = numParams;
73         param = p;
74         curChunkIdx = -1;
75         finishFlag = 0;
76         //needs to be set last
77         inited = 1;
78     }
79       
80     void waitLoopDone(int sync){
81         //while(!__sync_bool_compare_and_swap(&finishFlag, numChunks, 0));
82         if(sync) while(finishFlag!=numChunks);
83         //finishFlag = 0;
84         inited = 0;
85     }
86     int getNextChunkIdx(){
87         return __sync_add_and_fetch(&curChunkIdx, 1);
88     }
89     void reportFinished(int counter){
90         if(counter==0) return;
91         __sync_add_and_fetch(&finishFlag, counter);
92     }
93     
94     int isFree() { return finishFlag == numChunks; }
95     
96         void **getRedBufs() { return redBufs; }
97         
98     void stealWork();
99 };
100
101 /* FuncNodeHelper is a nodegroup object */
102
103 typedef struct converseNotifyMsg{
104     char core[CmiMsgHeaderSizeBytes];
105     int srcRank;
106     void *ptr;
107 }ConverseNotifyMsg;
108
109 class CharmNotifyMsg: public CMessage_CharmNotifyMsg{
110 public:
111     int srcRank;
112     void *ptr; //the loop info
113 };
114
115 class FuncNodeHelper : public CBase_FuncNodeHelper {
116     friend class FuncSingleHelper;
117         
118 public:
119     static int MAX_CHUNKS;
120 private:
121     int mode;
122         
123     int numHelpers; //in pthread mode, the counter includes itself    
124     FuncSingleHelper **helperPtr; /* ptrs to the FuncSingleHelpers it manages */
125         int useTreeBcast;
126     
127 public:
128         FuncNodeHelper(int mode_, int numThreads_);
129     ~FuncNodeHelper() {
130         delete [] helperPtr;
131     }
132         
133         void createPThreads();
134         void exit();
135         
136         int getNumHelpers() { return numHelpers; }
137         int needTreeBcast() { return useTreeBcast; }
138     
139     void parallelizeFunc(HelperFn func, /* the function that finishes a partial work on another thread */
140                         int paramNum, void * param, /* the input parameters for the above func */
141                         int numChunks, /* number of chunks to be partitioned */
142                         int lowerRange, int upperRange, /* the loop-like parallelization happens in [lowerRange, upperRange] */                        
143                         int sync=1, /* whether the flow will continue until all chunks have finished */
144                         void *redResult=NULL, REDUCTION_TYPE type=NODEHELPER_NONE /* the reduction result, ONLY SUPPORT SINGLE VAR of TYPE int/float/double */
145                         );
146     void reduce(void **redBufs, void *redBuf, REDUCTION_TYPE type, int numChunks);
147 };
148
149 void SingleHelperStealWork(ConverseNotifyMsg *msg);
150
151 /* FuncSingleHelper is a chare located on every core of a node */
152 //allowing arbitrary combination of sync and unsync parallelizd loops
153 #define TASK_BUFFER_SIZE (3)
154 class FuncSingleHelper: public CBase_FuncSingleHelper {
155         friend class FuncNodeHelper;
156 private:
157     int totalHelpers;
158     int notifyMsgBufSize;
159     
160     FuncNodeHelper *thisNodeHelper;
161 #if USE_CONVERSE_NOTIFICATION
162     //this msg is shared across all SingleHelpers
163     ConverseNotifyMsg *notifyMsg;
164 #else
165     //acted as a msg buffer for charm-level notification msgs sent to other
166     //SingleHelpers. At each sending, 
167     //1. the msg destination chare (SingleHelper) has to be set.
168     //2. the associated loop info has to be set.
169     CharmNotifyMsg **notifyMsg;
170     CurLoopInfo **taskBuffer;
171     int nextFreeTaskBuffer;
172 #endif
173     int nextFreeNotifyMsg;
174     
175 public:
176     FuncSingleHelper(int numHelpers);
177
178     ~FuncSingleHelper() {
179     #if USE_CONVERSE_NOTIFICATION
180         for(int i=0; i<notifyMsgBufSize; i++){
181             ConverseNotifyMsg *tmp = notifyMsg+i;
182             CurLoopInfo *loop = (CurLoopInfo *)(tmp->ptr);
183             delete loop;
184         }
185         free(notifyMsg);
186     #else
187         for(int i=0; i<notifyMsgBufSize; i++) delete notifyMsg[i];
188         free(notifyMsg);
189         for(int i=0; i<TASK_BUFFER_SIZE; i++) delete taskBuffer[i];
190         free(taskBuffer);
191     #endif
192     }
193 #if USE_CONVERSE_NOTIFICATION    
194     ConverseNotifyMsg *getNotifyMsg(){
195         while(1){
196             ConverseNotifyMsg *cur = notifyMsg+nextFreeNotifyMsg;
197             CurLoopInfo *loop = (CurLoopInfo *)(cur->ptr);
198             nextFreeNotifyMsg = (nextFreeNotifyMsg+1)%notifyMsgBufSize;
199             if(loop->isFree()) return cur;
200         }
201         return NULL;
202     }
203 #else
204     CharmNotifyMsg *getNotifyMsg(){
205         while(1){
206             CharmNotifyMsg *cur = notifyMsg[nextFreeNotifyMsg];
207             CurLoopInfo *loop = (CurLoopInfo *)(cur->ptr);
208             nextFreeNotifyMsg = (nextFreeNotifyMsg+1)%notifyMsgBufSize;
209             if(loop==NULL || loop->isFree()) return cur;
210         }
211         return NULL;
212     }
213     CurLoopInfo *getNewTask(){
214         while(1){
215             CurLoopInfo *cur = taskBuffer[nextFreeTaskBuffer];
216             nextFreeTaskBuffer = (nextFreeTaskBuffer+1)%TASK_BUFFER_SIZE;
217             if(cur->isFree()) return cur;
218         }
219         return NULL;
220     }
221 #endif    
222     
223     void stealWork(CharmNotifyMsg *msg);
224     
225     FuncSingleHelper(CkMigrateMessage *m) {}            
226 };
227
228 #endif