Used astyle --style=kr formatted source codes.
[charm.git] / src / libs / ck-libs / nodeHelper / 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         redBufs = new void *[maxChunks];
49         bufSpace = new char[maxChunks * CACHE_LINE_SIZE];
50         for (int i=0; i<maxChunks; i++) redBufs[i] = (void *)(bufSpace+i*CACHE_LINE_SIZE);
51     }
52
53     ~CurLoopInfo() {
54         delete [] redBufs;
55         delete [] bufSpace;
56     }
57
58     void set(int nc, HelperFn f, int lIdx, int uIdx, int numParams, void *p) {        /*
59       * WARNING: there's a rare data-racing case here. The current loop is
60       * about to finish (just before setting inited to 0; A helper (say B)
61       * just enters the stealWork and passes the inited check. The helper
62       * (say A) is very fast, and starts the next loop, and happens enter
63       * into the middle of this function. Then helper B will face corrupted
64       * task info as it is trying to execute the old loop task!
65       * In reality for user cases, this case happens very rarely!! -Chao Mei
66       */
67         numChunks = nc;
68         fnPtr = f;
69         lowerIndex = lIdx;
70         upperIndex = uIdx;
71         paramNum = numParams;
72         param = p;
73         curChunkIdx = -1;
74         finishFlag = 0;
75         //needs to be set last
76         inited = 1;
77     }
78
79     void waitLoopDone(int sync) {
80         //while(!__sync_bool_compare_and_swap(&finishFlag, numChunks, 0));
81         if (sync) while (finishFlag!=numChunks);
82         //finishFlag = 0;
83         inited = 0;
84     }
85     int getNextChunkIdx() {
86         return __sync_add_and_fetch(&curChunkIdx, 1);
87     }
88     void reportFinished(int counter) {
89         if (counter==0) return;
90         __sync_add_and_fetch(&finishFlag, counter);
91     }
92
93     int isFree() {
94         return finishFlag == numChunks;
95     }
96
97     void **getRedBufs() {
98         return redBufs;
99     }
100
101     void stealWork();
102 };
103
104 /* FuncNodeHelper is a nodegroup object */
105
106 typedef struct converseNotifyMsg {
107     char core[CmiMsgHeaderSizeBytes];
108     int srcRank;
109     void *ptr;
110 } ConverseNotifyMsg;
111
112 class CharmNotifyMsg: public CMessage_CharmNotifyMsg {
113 public:
114     int srcRank;
115     void *ptr; //the loop info
116 };
117
118 class FuncNodeHelper : public CBase_FuncNodeHelper {
119     friend class FuncSingleHelper;
120
121 public:
122     static int MAX_CHUNKS;
123 private:
124     int mode;
125
126     int numHelpers; //in pthread mode, the counter includes itself
127     FuncSingleHelper **helperPtr; /* ptrs to the FuncSingleHelpers it manages */
128     int useTreeBcast;
129
130 public:
131     FuncNodeHelper(int mode_, int numThreads_);
132     ~FuncNodeHelper() {
133         delete [] helperPtr;
134     }
135
136     void createPThreads();
137     void exit();
138
139     int getNumHelpers() {
140         return numHelpers;
141     }
142     int needTreeBcast() {
143         return useTreeBcast;
144     }
145
146     void parallelizeFunc(HelperFn func, /* the function that finishes a partial work on another thread */
147                          int paramNum, void * param, /* the input parameters for the above func */
148                          int numChunks, /* number of chunks to be partitioned */
149                          int lowerRange, int upperRange, /* the loop-like parallelization happens in [lowerRange, upperRange] */
150                          int sync=1, /* whether the flow will continue until all chunks have finished */
151                          void *redResult=NULL, REDUCTION_TYPE type=NODEHELPER_NONE /* the reduction result, ONLY SUPPORT SINGLE VAR of TYPE int/float/double */
152                         );
153     void reduce(void **redBufs, void *redBuf, REDUCTION_TYPE type, int numChunks);
154 };
155
156 void SingleHelperStealWork(ConverseNotifyMsg *msg);
157
158 /* FuncSingleHelper is a chare located on every core of a node */
159 //allowing arbitrary combination of sync and unsync parallelizd loops
160 #define TASK_BUFFER_SIZE (3)
161 class FuncSingleHelper: public CBase_FuncSingleHelper {
162     friend class FuncNodeHelper;
163 private:
164     int totalHelpers;
165     int notifyMsgBufSize;
166
167     FuncNodeHelper *thisNodeHelper;
168 #if USE_CONVERSE_NOTIFICATION
169     //this msg is shared across all SingleHelpers
170     ConverseNotifyMsg *notifyMsg;
171 #else
172     //acted as a msg buffer for charm-level notification msgs sent to other
173     //SingleHelpers. At each sending,
174     //1. the msg destination chare (SingleHelper) has to be set.
175     //2. the associated loop info has to be set.
176     CharmNotifyMsg **notifyMsg;
177     CurLoopInfo **taskBuffer;
178     int nextFreeTaskBuffer;
179 #endif
180     int nextFreeNotifyMsg;
181
182 public:
183     FuncSingleHelper(int numHelpers);
184
185     ~FuncSingleHelper() {
186 #if USE_CONVERSE_NOTIFICATION
187         for (int i=0; i<notifyMsgBufSize; i++) {
188             ConverseNotifyMsg *tmp = notifyMsg+i;
189             CurLoopInfo *loop = (CurLoopInfo *)(tmp->ptr);
190             delete loop;
191         }
192         free(notifyMsg);
193 #else
194         for (int i=0; i<notifyMsgBufSize; i++) delete notifyMsg[i];
195         free(notifyMsg);
196         for (int i=0; i<TASK_BUFFER_SIZE; i++) delete taskBuffer[i];
197         free(taskBuffer);
198 #endif
199     }
200 #if USE_CONVERSE_NOTIFICATION
201     ConverseNotifyMsg *getNotifyMsg() {
202         while (1) {
203             ConverseNotifyMsg *cur = notifyMsg+nextFreeNotifyMsg;
204             CurLoopInfo *loop = (CurLoopInfo *)(cur->ptr);
205             nextFreeNotifyMsg = (nextFreeNotifyMsg+1)%notifyMsgBufSize;
206             if (loop->isFree()) return cur;
207         }
208         return NULL;
209     }
210 #else
211     CharmNotifyMsg *getNotifyMsg() {
212         while (1) {
213             CharmNotifyMsg *cur = notifyMsg[nextFreeNotifyMsg];
214             CurLoopInfo *loop = (CurLoopInfo *)(cur->ptr);
215             nextFreeNotifyMsg = (nextFreeNotifyMsg+1)%notifyMsgBufSize;
216             if (loop==NULL || loop->isFree()) return cur;
217         }
218         return NULL;
219     }
220     CurLoopInfo *getNewTask() {
221         while (1) {
222             CurLoopInfo *cur = taskBuffer[nextFreeTaskBuffer];
223             nextFreeTaskBuffer = (nextFreeTaskBuffer+1)%TASK_BUFFER_SIZE;
224             if (cur->isFree()) return cur;
225         }
226         return NULL;
227     }
228 #endif
229
230     void stealWork(CharmNotifyMsg *msg);
231
232     FuncSingleHelper(CkMigrateMessage *m) {}
233 };
234
235 #endif