2 * functions for broadcast
5 CmiCommHandle
CmiSendNetworkFunc(int destPE
, int size
, char *msg
, int mode
);
7 static void handleOneBcastMsg(int size
, char *msg
) {
8 CmiAssert(CMI_BROADCAST_ROOT(msg
)!=0);
9 #if CMK_OFFLOAD_BCAST_PROCESS
10 if (CMI_BROADCAST_ROOT(msg
)>0) {
11 CMIQueuePush(CsvAccess(procBcastQ
), msg
);
13 #if CMK_NODE_QUEUE_AVAILABLE
14 CMIQueuePush(CsvAccess(nodeBcastQ
), msg
);
18 if (CMI_BROADCAST_ROOT(msg
)>0) {
19 processProcBcastMsg(size
, msg
);
21 #if CMK_NODE_QUEUE_AVAILABLE
22 processNodeBcastMsg(size
, msg
);
28 static void processBcastQs() {
29 #if CMK_OFFLOAD_BCAST_PROCESS
32 msg
= CMIQueuePop(CsvAccess(procBcastQ
));
34 MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p begin{", CmiMyNode(), msg
);
35 processProcBcastMsg(CMI_MSG_SIZE(msg
), msg
);
36 MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p end}", CmiMyNode(), msg
);
38 #if CMK_NODE_QUEUE_AVAILABLE
40 msg
= CMIQueuePop(CsvAccess(nodeBcastQ
));
42 MACHSTATE2(4, "[%d]: process a node-level bcast msg %p begin{", CmiMyNode(), msg
);
43 processNodeBcastMsg(CMI_MSG_SIZE(msg
), msg
);
44 MACHSTATE2(4, "[%d]: process a node-level bcast msg %p end}", CmiMyNode(), msg
);
50 static INLINE_KEYWORD
void processProcBcastMsg(int size
, char *msg
) {
51 /* Since this function is only called on intermediate nodes,
52 * the rank of this msg should be 0.
54 CmiAssert(CMI_DEST_RANK(msg
)==0);
55 /*CmiPushPE(CMI_DEST_RANK(msg), msg);*/
57 #if CMK_BROADCAST_SPANNING_TREE
58 SendSpanningChildrenProc(size
, msg
);
59 #elif CMK_BROADCAST_HYPERCUBE
60 SendHyperCubeProc(size
, msg
);
62 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
63 /* same message may be sent out, make a copy of it */
64 if (CmiNumNodes()>1 && CmiGetReference(msg
)>1) {
66 newmsg
= CopyMsg(msg
, size
);
76 #if CMK_NODE_QUEUE_AVAILABLE
77 static INLINE_KEYWORD
void processNodeBcastMsg(int size
, char *msg
) {
78 #if CMK_BROADCAST_SPANNING_TREE
79 SendSpanningChildrenNode(size
, msg
);
80 #elif CMK_BROADCAST_HYPERCUBE
81 SendHyperCubeNode(size
, msg
);
84 /* In SMP mode, this push operation needs to be executed
85 * after forwarding broadcast messages. If it is executed
86 * earlier, then during the bcast msg forwarding period,
87 * the msg could be already freed on the worker thread.
88 * As a result, the forwarded message could be wrong!
95 static void SendSpanningChildren(int size
, char *msg
, int rankToAssign
, int startNode
) {
96 #if CMK_BROADCAST_SPANNING_TREE
100 oldRank
= CMI_DEST_RANK(msg
);
101 /* doing this is to avoid the multiple assignment in the following for loop */
102 CMI_DEST_RANK(msg
) = rankToAssign
;
103 /* first send msgs to other nodes */
104 CmiAssert(startNode
>=0 && startNode
<CmiNumNodes());
105 for (i
=1; i
<=BROADCAST_SPANNING_FACTOR
; i
++) {
106 int nd
= CmiMyNode()-startNode
;
107 if (nd
<0) nd
+=CmiNumNodes();
108 nd
= BROADCAST_SPANNING_FACTOR
*nd
+ i
;
109 if (nd
> CmiNumNodes() - 1) break;
111 nd
= nd
%CmiNumNodes();
112 CmiAssert(nd
>=0 && nd
!=CmiMyNode());
113 #if CMK_BROADCAST_USE_CMIREFERENCE
115 CmiSendNetworkFunc(CmiNodeFirst(nd
), size
, msg
, BCAST_SYNC
);
117 newmsg
= CopyMsg(msg
, size
);
118 CmiSendNetworkFunc(CmiNodeFirst(nd
), size
, newmsg
, BCAST_SYNC
);
121 CMI_DEST_RANK(msg
) = oldRank
;
125 static void SendHyperCube(int size
, char *msg
, int rankToAssign
, int startNode
) {
126 #if CMK_BROADCAST_HYPERCUBE
127 int i
, cnt
, tmp
, relDist
, oldRank
;
128 const int dims
=CmiNodesDim
;
130 oldRank
= CMI_DEST_RANK(msg
);
131 /* doing this is to avoid the multiple assignment in the following for loop */
132 CMI_DEST_RANK(msg
) = rankToAssign
;
134 /* first send msgs to other nodes */
135 relDist
= CmiMyNode()-startNode
;
136 if (relDist
< 0) relDist
+= CmiNumNodes();
138 /* Sending scheme example: say we have 9 nodes, and the msg is sent from 0
139 * The overall sending steps will be as follows:
140 * 0-->8, 0-->4, 0-->2, 0-->1
144 * So for node id as N=A+2^B, it will forward the broadcast (B-1) msg to in
145 * the order as: N+2^(B-1), N+2^(B-2),..., N+1 except node 0, where B is
146 * the first position of bit 1 in the binary format of the number of N
147 * counting from the right with count starting from 0.
148 * On node 0, the value "B" should be CmiNodesDim
151 if(relDist
==0) cnt
= 1<<dims
;
152 else cnt
= relDist
& ((~relDist
)+1);
153 /*CmiPrintf("ND[%d]: send bcast msg with cnt=%d\n", CmiMyNode(), cnt);*/
154 /* Begin to send msgs */
155 for(cnt
>>=1; cnt
>0; cnt
>>=1){
156 int nd
= relDist
+ cnt
;
158 if (nd
>= CmiNumNodes()) continue;
159 nd
= (nd
+startNode
)%CmiNumNodes();
160 /*CmiPrintf("ND[%d]: send to node %d\n", CmiMyNode(), nd);*/
161 CmiAssert(nd
>=0 && nd
!=CmiMyNode());
162 #if CMK_BROADCAST_USE_CMIREFERENCE
164 CmiSendNetworkFunc(CmiNodeFirst(nd
), size
, msg
, BCAST_SYNC
);
166 newmsg
= CopyMsg(msg
, size
);
167 CmiSendNetworkFunc(CmiNodeFirst(nd
), size
, newmsg
, BCAST_SYNC
);
170 CMI_DEST_RANK(msg
) = oldRank
;
174 static void SendSpanningChildrenProc(int size
, char *msg
) {
175 int startnode
= CMI_BROADCAST_ROOT(msg
)-1;
176 SendSpanningChildren(size
, msg
, 0, startnode
);
178 /* second send msgs to my peers on this node */
179 SendToPeers(size
, msg
);
183 /* send msg along the hypercube in broadcast. (Sameer) */
184 static void SendHyperCubeProc(int size
, char *msg
) {
185 int startpe
= CMI_BROADCAST_ROOT(msg
)-1;
186 int startnode
= CmiNodeOf(startpe
);
188 if (startpe
> CmiNumPes()) startnode
= startpe
- CmiNumPes();
190 SendHyperCube(size
, msg
, 0, startnode
);
192 /* second send msgs to my peers on this node */
193 SendToPeers(size
, msg
);
197 #if CMK_NODE_QUEUE_AVAILABLE
198 static void SendSpanningChildrenNode(int size
, char *msg
) {
199 int startnode
= -CMI_BROADCAST_ROOT(msg
)-1;
200 SendSpanningChildren(size
, msg
, DGRAM_NODEMESSAGE
, startnode
);
202 static void SendHyperCubeNode(int size
, char *msg
) {
203 int startnode
= -CMI_BROADCAST_ROOT(msg
)-1;
204 SendHyperCube(size
, msg
, DGRAM_NODEMESSAGE
, startnode
);
208 #if USE_COMMON_SYNC_BCAST
209 /* Functions regarding broadcat op that sends to every one else except me */
210 void CmiSyncBroadcastFn1(int size
, char *msg
) {
213 CQdCreate(CpvAccess(cQdState
), CmiNumPes()-1);
214 /*record the rank to avoid re-sending the msg in spanning tree or hypercube*/
215 CMI_DEST_RANK(msg
) = CmiMyRank();
217 #if CMK_BROADCAST_SPANNING_TREE
218 CMI_SET_BROADCAST_ROOT(msg
, CmiMyNode()+1);
219 SendSpanningChildrenProc(size
, msg
);
220 #elif CMK_BROADCAST_HYPERCUBE
221 CMI_SET_BROADCAST_ROOT(msg
, CmiMyNode()+1);
222 SendHyperCubeProc(size
, msg
);
226 /* In SMP, this function may be called from comm thread with a larger pe */
227 if(mype
>= _Cmi_numpes
){
228 for(i
=0; i
<_Cmi_numpes
; i
++)
229 CmiSyncSendFn(i
, size
, msg
);
234 for ( i
=mype
+1; i
<_Cmi_numpes
; i
++ )
235 CmiSyncSendFn(i
, size
, msg
) ;
237 for ( i
=0; i
<mype
; i
++ )
238 CmiSyncSendFn(i
, size
, msg
) ;
241 /*CmiPrintf("In SyncBroadcast broadcast\n");*/
244 void CmiSyncBroadcastFn(int size
, char *msg
) {
246 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
247 /* need to copy the msg in case the msg is on the stack */
248 /* and we only need to copy when sending out network */
249 if (CmiNumNodes()>1) newmsg
= CopyMsg(msg
, size
);
251 CmiSyncBroadcastFn1(size
, newmsg
);
252 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
253 if (newmsg
!= msg
) CmiFree(newmsg
);
257 void CmiFreeBroadcastFn(int size
, char *msg
) {
258 CmiSyncBroadcastFn1(size
,msg
);
262 #define CmiSyncBroadcastFn1(s,m) CmiSyncBroadcastFn(s,m)
265 #if USE_COMMON_ASYNC_BCAST
266 /* FIXME: should use spanning or hypercube, but luckily async is never used */
267 CmiCommHandle
CmiAsyncBroadcastFn(int size
, char *msg
) {
268 /*CmiPrintf("In AsyncBroadcast broadcast\n");*/
269 CmiAbort("CmiAsyncBroadcastFn should never be called");
274 /* Functions regarding broadcat op that sends to every one */
275 void CmiSyncBroadcastAllFn(int size
, char *msg
) {
277 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
278 /* need to copy the msg in case the msg is on the stack */
279 /* and we only need to copy when sending out network */
280 if (CmiNumNodes()>1) newmsg
= CopyMsg(msg
, size
);
282 CmiSyncSendFn(CmiMyPe(), size
, newmsg
) ;
283 CmiSyncBroadcastFn1(size
, newmsg
);
284 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
285 if (newmsg
!= msg
) CmiFree(newmsg
);
289 void CmiFreeBroadcastAllFn(int size
, char *msg
) {
290 CmiSyncBroadcastFn1(size
, msg
);
291 #if CMK_BROADCAST_SPANNING_TREE && CMK_BROADCAST_USE_CMIREFERENCE
292 /* need to copy the msg in case the msg is on the stack */
293 /* and we only need to copy when sending out network */
294 if (CmiNumNodes()>1 && CmiGetReference(msg
)>1) {
295 void *newmsg
= CopyMsg(msg
, size
);
303 CmiCommHandle
CmiAsyncBroadcastAllFn(int size
, char *msg
) {
304 CmiSendSelf(CopyMsg(msg
, size
));
305 return CmiAsyncBroadcastFn(size
, msg
);
308 #if CMK_NODE_QUEUE_AVAILABLE
309 #if USE_COMMON_SYNC_BCAST
310 void CmiSyncNodeBroadcastFn(int size
, char *msg
) {
311 int mynode
= CmiMyNode();
313 CQdCreate(CpvAccess(cQdState
), CmiNumNodes()-1);
314 #if CMK_BROADCAST_SPANNING_TREE
315 CMI_SET_BROADCAST_ROOT(msg
, -CmiMyNode()-1);
316 SendSpanningChildrenNode(size
, msg
);
317 #elif CMK_BROADCAST_HYPERCUBE
318 CMI_SET_BROADCAST_ROOT(msg
, -CmiMyNode()-1);
319 SendHyperCubeNode(size
, msg
);
321 for (i
=mynode
+1; i
<CmiNumNodes(); i
++)
322 CmiSyncNodeSendFn(i
, size
, msg
);
323 for (i
=0; i
<mynode
; i
++)
324 CmiSyncNodeSendFn(i
, size
, msg
);
328 void CmiFreeNodeBroadcastFn(int size
, char *msg
) {
329 CmiSyncNodeBroadcastFn(size
, msg
);
334 #if USE_COMMON_ASYNC_BCAST
335 CmiCommHandle
CmiAsyncNodeBroadcastFn(int size
, char *msg
) {
336 CmiSyncNodeBroadcastFn(size
, msg
);
341 void CmiSyncNodeBroadcastAllFn(int size
, char *msg
) {
342 CmiSyncNodeSendFn(CmiMyNode(), size
, msg
);
343 CmiSyncNodeBroadcastFn(size
, msg
);
346 CmiCommHandle
CmiAsyncNodeBroadcastAllFn(int size
, char *msg
) {
347 CmiSendNodeSelf(CopyMsg(msg
, size
));
348 return CmiAsyncNodeBroadcastFn(size
, msg
);
351 void CmiFreeNodeBroadcastAllFn(int size
, char *msg
) {
352 CmiSyncNodeBroadcastFn(size
, msg
);
353 /* Since it's a node-level msg, the msg could be executed on any other
354 * procs on the same node. This means, the push of this msg to the
355 * node-level queue could be immediately followed a pop of this msg on
356 * other cores on the same node even when this msg has not been sent to
357 * other nodes. This is the reason CmiSendNodeSelf must be called after
358 * CmiSyncNodeBroadcastFn
360 CmiSendNodeSelf(msg
);
363 /* ##### End of Functions Related with Message Sending OPs ##### */
365 #if ! CMK_MULTICAST_LIST_USE_COMMON_CODE
367 void CmiSyncListSendFn(int npes
, int *pes
, int len
, char *msg
)
369 LrtsSyncListSendFn(npes
, pes
, len
, msg
);
372 CmiCommHandle
CmiAsyncListSendFn(int npes
, int *pes
, int len
, char *msg
)
374 return LrtsAsyncListSendFn(npes
, pes
, len
, msg
);
377 void CmiFreeListSendFn(int npes
, int *pes
, int len
, char *msg
)
379 LrtsFreeListSendFn(npes
, pes
, len
, msg
);