2 * functions for broadcast
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);
16 #if CMK_NODE_QUEUE_AVAILABLE
17 CMIQueuePush(CsvAccess(nodeBcastQ), msg);
21 if (CMI_BROADCAST_ROOT(msg)>0) {
22 processProcBcastMsg(size, msg);
24 #if CMK_NODE_QUEUE_AVAILABLE
25 processNodeBcastMsg(size, msg);
31 static void processBcastQs(void) {
32 #if CMK_OFFLOAD_BCAST_PROCESS
35 msg = CMIQueuePop(CsvAccess(procBcastQ));
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);
41 #if CMK_NODE_QUEUE_AVAILABLE
43 msg = CMIQueuePop(CsvAccess(nodeBcastQ));
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);
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);
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) {
64 newmsg = CopyMsg(msg, size);
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.
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
81 if(!CMI_IS_ZC_BCAST(msg))
83 forwardProcBcastMsg(size, 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);
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))
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!
123 // API to forward proc bcast msg
124 void CmiForwardProcBcastMsg(int size, char *msg) {
125 forwardProcBcastMsg(size, msg);
129 // API to forward message to peer PEs
130 void CmiForwardMsgToPeers(int size, char *msg) {
131 SendToPeers(size, msg);
135 static void SendSpanningChildren(int size, char *msg, int rankToAssign, int startNode) {
136 #if CMK_BROADCAST_SPANNING_TREE
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;
152 nd = nd%CmiNumNodes();
153 CmiAssert(nd>=0 && nd!=CmiMyNode());
154 #if CMK_BROADCAST_USE_CMIREFERENCE
156 CmiSendNetworkFunc(CmiNodeFirst(nd), size, msg, BCAST_SYNC);
158 newmsg = CopyMsg(msg, size);
159 CmiSendNetworkFunc(CmiNodeFirst(nd), size, newmsg, BCAST_SYNC);
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);
170 get_topo_tree_nbs(startNode, &parent, &child_count, &children);
172 for (i=0; i < child_count; i++) {
173 int nd = children[i];
174 #if CMK_BROADCAST_USE_CMIREFERENCE
176 CmiSendNetworkFunc(CmiNodeFirst(nd), size, msg, BCAST_SYNC);
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);
184 CMI_DEST_RANK(msg) = oldRank;
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
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
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;
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
227 CmiSendNetworkFunc(CmiNodeFirst(nd), size, msg, BCAST_SYNC);
229 newmsg = CopyMsg(msg, size);
230 CmiSendNetworkFunc(CmiNodeFirst(nd), size, newmsg, BCAST_SYNC);
233 CMI_DEST_RANK(msg) = oldRank;
237 static void SendSpanningChildrenProc(int size, char *msg) {
238 int startnode = CMI_BROADCAST_ROOT(msg)-1;
239 SendSpanningChildren(size, msg, 0, startnode);
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);
256 if (startpe > CmiNumPes()) startnode = startpe - CmiNumPes();
258 SendHyperCube(size, msg, 0, startnode);
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);
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) {
288 CQdCreate(CpvAccess(cQdState), CmiNumPes()-1);
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);
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);
310 for ( i=mype+1; i<_Cmi_numpes; i++ )
311 CmiSyncSendFn(i, size, msg) ;
313 for ( i=0; i<mype; i++ )
314 CmiSyncSendFn(i, size, msg) ;
317 /*CmiPrintf("In SyncBroadcast broadcast\n");*/
320 void CmiSyncBroadcastFn(int size, char *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);
327 CmiSyncBroadcastFn1(size, newmsg);
328 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
329 if (newmsg != msg) CmiFree(newmsg);
333 void CmiFreeBroadcastFn(int size, char *msg) {
334 CmiSyncBroadcastFn1(size,msg);
338 #define CmiSyncBroadcastFn1(s,m) CmiSyncBroadcastFn(s,m)
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");
350 /* Functions regarding broadcat op that sends to every one */
351 void CmiSyncBroadcastAllFn(int size, char *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);
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);
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);
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();
390 CQdCreate(CpvAccess(cQdState), CmiNumNodes()-1);
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);
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);
406 void CmiFreeNodeBroadcastFn(int size, char *msg) {
407 CmiSyncNodeBroadcastFn(size, msg);
412 #if USE_COMMON_ASYNC_BCAST
413 CmiCommHandle CmiAsyncNodeBroadcastFn(int size, char *msg) {
414 CmiSyncNodeBroadcastFn(size, msg);
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
438 CmiSendNodeSelf(msg);
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);