Zcpy Bcast Send API: Guard ZC API macros for non-RDMA layers
[charm.git] / src / conv-core / cputopology.C
1 #include <map>
2 #include <vector>
3 #include <algorithm>
4 #include "converse.h"
5 #include "sockRoutines.h"
6
7 #define DEBUGP(x)  /** CmiPrintf x; */
8
9 /** This scheme relies on using IP address to identify physical nodes 
10  * written by Gengbin Zheng  9/2008
11  *
12  * last updated 10/4/2009   Gengbin Zheng
13  * added function CmiCpuTopologyEnabled() which retuens 1 when supported
14  * when not supported return 0
15  * all functions when cputopology not support, now act like a normal non-smp 
16  * case and all PEs are unique.
17  *
18  * major changes 10/28/09   Gengbin Zheng
19  * - parameters changed from pe to node to be consistent with the function name
20  * - two new functions:   CmiPhysicalNodeID and CmiPhysicalRank
21  *
22  * 3/5/2010   Gengbin Zheng
23  * - use CmiReduce to optimize the collection of node info
24  */
25
26 #if 1
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <unistd.h>
31
32 #include <stdlib.h>
33 #include <stdio.h>
34
35 #if CMK_BLUEGENEQ
36 #include "TopoManager.h"
37 #endif
38
39 #if CMK_BLUEGENEQ
40 #include "spi/include/kernel/process.h"
41 #endif
42
43 #if CMK_CRAYXE || CMK_CRAYXC
44 extern "C" int getXTNodeID(int mpirank, int nummpiranks);
45 #endif
46
47 #if defined(__APPLE__)  && CMK_HAS_MULTIPROCESSING_H
48 #include <Carbon/Carbon.h>
49 #include <Multiprocessing.h>
50 #endif
51
52 #if CMK_BIGSIM_CHARM
53 #include "middle-blue.h"
54 using namespace BGConverse;
55 #endif
56
57 extern "C" int CmiNumCores(void) {
58   int a = 1;
59 #ifdef _WIN32
60 struct _SYSTEM_INFO sysinfo;
61 #endif  
62
63   /* Allow the user to override the number of CPUs for use
64      in scalability testing, debugging, etc. */
65   char *forcecount = getenv("FORCECPUCOUNT");
66   if (forcecount != NULL) {
67     if (sscanf(forcecount, "%d", &a) == 1) {
68       return a; /* if we got a valid count, return it */
69     } else {
70       a = 1;      /* otherwise use the real available hardware CPU count */
71     }
72   }
73
74 #if defined(__APPLE__)  && CMK_HAS_MULTIPROCESSING_H
75   a = MPProcessorsScheduled(); /* Number of active/running CPUs */
76 #endif
77
78 #ifdef _WIN32
79   //struct _SYSTEM_INFO sysinfo;  
80   GetSystemInfo(&sysinfo);
81   a = sysinfo.dwNumberOfProcessors; /* total number of CPUs */
82 #endif /* _MSC_VER */
83
84
85 #ifdef _SC_NPROCESSORS_ONLN
86   a = sysconf(_SC_NPROCESSORS_ONLN); /* number of active/running CPUs */
87 #ifdef _SC_NPROCESSORS_CONF
88   /* also consider CPUs that are temporarily powered down by the OS */
89   const int b = sysconf(_SC_NPROCESSORS_CONF);
90   if ( b > a ) a = b;
91 #endif
92 #elif defined(_SC_CRAY_NCPU)
93   a = sysconf(_SC_CRAY_NCPU);
94 #elif defined(_SC_NPROC_ONLN)
95   a = sysconf(_SC_NPROC_ONLN); /* number of active/running CPUs */
96 #endif
97 #if CMK_BLUEGENEQ
98   a *= Kernel_ProcessCount();
99 #endif
100
101   if (a < 1) a = 1;
102
103   return a;
104 }
105
106 struct _procInfo {
107   skt_ip_t ip;
108   int pe;
109   int ncores;
110   int rank;
111   int nodeID;
112 };
113
114 typedef struct _hostnameMsg {
115   char core[CmiMsgHeaderSizeBytes];
116   int n;
117   _procInfo *procs;
118 } hostnameMsg;
119
120 typedef struct _nodeTopoMsg {
121   char core[CmiMsgHeaderSizeBytes];
122   int *nodes;
123 } nodeTopoMsg;
124
125 typedef struct _topoDoneMsg { // used for empty reduction to indicate all PEs have topo info
126   char core[CmiMsgHeaderSizeBytes];
127 } topoDoneMsg;
128
129 // nodeIDs[pe] is the node number of processor pe
130 class CpuTopology {
131 public:
132   static int *nodeIDs;
133   static int numPes;
134   static int numNodes;
135   static std::vector<int> *bynodes;
136   static int supported;
137
138   ~CpuTopology() {
139     delete [] bynodes;
140   }
141
142     // return -1 when not supported
143   int numUniqNodes() {
144 #if 0
145     if (numNodes != 0) return numNodes;
146     int n = 0;
147     for (int i=0; i<CmiNumPes(); i++) 
148       if (nodeIDs[i] > n)
149         n = nodeIDs[i];
150     numNodes = n+1;
151     return numNodes;
152 #else
153     if (numNodes > 0) return numNodes;     // already calculated
154     std::vector<int> unodes(numPes);
155     int i;
156     for (i=0; i<numPes; i++) unodes[i] = nodeIDs[i];
157     std::sort(unodes.begin(), unodes.end());
158     int last = -1;
159     std::map<int, int> nodemap;  // nodeIDs can be out of range of [0,numNodes]
160     for (i=0; i<numPes; i++)  { 
161         if (unodes[i] != last) {
162           last=unodes[i];
163           nodemap[unodes[i]] = numNodes;
164           numNodes++; 
165         }
166     }
167     if (numNodes == 0)  {
168       numNodes = CmiNumNodes();
169       numPes = CmiNumPes();
170     }
171     else {
172         // re-number nodeIDs, which may be necessary e.g. on BlueGene/P
173       for (i=0; i<numPes; i++) nodeIDs[i] = nodemap[nodeIDs[i]];
174       CpuTopology::supported = 1;
175     }
176     return numNodes;
177 #endif
178   }
179
180   void sort() {
181     int i;
182     numUniqNodes();
183     bynodes = new std::vector<int>[numNodes];
184     if (supported) {
185       for (i=0; i<numPes; i++){
186         CmiAssert(nodeIDs[i] >=0 && nodeIDs[i] <= numNodes); // Sanity check for bug that occurs on mpi-crayxt
187         bynodes[nodeIDs[i]].push_back(i);
188       }
189     }
190     else {    /* not supported/enabled */
191       for (i=0;i<CmiNumPes();i++)  bynodes[CmiNodeOf(i)].push_back(i);
192     }
193   }
194
195   void print() {
196     int i;
197     CmiPrintf("Charm++> Cpu topology info:\n");
198     CmiPrintf("PE to node map: ");
199     for (i=0; i<CmiNumPes(); i++)
200       CmiPrintf("%d ", nodeIDs[i]);
201     CmiPrintf("\n");
202     CmiPrintf("Node to PE map:\n");
203     for (i=0; i<numNodes; i++) {
204       CmiPrintf("Chip #%d: ", i);
205       for (int j=0; j<bynodes[i].size(); j++)
206         CmiPrintf("%d ", bynodes[i][j]);
207       CmiPrintf("\n");
208     }
209   }
210
211 };
212
213 int *CpuTopology::nodeIDs = NULL;
214 int CpuTopology::numPes = 0;
215 int CpuTopology::numNodes = 0;
216 std::vector<int> *CpuTopology::bynodes = NULL;
217 int CpuTopology::supported = 0;
218
219 namespace CpuTopoDetails {
220
221 static nodeTopoMsg *topomsg = NULL;
222 static CmmTable hostTable;
223
224 CpvStaticDeclare(int, cpuTopoHandlerIdx);
225 CpvStaticDeclare(int, cpuTopoRecvHandlerIdx);
226 CpvStaticDeclare(int, topoDoneHandlerIdx);
227
228 static CpuTopology cpuTopo;
229 static CmiNodeLock topoLock = 0; /* Not spelled 'NULL' to quiet warnings when CmiNodeLock is just 'int' */
230 static int done = 0;
231 static int topoDone = 0;
232 static int _noip = 0;
233
234 }
235
236 using namespace CpuTopoDetails;
237
238 static void printTopology(int numNodes)
239 {
240   // assume all nodes have same number of cores
241   const int ways = CmiNumCores();
242   if (ways > 1)
243     CmiPrintf("Charm++> Running on %d hosts (%d sockets x %d cores x %d PUs = %d-way SMP)\n",
244               numNodes, CmiHwlocTopologyLocal.num_sockets,
245               CmiHwlocTopologyLocal.num_cores / CmiHwlocTopologyLocal.num_sockets,
246               CmiHwlocTopologyLocal.num_pus / CmiHwlocTopologyLocal.num_cores,
247               ways);
248   else
249     CmiPrintf("Charm++> Running on %d hosts\n", numNodes);
250
251 #if !CMK_BLUEGENEQ
252   // ignore BG/Q's reserved socket
253   if (ways != CmiHwlocTopologyLocal.num_pus)
254     CmiPrintf("Charm++> Warning: Internally-determined PU count does not match hwloc's result!\n");
255 #endif
256 }
257
258 /* called on PE 0 */
259 static void cpuTopoHandler(void *m)
260 {
261   _procInfo *rec;
262   hostnameMsg *msg = (hostnameMsg *)m;
263   int tag, tag1, pe;
264
265   if (topomsg == NULL) {
266     int i;
267     hostTable = CmmNew();
268     topomsg = (nodeTopoMsg *)CmiAlloc(sizeof(nodeTopoMsg)+CmiNumPes()*sizeof(int));
269 #if CMK_ONESIDED_IMPL
270     CMI_ZC_MSGTYPE(topomsg) = CMK_REG_NO_ZC_MSG;
271 #endif
272     CmiSetHandler((char *)topomsg, CpvAccess(cpuTopoRecvHandlerIdx));
273     topomsg->nodes = (int *)((char*)topomsg + sizeof(nodeTopoMsg));
274     for (i=0; i<CmiNumPes(); i++) topomsg->nodes[i] = -1;
275   }
276   CmiAssert(topomsg != NULL);
277
278   msg->procs = (_procInfo*)((char*)msg + sizeof(hostnameMsg));
279   CmiAssert(msg->n == CmiNumPes());
280   for (int i=0; i<msg->n; i++) 
281   {
282     _procInfo *proc = msg->procs+i;
283
284 /*   for debug
285   skt_print_ip(str, msg->ip);
286   printf("hostname: %d %s\n", msg->pe, str);
287 */
288     tag = *(int*)&proc->ip;
289     pe = proc->pe;
290     if ((rec = (_procInfo *)CmmProbe(hostTable, 1, &tag, &tag1)) != NULL) {
291     }
292     else {
293       proc->nodeID = pe;           // we will compact the node ID later
294       rec = proc;
295       CmmPut(hostTable, 1, &tag, proc);
296     }
297     topomsg->nodes[pe] = rec->nodeID;
298     rec->rank ++;
299   }
300
301   printTopology(CmmEntries(hostTable));
302
303     // clean up CmmTable
304   hostnameMsg *tmpm;
305   tag = CmmWildCard;
306   while ((tmpm = (hostnameMsg *)CmmGet(hostTable, 1, &tag, &tag1)));
307   CmmFree(hostTable);
308   CmiFree(msg);
309
310   CmiSyncBroadcastAllAndFree(sizeof(nodeTopoMsg)+CmiNumPes()*sizeof(int), (char *)topomsg);
311 }
312
313 /* called on PE 0 */
314 static void topoDoneHandler(void *m) {
315   CmiLock(topoLock);
316   topoDone++;
317   CmiUnlock(topoLock);
318 }
319
320 /* called on each processor */
321 static void cpuTopoRecvHandler(void *msg)
322 {
323   nodeTopoMsg *m = (nodeTopoMsg *)msg;
324   m->nodes = (int *)((char*)m + sizeof(nodeTopoMsg));
325
326   CmiLock(topoLock);
327   if (cpuTopo.nodeIDs == NULL) {
328     cpuTopo.nodeIDs = m->nodes;
329     cpuTopo.sort();
330   }
331   else
332     CmiFree(m);
333   done++;
334   CmiUnlock(topoLock);
335
336   //if (CmiMyPe() == 0) cpuTopo.print();
337 }
338
339 // reduction function
340 static void * combineMessage(int *size, void *data, void **remote, int count) 
341 {
342   int i, j;
343   int nprocs = ((hostnameMsg *)data)->n;
344   if (count == 0) return data;
345   for (i=0; i<count; i++) nprocs += ((hostnameMsg *)remote[i])->n;
346   *size = sizeof(hostnameMsg)+sizeof(_procInfo)*nprocs;
347   hostnameMsg *msg = (hostnameMsg *)CmiAlloc(*size);
348 #if CMK_ONESIDED_IMPL
349   CMI_ZC_MSGTYPE(msg) = CMK_REG_NO_ZC_MSG;
350 #endif
351   msg->procs = (_procInfo*)((char*)msg + sizeof(hostnameMsg));
352   msg->n = nprocs;
353   CmiSetHandler((char *)msg, CpvAccess(cpuTopoHandlerIdx));
354
355   int n=0;
356   hostnameMsg *m = (hostnameMsg*)data;
357   m->procs = (_procInfo*)((char*)m + sizeof(hostnameMsg));
358   for (j=0; j<m->n; j++)
359     msg->procs[n++] = m->procs[j];
360   for (i=0; i<count; i++) {
361     m = (hostnameMsg*)remote[i];
362     m->procs = (_procInfo*)((char*)m + sizeof(hostnameMsg));
363     for (j=0; j<m->n; j++)
364       msg->procs[n++] = m->procs[j];
365   }
366   return msg;
367 }
368
369 // reduction function
370 static void *emptyReduction(int *size, void *data, void **remote, int count)
371 {
372   if (CmiMyPe() != 0) {
373     CmiLock(topoLock);
374     topoDone++;
375     CmiUnlock(topoLock);
376   }
377   *size = sizeof(topoDoneMsg);
378   topoDoneMsg *msg = (topoDoneMsg *)CmiAlloc(sizeof(topoDoneMsg));
379 #if CMK_ONESIDED_IMPL
380   CMI_ZC_MSGTYPE(msg) = CMK_REG_NO_ZC_MSG;
381 #endif
382   CmiSetHandler((char *)msg, CpvAccess(topoDoneHandlerIdx));
383   return msg;
384 }
385
386 /******************  API implementation **********************/
387
388 extern "C" int LrtsCpuTopoEnabled()
389 {
390   return CpuTopology::supported;
391 }
392
393 extern "C" int LrtsPeOnSameNode(int pe1, int pe2)
394 {
395   int *nodeIDs = cpuTopo.nodeIDs;
396   if (!cpuTopo.supported || nodeIDs == NULL) return CmiNodeOf(pe1) == CmiNodeOf(pe2);
397   else return nodeIDs[pe1] == nodeIDs[pe2];
398 }
399
400 // return -1 when not supported
401 extern "C" int LrtsNumNodes()
402 {
403   if (!cpuTopo.supported) return CmiNumNodes();
404   else return cpuTopo.numUniqNodes();
405 }
406
407 extern "C" int LrtsNodeSize(int node)
408 {
409   return !cpuTopo.supported?CmiNodeSize(node):(int)cpuTopo.bynodes[node].size();
410 }
411
412 // pelist points to system memory, user should not free it
413 extern "C" void LrtsPeOnNode(int node, int **pelist, int *num)
414 {
415   *num = cpuTopo.bynodes[node].size();
416   if (pelist!=NULL && *num>0) *pelist = cpuTopo.bynodes[node].data();
417 }
418
419 extern "C" int LrtsRankOf(int pe)
420 {
421   if (!cpuTopo.supported) return CmiRankOf(pe);
422   const std::vector<int> &v = cpuTopo.bynodes[cpuTopo.nodeIDs[pe]];
423   int rank = 0;  
424   int npes = v.size();
425   while (rank < npes && v[rank] < pe) rank++;       // already sorted
426   CmiAssert(v[rank] == pe);
427   return rank;
428 }
429
430 extern "C" int LrtsNodeOf(int pe)
431 {
432   if (!cpuTopo.supported) return CmiNodeOf(pe);
433   return cpuTopo.nodeIDs[pe];
434 }
435
436 // the least number processor on the same physical node
437 extern "C"  int LrtsNodeFirst(int node)
438 {
439   if (!cpuTopo.supported) return CmiNodeFirst(node);
440   return cpuTopo.bynodes[node][0];
441 }
442
443
444 extern "C" void LrtsInitCpuTopo(char **argv)
445 {
446   static skt_ip_t myip;
447   hostnameMsg  *msg;
448   double startT;
449  
450   int obtain_flag = 1;              // default on
451   int show_flag = 0;                // default not show topology
452
453   if (CmiMyRank() ==0) {
454      topoLock = CmiCreateLock();
455   }
456
457 #if __FAULT__
458   obtain_flag = 0;
459 #endif
460   if(CmiGetArgFlagDesc(argv,"+obtain_cpu_topology",
461                                            "obtain cpu topology info"))
462     obtain_flag = 1;
463   if (CmiGetArgFlagDesc(argv,"+skip_cpu_topology",
464                                "skip the processof getting cpu topology info"))
465     obtain_flag = 0;
466   if(CmiGetArgFlagDesc(argv,"+show_cpu_topology",
467                                            "Show cpu topology info"))
468     show_flag = 1;
469
470 #if CMK_BIGSIM_CHARM
471   if (BgNodeRank() == 0)
472 #endif
473     {
474       CpvInitialize(int, cpuTopoHandlerIdx);
475       CpvInitialize(int, cpuTopoRecvHandlerIdx);
476       CpvInitialize(int, topoDoneHandlerIdx);
477       CpvAccess(cpuTopoHandlerIdx) =
478         CmiRegisterHandler((CmiHandler)cpuTopoHandler);
479       CpvAccess(cpuTopoRecvHandlerIdx) =
480         CmiRegisterHandler((CmiHandler)cpuTopoRecvHandler);
481       CpvAccess(topoDoneHandlerIdx) =
482         CmiRegisterHandler((CmiHandler)topoDoneHandler);
483     }
484   if (!obtain_flag) {
485     if (CmiMyRank() == 0) cpuTopo.sort();
486     CmiNodeAllBarrier();
487     CcdRaiseCondition(CcdTOPOLOGY_AVAIL);      // call callbacks
488     return;
489   }
490
491   if (CmiMyPe() == 0) {
492 #if CMK_BIGSIM_CHARM
493     if (BgNodeRank() == 0)
494 #endif
495       startT = CmiWallTimer();
496   }
497
498 #if CMK_BIGSIM_CHARM
499   if (BgNodeRank() == 0)
500   {
501     //int numPes = BgNumNodes()*BgGetNumWorkThread();
502     int numPes = cpuTopo.numPes = CkNumPes();
503     cpuTopo.nodeIDs = new int[numPes];
504     CpuTopology::supported = 1;
505     int wth = BgGetNumWorkThread();
506     for (int i=0; i<numPes; i++) {
507       int nid = i / wth;
508       cpuTopo.nodeIDs[i] = nid;
509     }
510     cpuTopo.sort();
511   }
512   return;
513 #else
514
515 #if CMK_USE_GM
516   CmiBarrier();
517 #endif
518
519
520 #if 0
521   if (gethostname(hostname, 999)!=0) {
522       strcpy(hostname, "");
523   }
524 #endif
525 #if CMK_BLUEGENEQ
526   if (CmiMyRank() == 0) {
527    TopoManager tmgr;
528
529     int numPes = cpuTopo.numPes = CmiNumPes();
530     cpuTopo.nodeIDs = new int[numPes];
531     CpuTopology::supported = 1;
532
533     int a, b, c, d, e, t, nid;
534     for(int i=0; i<numPes; i++) {
535       tmgr.rankToCoordinates(i, a, b, c, d, e, t);
536       nid = tmgr.coordinatesToRank(a, b, c, d, e, 0);
537       cpuTopo.nodeIDs[i] = nid;
538     }
539     cpuTopo.sort();
540     if (CmiMyPe()==0) printTopology(cpuTopo.numNodes);
541   }
542   CmiNodeAllBarrier();
543 #elif CMK_CRAYXE || CMK_CRAYXC
544   if(CmiMyRank() == 0) {
545     int numPes = cpuTopo.numPes = CmiNumPes();
546     int numNodes = CmiNumNodes();
547     cpuTopo.nodeIDs = new int[numPes];
548     CpuTopology::supported = 1;
549
550     int nid;
551     for(int i=0; i<numPes; i++) {
552       nid = getXTNodeID(CmiNodeOf(i), numNodes);
553       cpuTopo.nodeIDs[i] = nid;
554     }
555     int prev = -1;
556     nid = -1;
557
558     // this assumes that all cores on a node have consecutive MPI rank IDs
559     // and then changes nodeIDs to 0 to numNodes-1
560     for(int i=0; i<numPes; i++) {
561       if(cpuTopo.nodeIDs[i] != prev) {
562         prev = cpuTopo.nodeIDs[i];
563         cpuTopo.nodeIDs[i] = ++nid;
564       }
565       else
566         cpuTopo.nodeIDs[i] = nid;
567     }
568     cpuTopo.sort();
569     if (CmiMyPe()==0) printTopology(cpuTopo.numNodes);
570   }
571   CmiNodeAllBarrier();
572
573 #else
574
575   bool topoInProgress = true;
576
577   if (CmiMyPe() >= CmiNumPes()) {
578     CmiNodeAllBarrier();         // comm thread waiting
579 #if CMK_MACHINE_PROGRESS_DEFINED
580     bool waitForSecondReduction = (CmiNumNodes() > 1);
581     while (topoInProgress) {
582       CmiNetworkProgress();
583       CmiLock(topoLock);
584       if (waitForSecondReduction) topoInProgress = topoDone < CmiMyNodeSize();
585       else topoInProgress = done < CmiMyNodeSize();
586       CmiUnlock(topoLock);
587     }
588 #endif
589     return;    /* comm thread return */
590   }
591
592     /* get my ip address */
593   if (CmiMyRank() == 0)
594   {
595   #if CMK_HAS_GETHOSTNAME && !CMK_BLUEGENEQ
596     myip = skt_my_ip();        /* not thread safe, so only calls on rank 0 */
597     // fprintf(stderr, "[%d] IP is %d.%d.%d.%d\n", CmiMyPe(), myip.data[0],myip.data[1],myip.data[2],myip.data[3]);
598   #elif CMK_BPROC
599     myip = skt_innode_my_ip();
600   #else
601     if (!CmiMyPe())
602     CmiPrintf("CmiInitCPUTopology Warning: Can not get unique name for the compute nodes. \n");
603     _noip = 1; 
604   #endif
605     cpuTopo.numPes = CmiNumPes();
606   }
607
608   CmiNodeAllBarrier();
609   if (_noip) return; 
610
611     /* prepare a msg to send */
612   msg = (hostnameMsg *)CmiAlloc(sizeof(hostnameMsg)+sizeof(_procInfo));
613 #if CMK_ONESIDED_IMPL
614   CMI_ZC_MSGTYPE(msg) = CMK_REG_NO_ZC_MSG;
615 #endif
616   msg->n = 1;
617   msg->procs = (_procInfo*)((char*)msg + sizeof(hostnameMsg));
618   CmiSetHandler((char *)msg, CpvAccess(cpuTopoHandlerIdx));
619   msg->procs[0].pe = CmiMyPe();
620   msg->procs[0].ip = myip;
621   msg->procs[0].ncores = CmiNumCores();
622   msg->procs[0].rank = 0;
623   msg->procs[0].nodeID = 0;
624   CmiReduce(msg, sizeof(hostnameMsg)+sizeof(_procInfo), combineMessage);
625
626   // blocking here (wait for broadcast from PE0 to reach all PEs in this node)
627   while (topoInProgress) {
628     CsdSchedulePoll();
629     CmiLock(topoLock);
630     topoInProgress = done < CmiMyNodeSize();
631     CmiUnlock(topoLock);
632   }
633
634   if (CmiNumNodes() > 1) {
635     topoDoneMsg *msg2 = (topoDoneMsg *)CmiAlloc(sizeof(topoDoneMsg));
636 #if CMK_ONESIDED_IMPL
637     CMI_ZC_MSGTYPE(msg2) = CMK_REG_NO_ZC_MSG;
638 #endif
639     CmiSetHandler((char *)msg2, CpvAccess(topoDoneHandlerIdx));
640     CmiReduce(msg2, sizeof(topoDoneMsg), emptyReduction);
641     if ((CmiMyPe() == 0) || (CmiNumSpanTreeChildren(CmiMyPe()) > 0)) {
642       // wait until everyone else has topo info
643       topoInProgress = true;
644       while (topoInProgress) {
645         CsdSchedulePoll();
646         CmiLock(topoLock);
647         topoInProgress = topoDone < CmiMyNodeSize();
648         CmiUnlock(topoLock);
649       }
650     } else {
651       CmiLock(topoLock);
652       topoDone++;
653       CmiUnlock(topoLock);
654     }
655   }
656
657   if (CmiMyPe() == 0) {
658 #if CMK_BIGSIM_CHARM
659     if (BgNodeRank() == 0)
660 #endif
661       CmiPrintf("Charm++> cpu topology info is gathered in %.3f seconds.\n", CmiWallTimer()-startT);
662   }
663 #endif
664
665 #endif   /* __BIGSIM__ */
666
667   // now every one should have the node info
668   CcdRaiseCondition(CcdTOPOLOGY_AVAIL);      // call callbacks
669   if (CmiMyPe() == 0 && show_flag) cpuTopo.print();
670 }
671
672 #else           /* not supporting cpu topology */
673
674 extern "C" void LrtsInitCpuTopo(char **argv)
675 {
676   /* do nothing */
677   int obtain_flag = CmiGetArgFlagDesc(argv,"+obtain_cpu_topology",
678                                                 "obtain cpu topology info");
679   CmiGetArgFlagDesc(argv,"+skip_cpu_topology",
680                                "skip the processof getting cpu topology info");
681   CmiGetArgFlagDesc(argv,"+show_cpu_topology",
682                                            "Show cpu topology info");
683 }
684
685 #endif
686
687 extern "C" int CmiCpuTopologyEnabled()
688 {
689   return LrtsCpuTopoEnabled();
690 }
691 extern "C" int CmiPeOnSamePhysicalNode(int pe1, int pe2)
692 {
693   return LrtsPeOnSameNode(pe1, pe2);
694 }
695 extern "C" int CmiNumPhysicalNodes()
696 {
697   return LrtsNumNodes();
698 }
699 extern "C" int CmiNumPesOnPhysicalNode(int node)
700 {
701   return LrtsNodeSize(node);
702 }
703 extern "C" void CmiGetPesOnPhysicalNode(int node, int **pelist, int *num)
704 {
705   LrtsPeOnNode(node, pelist, num);
706 }
707 extern "C" int CmiPhysicalRank(int pe)
708 {
709   return LrtsRankOf(pe);
710 }
711 extern "C" int CmiPhysicalNodeID(int pe)
712 {
713   return LrtsNodeOf(pe);
714 }
715 extern "C" int CmiGetFirstPeOnPhysicalNode(int node)
716 {
717   return LrtsNodeFirst(node);
718 }
719 extern "C" void CmiInitCPUTopology(char **argv)
720 {
721   LrtsInitCpuTopo(argv);
722 }
723