Rename the majority of remaining C files in the RTS to C++
[charm.git] / src / arch / util / machine-broadcast.C
blobe1e3510410facc16b41fefa5ed9770cf49abd7c1
1 /**
2  *        functions for broadcast
3 **/
5 #define CONVERSE_MACHINE_BROADCAST_C_
6 #include "spanningTree.h"
8 CmiCommHandle CmiSendNetworkFunc(int destPE, int size, char *msg, int mode);
10 static void handleOneBcastMsg(int size, char *msg) {
11     CmiAssert(CMI_BROADCAST_ROOT(msg)!=0);
12 #if CMK_OFFLOAD_BCAST_PROCESS
13     if (CMI_BROADCAST_ROOT(msg)>0) {
14         CMIQueuePush(CsvAccess(procBcastQ), msg);
15     } else {
16 #if CMK_NODE_QUEUE_AVAILABLE
17         CMIQueuePush(CsvAccess(nodeBcastQ), msg);
18 #endif
19     }
20 #else
21     if (CMI_BROADCAST_ROOT(msg)>0) {
22         processProcBcastMsg(size, msg);
23     } else {
24 #if CMK_NODE_QUEUE_AVAILABLE
25         processNodeBcastMsg(size, msg);
26 #endif
27     }
28 #endif
31 static void processBcastQs(void) {
32 #if CMK_OFFLOAD_BCAST_PROCESS
33     char *msg;
34     do {
35         msg = CMIQueuePop(CsvAccess(procBcastQ));
36         if (!msg) break;
37         MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p begin{", CmiMyNode(), msg);
38         processProcBcastMsg(CMI_MSG_SIZE(msg), msg);
39         MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p end}", CmiMyNode(), msg);
40     } while (1);
41 #if CMK_NODE_QUEUE_AVAILABLE
42     do {
43         msg = CMIQueuePop(CsvAccess(nodeBcastQ));
44         if (!msg) break;
45         MACHSTATE2(4, "[%d]: process a node-level bcast msg %p begin{", CmiMyNode(), msg);
46         processNodeBcastMsg(CMI_MSG_SIZE(msg), msg);
47         MACHSTATE2(4, "[%d]: process a node-level bcast msg %p end}", CmiMyNode(), msg);
48     } while (1);
49 #endif
50 #endif
53 // Method to forward the received proc message to my child nodes
54 static INLINE_KEYWORD void forwardProcBcastMsg(int size, char *msg) {
55 #if CMK_BROADCAST_SPANNING_TREE
56   SendSpanningChildrenProc(size, msg);
57 #elif CMK_BROADCAST_HYPERCUBE
58   SendHyperCubeProc(size, msg);
59 #endif
60 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
61   /* same message may be sent out, make a copy of it */
62   if (CmiNumNodes()>1 && CmiGetReference(msg)>1) {
63     void *newmsg;
64     newmsg = CopyMsg(msg, size);
65     CmiFree(msg);
66     msg = newmsg;
67   }
68 #endif
71 static INLINE_KEYWORD void processProcBcastMsg(int size, char *msg) {
72     /* Since this function is only called on intermediate nodes,
73      * the rank of this msg should be 0.
74      */
75     CmiAssert(CMI_DEST_RANK(msg)==0);
76     /*CmiPushPE(CMI_DEST_RANK(msg), msg);*/
78     // Forward regular messages, do not forward ncpy bcast messages as those messages
79     // are forwarded separately after the completion of the payload transfer
80 #if CMK_ONESIDED_IMPL
81     if(!CMI_IS_ZC_BCAST(msg))
82 #endif
83       forwardProcBcastMsg(size, msg);
85     CmiPushPE(0, msg);
89 #if CMK_NODE_QUEUE_AVAILABLE
90 // Method to forward the received node message to my child nodes
91 static INLINE_KEYWORD void forwardNodeBcastMsg(int size, char *msg) {
92 #if CMK_BROADCAST_SPANNING_TREE
93   SendSpanningChildrenNode(size, msg);
94 #elif CMK_BROADCAST_HYPERCUBE
95   SendHyperCubeNode(size, msg);
96 #endif
99 // API to forward node bcast msg
100 void CmiForwardNodeBcastMsg(int size, char *msg) {
101   forwardNodeBcastMsg(size, msg);
104 static INLINE_KEYWORD void processNodeBcastMsg(int size, char *msg) {
105     // Forward regular messages, do not forward ncpy bcast messages as those messages
106     // are forwarded separately after the completion of the payload transfer
107 #if CMK_ONESIDED_IMPL
108     if(!CMI_IS_ZC_BCAST(msg))
109 #endif
110       forwardNodeBcastMsg(size, msg);
112     /* In SMP mode, this push operation needs to be executed
113      * after forwarding broadcast messages. If it is executed
114      * earlier, then during the bcast msg forwarding period,
115      * the msg could be already freed on the worker thread.
116      * As a result, the forwarded message could be wrong!
117      * 
118      */
119     CmiPushNode(msg);
121 #endif
123 // API to forward proc bcast msg
124 void CmiForwardProcBcastMsg(int size, char *msg) {
125   forwardProcBcastMsg(size, msg);
128 #if CMK_SMP
129 // API to forward message to peer PEs
130 void CmiForwardMsgToPeers(int size, char *msg) {
131   SendToPeers(size, msg);
133 #endif
135 static void SendSpanningChildren(int size, char *msg, int rankToAssign, int startNode) {
136 #if CMK_BROADCAST_SPANNING_TREE
137     int i, oldRank;
138     char *newmsg;
140     oldRank = CMI_DEST_RANK(msg);
141     /* doing this is to avoid the multiple assignment in the following for loop */
142     CMI_DEST_RANK(msg) = rankToAssign;
143     /* first send msgs to other nodes */
144     CmiAssert(startNode >=0 &&  startNode<CmiNumNodes());
145     if (_topoTree == NULL) {
146       for (i=1; i<=BROADCAST_SPANNING_FACTOR; i++) {
147         int nd = CmiMyNode()-startNode;
148         if (nd<0) nd+=CmiNumNodes();
149         nd = BROADCAST_SPANNING_FACTOR*nd + i;
150         if (nd > CmiNumNodes() - 1) break;
151         nd += startNode;
152         nd = nd%CmiNumNodes();
153         CmiAssert(nd>=0 && nd!=CmiMyNode());
154 #if CMK_BROADCAST_USE_CMIREFERENCE
155         CmiReference(msg);
156         CmiSendNetworkFunc(CmiNodeFirst(nd), size, msg, BCAST_SYNC);
157 #else
158         newmsg = CopyMsg(msg, size);
159         CmiSendNetworkFunc(CmiNodeFirst(nd), size, newmsg, BCAST_SYNC);
160 #endif
161       }
162     } else {
163       int parent, child_count;
164       int *children = NULL;
165       if (startNode == 0) {
166         child_count = _topoTree->child_count;
167         children    = _topoTree->children;
168         //CmiPrintf("[%d][%d] SendSpanningChildren child count%d \n", CmiMyPe(), CmiMyNode(), child_count);
169       } else {
170         get_topo_tree_nbs(startNode, &parent, &child_count, &children);
171       }
172       for (i=0; i < child_count; i++) {
173         int nd = children[i];
174 #if CMK_BROADCAST_USE_CMIREFERENCE
175         CmiReference(msg);
176         CmiSendNetworkFunc(CmiNodeFirst(nd), size, msg, BCAST_SYNC);
177 #else
178         newmsg = CopyMsg(msg, size);
179         //CmiPrintf("[%d][%d] SendSpanningChildren: sending copymsg to %d \n", CmiMyPe(), CmiMyNode(), CmiNodeFirst(nd));
180         CmiSendNetworkFunc(CmiNodeFirst(nd), size, newmsg, BCAST_SYNC);
181 #endif
182       }
183     }
184     CMI_DEST_RANK(msg) = oldRank;
185 #endif
188 static void SendHyperCube(int size,  char *msg, int rankToAssign, int startNode) {
189 #if CMK_BROADCAST_HYPERCUBE
190     int i, cnt, tmp, relDist, oldRank;
191     const int dims=CmiNodesDim;
193     oldRank = CMI_DEST_RANK(msg);
194     /* doing this is to avoid the multiple assignment in the following for loop */
195     CMI_DEST_RANK(msg) = rankToAssign;
197     /* first send msgs to other nodes */
198     relDist = CmiMyNode()-startNode;
199     if (relDist < 0) relDist += CmiNumNodes();
201     /* Sending scheme example: say we have 9 nodes, and the msg is sent from 0
202      * The overall sending steps will be as follows:
203      * 0-->8, 0-->4, 0-->2, 0-->1
204      *               4-->6, 4-->5
205      *                      2-->3
206      *                      6-->7
207      * So for node id as N=A+2^B, it will forward the broadcast (B-1) msg to in
208      * the order as: N+2^(B-1), N+2^(B-2),..., N+1 except node 0, where B is
209      * the first position of bit 1 in the binary format of the number of N
210      * counting from the right with count starting from 0.
211      * On node 0, the value "B" should be CmiNodesDim
212      */
213     /* Calculate 2^B */
214     if(relDist==0) cnt = 1<<dims;
215     else cnt = relDist & ((~relDist)+1);
216     /*CmiPrintf("ND[%d]: send bcast msg with cnt=%d\n", CmiMyNode(), cnt);*/
217     /* Begin to send msgs */
218     for(cnt>>=1; cnt>0; cnt>>=1){
219         int nd = relDist + cnt;
220         char *newmsg;
221         if (nd >= CmiNumNodes()) continue;
222         nd = (nd+startNode)%CmiNumNodes();
223         /*CmiPrintf("ND[%d]: send to node %d\n", CmiMyNode(), nd);*/
224         CmiAssert(nd>=0 && nd!=CmiMyNode());
225 #if CMK_BROADCAST_USE_CMIREFERENCE
226         CmiReference(msg);
227         CmiSendNetworkFunc(CmiNodeFirst(nd), size, msg, BCAST_SYNC);
228 #else
229         newmsg = CopyMsg(msg, size);
230         CmiSendNetworkFunc(CmiNodeFirst(nd), size, newmsg, BCAST_SYNC);
231 #endif
232     }
233     CMI_DEST_RANK(msg) = oldRank;
234 #endif
237 static void SendSpanningChildrenProc(int size, char *msg) {
238     int startnode = CMI_BROADCAST_ROOT(msg)-1;
239     SendSpanningChildren(size, msg, 0, startnode);
240 #if CMK_SMP
241     // Forward regular messages, do not forward ncpy bcast messages as those messages
242     // are forwarded separately after the completion of the payload transfer
243 #if CMK_ONESIDED_IMPL
244     if(!CMI_IS_ZC_BCAST(msg))
245 #endif // end of CMK_ONESIDED_IMPL
246       /* second send msgs to my peers on this node */
247       SendToPeers(size, msg);
248 #endif // end of CMK_SMP
251 /* send msg along the hypercube in broadcast. (Sameer) */
252 static void SendHyperCubeProc(int size, char *msg) {
253     int startpe = CMI_BROADCAST_ROOT(msg)-1;
254     int startnode = CmiNodeOf(startpe);
255 #if CMK_SMP
256     if (startpe > CmiNumPes()) startnode = startpe - CmiNumPes();
257 #endif
258     SendHyperCube(size, msg, 0, startnode);
260 #if CMK_SMP
261     // Forward regular messages, do not forward ncpy bcast messages as those messages
262     // are forwarded separately after the completion of the payload transfer
263 #if CMK_ONESIDED_IMPL
264     if(!CMI_IS_ZC_BCAST(msg))
265 #endif // end of CMK_ONESIDED_IMPL
266       /* second send msgs to my peers on this node */
267       SendToPeers(size, msg);
268 #endif // end of CMK_SMP
271 #if CMK_NODE_QUEUE_AVAILABLE
272 static void SendSpanningChildrenNode(int size, char *msg) {
273     int startnode = -CMI_BROADCAST_ROOT(msg)-1;
274     SendSpanningChildren(size, msg, DGRAM_NODEMESSAGE, startnode);
276 static void SendHyperCubeNode(int size, char *msg) {
277     int startnode = -CMI_BROADCAST_ROOT(msg)-1;
278     SendHyperCube(size, msg, DGRAM_NODEMESSAGE, startnode);
280 #endif
282 #if USE_COMMON_SYNC_BCAST
283 /* Functions regarding broadcat op that sends to every one else except me */
284 void CmiSyncBroadcastFn1(int size, char *msg) {
285     int i, mype;
287 #if CMI_QD
288     CQdCreate(CpvAccess(cQdState), CmiNumPes()-1);
289 #endif
290     /*record the rank to avoid re-sending the msg in  spanning tree or hypercube*/
291     CMI_DEST_RANK(msg) = CmiMyRank();
293 #if CMK_BROADCAST_SPANNING_TREE
294     CMI_SET_BROADCAST_ROOT(msg, CmiMyNode()+1);
295     SendSpanningChildrenProc(size, msg);
296 #elif CMK_BROADCAST_HYPERCUBE
297     CMI_SET_BROADCAST_ROOT(msg, CmiMyNode()+1);
298     SendHyperCubeProc(size, msg);
299 #else
300     mype = CmiMyPe();
301     #if CMK_SMP
302     /* In SMP, this function may be called from comm thread with a larger pe */
303     if(mype >= _Cmi_numpes){
304         for(i=0; i<_Cmi_numpes; i++)
305                 CmiSyncSendFn(i, size, msg);
306         return;
307     }
308     #endif
309         
310     for ( i=mype+1; i<_Cmi_numpes; i++ )
311         CmiSyncSendFn(i, size, msg) ;
312         
313     for ( i=0; i<mype; i++ )
314         CmiSyncSendFn(i, size, msg) ;
315 #endif
317     /*CmiPrintf("In  SyncBroadcast broadcast\n");*/
320 void CmiSyncBroadcastFn(int size, char *msg) {
321     char *newmsg = msg;
322 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
323       /* need to copy the msg in case the msg is on the stack */
324       /* and we only need to copy when sending out network */
325     if (CmiNumNodes()>1) newmsg = CopyMsg(msg, size);
326 #endif
327     CmiSyncBroadcastFn1(size, newmsg);
328 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
329     if (newmsg != msg) CmiFree(newmsg);
330 #endif
333 void CmiFreeBroadcastFn(int size, char *msg) {
334     CmiSyncBroadcastFn1(size,msg);
335     CmiFree(msg);
337 #else
338 #define  CmiSyncBroadcastFn1(s,m)      CmiSyncBroadcastFn(s,m)
339 #endif
341 #if USE_COMMON_ASYNC_BCAST
342 /* FIXME: should use spanning or hypercube, but luckily async is never used */
343 CmiCommHandle CmiAsyncBroadcastFn(int size, char *msg) {
344     /*CmiPrintf("In  AsyncBroadcast broadcast\n");*/
345     CmiAbort("CmiAsyncBroadcastFn should never be called");
346     return 0;
348 #endif
350 /* Functions regarding broadcat op that sends to every one */
351 void CmiSyncBroadcastAllFn(int size, char *msg) {
352     char *newmsg = msg;
353 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
354       /* need to copy the msg in case the msg is on the stack */
355       /* and we only need to copy when sending out network */
356     if (CmiNumNodes()>1) newmsg = CopyMsg(msg, size);
357 #endif
358     CmiSyncSendFn(CmiMyPe(), size, newmsg) ;
359     CmiSyncBroadcastFn1(size, newmsg);
360 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
361     if (newmsg != msg) CmiFree(newmsg);
362 #endif
365 void CmiFreeBroadcastAllFn(int size, char *msg) {
366     CmiSyncBroadcastFn1(size, msg);
367 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
368       /* need to copy the msg in case the msg is on the stack */
369       /* and we only need to copy when sending out network */
370     if (CmiNumNodes()>1 && CmiGetReference(msg)>1) {
371       void *newmsg = CopyMsg(msg, size);
372       CmiFree(msg);
373       msg = newmsg;
374     }
375 #endif
376     CmiSendSelf(msg);
379 CmiCommHandle CmiAsyncBroadcastAllFn(int size, char *msg) {
380     CmiSendSelf(CopyMsg(msg, size));
381     return CmiAsyncBroadcastFn(size, msg);
384 #if CMK_NODE_QUEUE_AVAILABLE
385 #if USE_COMMON_SYNC_BCAST
386 void CmiSyncNodeBroadcastFn(int size, char *msg) {
387     int mynode = CmiMyNode();
388     int i;
389 #if CMI_QD
390     CQdCreate(CpvAccess(cQdState), CmiNumNodes()-1);
391 #endif
392 #if CMK_BROADCAST_SPANNING_TREE
393     CMI_SET_BROADCAST_ROOT(msg, -CmiMyNode()-1);
394     SendSpanningChildrenNode(size, msg);
395 #elif CMK_BROADCAST_HYPERCUBE
396     CMI_SET_BROADCAST_ROOT(msg, -CmiMyNode()-1);
397     SendHyperCubeNode(size, msg);
398 #else
399     for (i=mynode+1; i<CmiNumNodes(); i++)
400         CmiSyncNodeSendFn(i, size, msg);
401     for (i=0; i<mynode; i++)
402         CmiSyncNodeSendFn(i, size, msg);
403 #endif
406 void CmiFreeNodeBroadcastFn(int size, char *msg) {
407     CmiSyncNodeBroadcastFn(size, msg);
408     CmiFree(msg);
410 #endif
412 #if USE_COMMON_ASYNC_BCAST
413 CmiCommHandle CmiAsyncNodeBroadcastFn(int size, char *msg) {
414     CmiSyncNodeBroadcastFn(size, msg);
415     return 0;
417 #endif
419 void CmiSyncNodeBroadcastAllFn(int size, char *msg) {
420     CmiSyncNodeSendFn(CmiMyNode(), size, msg);
421     CmiSyncNodeBroadcastFn(size, msg);
424 CmiCommHandle CmiAsyncNodeBroadcastAllFn(int size, char *msg) {
425     CmiSendNodeSelf(CopyMsg(msg, size));
426     return CmiAsyncNodeBroadcastFn(size, msg);
429 void CmiFreeNodeBroadcastAllFn(int size, char *msg) {
430     CmiSyncNodeBroadcastFn(size, msg);
431     /* Since it's a node-level msg, the msg could be executed on any other
432      * procs on the same node. This means, the push of this msg to the
433      * node-level queue could be immediately followed a pop of this msg on
434      * other cores on the same node even when this msg has not been sent to
435      * other nodes. This is the reason CmiSendNodeSelf must be called after
436      * CmiSyncNodeBroadcastFn 
437      */
438     CmiSendNodeSelf(msg);
440 #endif
441 /* ##### End of Functions Related with Message Sending OPs ##### */
443 #if ! CMK_MULTICAST_LIST_USE_COMMON_CODE
445 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
447     LrtsSyncListSendFn(npes, pes, len, msg);
450 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
452     return LrtsAsyncListSendFn(npes, pes, len, msg);
455 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
457     LrtsFreeListSendFn(npes, pes, len, msg);
460 #endif