restructure machine-common, split broadcast related
[charm.git] / src / arch / util / machine-broadcast.c
1 static void handleOneBcastMsg(int size, char *msg) {
2     CmiAssert(CMI_BROADCAST_ROOT(msg)!=0);
3 #if CMK_OFFLOAD_BCAST_PROCESS
4     if (CMI_BROADCAST_ROOT(msg)>0) {
5         PCQueuePush(CsvAccess(procBcastQ), msg);
6     } else {
7 #if CMK_NODE_QUEUE_AVAILABLE
8         PCQueuePush(CsvAccess(nodeBcastQ), msg);
9 #endif
10     }
11 #else
12     if (CMI_BROADCAST_ROOT(msg)>0) {
13         processProcBcastMsg(size, msg);
14     } else {
15 #if CMK_NODE_QUEUE_AVAILABLE
16         processNodeBcastMsg(size, msg);
17 #endif
18     }
19 #endif
20 }
21
22 static void processBcastQs() {
23 #if CMK_OFFLOAD_BCAST_PROCESS
24     char *msg;
25     do {
26         msg = PCQueuePop(CsvAccess(procBcastQ));
27         if (!msg) break;
28         MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p begin{", CmiMyNode(), msg);
29         processProcBcastMsg(CMI_MSG_SIZE(msg), msg);
30         MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p end}", CmiMyNode(), msg);
31     } while (1);
32 #if CMK_NODE_QUEUE_AVAILABLE
33     do {
34         msg = PCQueuePop(CsvAccess(nodeBcastQ));
35         if (!msg) break;
36         MACHSTATE2(4, "[%d]: process a node-level bcast msg %p begin{", CmiMyNode(), msg);
37         processNodeBcastMsg(CMI_MSG_SIZE(msg), msg);
38         MACHSTATE2(4, "[%d]: process a node-level bcast msg %p end}", CmiMyNode(), msg);
39     } while (1);
40 #endif
41 #endif
42 }
43
44 static INLINE_KEYWORD void processProcBcastMsg(int size, char *msg) {
45 #if CMK_BROADCAST_SPANNING_TREE
46     SendSpanningChildrenProc(size, msg);
47 #elif CMK_BROADCAST_HYPERCUBE
48     SendHyperCubeProc(size, msg);
49 #endif
50
51     /* Since this function is only called on intermediate nodes,
52      * the rank of this msg should be 0.
53      */
54     CmiAssert(CMI_DEST_RANK(msg)==0);
55     /*CmiPushPE(CMI_DEST_RANK(msg), msg);*/
56     CmiPushPE(0, msg);
57 }
58
59 static INLINE_KEYWORD void processNodeBcastMsg(int size, char *msg) {
60 #if CMK_BROADCAST_SPANNING_TREE
61     SendSpanningChildrenNode(size, msg);
62 #elif CMK_BROADCAST_HYPERCUBE
63     SendHyperCubeNode(size, msg);
64 #endif
65
66     /* In SMP mode, this push operation needs to be executed
67      * after forwarding broadcast messages. If it is executed
68      * earlier, then during the bcast msg forwarding period,
69      * the msg could be already freed on the worker thread.
70      * As a result, the forwarded message could be wrong!
71      * 
72      */
73     CmiPushNode(msg);
74 }
75
76 static void SendSpanningChildren(int size, char *msg, int rankToAssign, int startNode) {
77 #if CMK_BROADCAST_SPANNING_TREE
78     int i, oldRank;
79     char *newmsg;
80
81     oldRank = CMI_DEST_RANK(msg);
82     /* doing this is to avoid the multiple assignment in the following for loop */
83     CMI_DEST_RANK(msg) = rankToAssign;
84     /* first send msgs to other nodes */
85     CmiAssert(startNode >=0 &&  startNode<CmiNumNodes());
86     for (i=1; i<=BROADCAST_SPANNING_FACTOR; i++) {
87         int nd = CmiMyNode()-startNode;
88         if (nd<0) nd+=CmiNumNodes();
89         nd = BROADCAST_SPANNING_FACTOR*nd + i;
90         if (nd > CmiNumNodes() - 1) break;
91         nd += startNode;
92         nd = nd%CmiNumNodes();
93         CmiAssert(nd>=0 && nd!=CmiMyNode());
94 #if CMK_BROADCAST_USE_CMIREFERENCE
95         CmiReference(msg);
96         LrtsSendFunc(nd, size, msg, P2P_SYNC);
97 #else
98         newmsg = CopyMsg(msg, size);
99         LrtsSendFunc(nd, size, newmsg, P2P_SYNC);
100 #endif
101     }
102     CMI_DEST_RANK(msg) = oldRank;
103 #endif
104 }
105 static void SendHyperCube(int size,  char *msg, int rankToAssign, int startNode) {
106 #if CMK_BROADCAST_HYPERCUBE
107     int i, cnt, tmp, relDist, oldRank;
108     const int dims=CmiNodesDim;
109
110     oldRank = CMI_DEST_RANK(msg);
111     /* doing this is to avoid the multiple assignment in the following for loop */
112     CMI_DEST_RANK(msg) = rankToAssign;
113
114     /* first send msgs to other nodes */
115     relDist = CmiMyNode()-startNode;
116     if (relDist < 0) relDist += CmiNumNodes();
117
118     /* Sending scheme example: say we have 9 nodes, and the msg is sent from 0
119      * The overall sending steps will be as follows:
120      * 0-->8, 0-->4, 0-->2, 0-->1
121      *               4-->6, 4-->5
122      *                      2-->3
123      *                      6-->7
124      * So for node id as N=A+2^B, it will forward the broadcast (B-1) msg to in
125      * the order as: N+2^(B-1), N+2^(B-2),..., N+1 except node 0, where B is
126      * the first position of bit 1 in the binary format of the number of N
127      * counting from the right with count starting from 0.
128      * On node 0, the value "B" should be CmiNodesDim
129      */
130     /* Calculate 2^B */
131     if(relDist==0) cnt = 1<<dims;
132     else cnt = relDist & ((~relDist)+1);
133     /*CmiPrintf("ND[%d]: send bcast msg with cnt=%d\n", CmiMyNode(), cnt);*/
134     /* Begin to send msgs */
135     for(cnt>>=1; cnt>0; cnt>>=1){
136         int nd = relDist + cnt;
137         if (nd >= CmiNumNodes()) continue;
138         nd = (nd+startNode)%CmiNumNodes();
139         /*CmiPrintf("ND[%d]: send to node %d\n", CmiMyNode(), nd);*/
140         CmiAssert(nd>=0 && nd!=CmiMyNode());
141 #if CMK_BROADCAST_USE_CMIREFERENCE
142         CmiReference(msg);
143         LrtsSendFunc(nd, size, msg, P2P_SYNC);
144 #else
145         char *newmsg = CopyMsg(msg, size);
146         LrtsSendFunc(nd, size, newmsg, P2P_SYNC);
147 #endif
148     }
149     CMI_DEST_RANK(msg) = oldRank;
150 #endif
151 }
152
153 static void SendSpanningChildrenProc(int size, char *msg) {
154     int startpe = CMI_BROADCAST_ROOT(msg)-1;
155     int startnode = CmiNodeOf(startpe);
156 #if CMK_SMP
157     if (startpe > CmiNumPes()) startnode = startpe - CmiNumPes();
158 #endif
159     SendSpanningChildren(size, msg, 0, startnode);
160 #if CMK_SMP
161     /* second send msgs to my peers on this node */
162     SendToPeers(size, msg);
163 #endif
164 }
165
166 /* send msg along the hypercube in broadcast. (Sameer) */
167 static void SendHyperCubeProc(int size, char *msg) {
168     int startpe = CMI_BROADCAST_ROOT(msg)-1;
169     int startnode = CmiNodeOf(startpe);
170 #if CMK_SMP
171     if (startpe > CmiNumPes()) startnode = startpe - CmiNumPes();
172 #endif
173     SendHyperCube(size, msg, 0, startnode);
174 #if CMK_SMP
175     /* second send msgs to my peers on this node */
176     SendToPeers(size, msg);
177 #endif
178 }
179
180 #if CMK_NODE_QUEUE_AVAILABLE
181 static void SendSpanningChildrenNode(int size, char *msg) {
182     int startnode = -CMI_BROADCAST_ROOT(msg)-1;
183     SendSpanningChildren(size, msg, DGRAM_NODEMESSAGE, startnode);
184 }
185 static void SendHyperCubeNode(int size, char *msg) {
186     int startnode = -CMI_BROADCAST_ROOT(msg)-1;
187     SendHyperCube(size, msg, DGRAM_NODEMESSAGE, startnode);
188 }
189 #endif
190
191 #if USE_COMMON_SYNC_BCAST
192 /* Functions regarding broadcat op that sends to every one else except me */
193 void CmiSyncBroadcastFn(int size, char *msg) {
194     int mype = CmiMyPe();
195     int i;
196
197     CQdCreate(CpvAccess(cQdState), CmiNumPes()-1);
198 #if CMK_SMP
199     /*record the rank to avoid re-sending the msg in  spanning tree or hypercube*/
200     CMI_DEST_RANK(msg) = CmiMyRank();
201 #endif
202
203 #if CMK_BROADCAST_SPANNING_TREE
204     CMI_SET_BROADCAST_ROOT(msg, mype+1);
205     SendSpanningChildrenProc(size, msg);
206 #elif CMK_BROADCAST_HYPERCUBE
207     CMI_SET_BROADCAST_ROOT(msg, mype+1);
208     SendHyperCubeProc(size, msg);
209 #else
210     for ( i=mype+1; i<_Cmi_numpes; i++ )
211         CmiSyncSendFn(i, size, msg) ;
212     for ( i=0; i<mype; i++ )
213         CmiSyncSendFn(i, size, msg) ;
214 #endif
215
216     /*CmiPrintf("In  SyncBroadcast broadcast\n");*/
217 }
218
219 void CmiFreeBroadcastFn(int size, char *msg) {
220     CmiSyncBroadcastFn(size,msg);
221     CmiFree(msg);
222 }
223 #endif
224
225 #if USE_COMMON_ASYNC_BCAST
226 /* FIXME: should use spanning or hypercube, but luckily async is never used */
227 CmiCommHandle CmiAsyncBroadcastFn(int size, char *msg) {
228     /*CmiPrintf("In  AsyncBroadcast broadcast\n");*/
229     CmiAbort("CmiAsyncBroadcastFn should never be called");
230     return 0;
231 }
232 #endif
233
234 /* Functions regarding broadcat op that sends to every one */
235 void CmiSyncBroadcastAllFn(int size, char *msg) {
236     CmiSyncSendFn(CmiMyPe(), size, msg) ;
237     CmiSyncBroadcastFn(size, msg);
238 }
239
240 void CmiFreeBroadcastAllFn(int size, char *msg) {
241     CmiSendSelf(msg);
242     CmiSyncBroadcastFn(size, msg);
243 }
244
245 CmiCommHandle CmiAsyncBroadcastAllFn(int size, char *msg) {
246     CmiSendSelf(CopyMsg(msg, size));
247     return CmiAsyncBroadcastFn(size, msg);
248 }
249
250 #if CMK_NODE_QUEUE_AVAILABLE
251 #if USE_COMMON_SYNC_BCAST
252 void CmiSyncNodeBroadcastFn(int size, char *msg) {
253     int mynode = CmiMyNode();
254     int i;
255     CQdCreate(CpvAccess(cQdState), CmiNumNodes()-1);
256 #if CMK_BROADCAST_SPANNING_TREE
257     CMI_SET_BROADCAST_ROOT(msg, -CmiMyNode()-1);
258     SendSpanningChildrenNode(size, msg);
259 #elif CMK_BROADCAST_HYPERCUBE
260     CMI_SET_BROADCAST_ROOT(msg, -CmiMyNode()-1);
261     SendHyperCubeNode(size, msg);
262 #else
263     for (i=mynode+1; i<CmiNumNodes(); i++)
264         CmiSyncNodeSendFn(i, size, msg);
265     for (i=0; i<mynode; i++)
266         CmiSyncNodeSendFn(i, size, msg);
267 #endif
268 }
269
270 void CmiFreeNodeBroadcastFn(int size, char *msg) {
271     CmiSyncNodeBroadcastFn(size, msg);
272     CmiFree(msg);
273 }
274 #endif
275
276 #if USE_COMMON_ASYNC_BCAST
277 CmiCommHandle CmiAsyncNodeBroadcastFn(int size, char *msg) {
278     CmiSyncNodeBroadcastFn(size, msg);
279     return 0;
280 }
281 #endif
282
283 void CmiSyncNodeBroadcastAllFn(int size, char *msg) {
284     CmiSyncNodeSendFn(CmiMyNode(), size, msg);
285     CmiSyncNodeBroadcastFn(size, msg);
286 }
287
288 CmiCommHandle CmiAsyncNodeBroadcastAllFn(int size, char *msg) {
289     CmiSendNodeSelf(CopyMsg(msg, size));
290     return CmiAsyncNodeBroadcastFn(size, msg);
291 }
292
293 void CmiFreeNodeBroadcastAllFn(int size, char *msg) {
294     CmiSyncNodeBroadcastFn(size, msg);
295     /* Since it's a node-level msg, the msg could be executed on any other
296      * procs on the same node. This means, the push of this msg to the
297      * node-level queue could be immediately followed a pop of this msg on
298      * other cores on the same node even when this msg has not been sent to
299      * other nodes. This is the reason CmiSendNodeSelf must be called after
300      * CmiSyncNodeBroadcastFn 
301      */
302     CmiSendNodeSelf(msg);
303 }
304 #endif
305 /* ##### End of Functions Related with Message Sending OPs ##### */