MPProcessorsScheduled only avaialble on Mac version 10 and later
[charm.git] / src / conv-core / cputopology.C
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 #include "converse.h"
9 #include "sockRoutines.h"
10 #include "cklists.h"
11
12 #define DEBUGP(x)  /* CmiPrintf x;  */
13
14 /*
15  This scheme relies on using IP address to identify physical nodes 
16
17   written by Gengbin Zheng  9/2008
18 */
19 #if 1
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24
25 #include <stdlib.h>
26 #include <stdio.h>
27
28 #if defined(__APPLE__)  && CMK_HAS_MULTIPROCESSING_H
29 #include <Carbon/Carbon.h>
30 #include <Multiprocessing.h>
31 #endif
32
33 extern "C" int CmiNumCores(void) {
34   int a = 1;
35 #ifdef _WIN32
36 struct _SYSTEM_INFO sysinfo;
37 #endif  
38
39   /* Allow the user to override the number of CPUs for use
40      in scalability testing, debugging, etc. */
41   char *forcecount = getenv("VMDFORCECPUCOUNT");
42   if (forcecount != NULL) {
43     if (sscanf(forcecount, "%d", &a) == 1) {
44       return a; /* if we got a valid count, return it */
45     } else {
46       a = 1;      /* otherwise use the real available hardware CPU count */
47     }
48   }
49
50 #if defined(__APPLE__)  && CMK_HAS_MULTIPROCESSING_H
51   a = MPProcessorsScheduled(); /* Number of active/running CPUs */
52 #endif
53
54 #ifdef _WIN32
55   //struct _SYSTEM_INFO sysinfo;  
56   GetSystemInfo(&sysinfo);
57   a = sysinfo.dwNumberOfProcessors; /* total number of CPUs */
58 #endif /* _MSC_VER */
59
60
61 #ifdef _SC_NPROCESSORS_ONLN
62   a = sysconf(_SC_NPROCESSORS_ONLN); /* number of active/running CPUs */
63 #elif defined(_SC_CRAY_NCPU)
64   a = sysconf(_SC_CRAY_NCPU);
65 #elif defined(_SC_NPROC_ONLN)
66   a = sysconf(_SC_NPROC_ONLN); /* number of active/running CPUs */
67 #endif
68   if (a == -1) a = 1;
69
70 #if defined(ARCH_HPUX11) || defined(ARCH_HPUX10)
71   a = mpctl(MPC_GETNUMSPUS, 0, 0); /* total number of CPUs */
72 #endif /* HPUX */
73
74   return a;
75 }
76
77 static int cpuTopoHandlerIdx;
78 static int cpuTopoRecvHandlerIdx;
79
80 typedef struct _hostnameMsg {
81   char core[CmiMsgHeaderSizeBytes];
82   int pe;
83   skt_ip_t ip;
84   int ncores;
85   int rank;
86   int nodenum;
87 } hostnameMsg;
88
89 typedef struct _nodeTopoMsg {
90   char core[CmiMsgHeaderSizeBytes];
91   int *nodes;
92 } nodeTopoMsg;
93
94 static nodeTopoMsg *topomsg = NULL;
95 static CmmTable hostTable;
96
97 // nodenum[pe] is the node number of processor pe
98 class CpuTopology {
99 public:
100 static int *nodenum;
101 static int numNodes;
102 static CkVec<int> *bynodes;
103
104 int numUniqNodes() {
105                if (numNodes != 0) return numNodes;
106                int n = 0;
107                for (int i=0; i<CmiNumPes(); i++) 
108                  if (nodenum[i] > n) n = nodenum[i];
109                numNodes = n+1;
110                return numNodes;
111              }
112 void sort() {
113                int i;
114                numUniqNodes();
115                bynodes = new CkVec<int>[numNodes];
116                for (i=0; i<CmiNumPes(); i++) 
117                  bynodes[nodenum[i]].push_back(i);
118              }
119 void print() {
120                int i;
121                CmiPrintf("Charm++> Cpu topology info:\n");
122                for (i=0; i<CmiNumPes(); i++) CmiPrintf("%d ", nodenum[i]);
123                CmiPrintf("\n");
124                for (i=0; i<numNodes; i++) {
125                  CmiPrintf("Chip #%d: ", i);
126                  for (int j=0; j<bynodes[i].size(); j++) CmiPrintf("%d ", bynodes[i][j]);
127                  CmiPrintf("\n");
128                }
129              }
130 };
131
132 int *CpuTopology::nodenum = NULL;
133 int CpuTopology::numNodes = 0;
134 CkVec<int> *CpuTopology::bynodes = NULL;
135
136 static CpuTopology cpuTopo;
137 static CmiNodeLock topoLock;
138
139 /* called on PE 0 */
140 static void cpuTopoHandler(void *m)
141 {
142   static int count = 0;
143   static int nodecount = 0;
144   hostnameMsg *rec;
145   hostnameMsg *msg = (hostnameMsg *)m;
146   hostnameMsg *tmpm;
147   char str[128];
148   int tag, tag1, pe, myrank;
149   CmiAssert(topomsg != NULL);
150
151 /*   for debug
152   skt_print_ip(str, msg->ip);
153   printf("hostname: %d %s\n", msg->pe, str);
154 */
155   tag = *(int*)&msg->ip;
156   pe = msg->pe;
157   if ((rec = (hostnameMsg *)CmmProbe(hostTable, 1, &tag, &tag1)) != NULL) {
158     CmiFree(msg);
159   }
160   else {
161     msg->nodenum = nodecount++;
162     rec = msg;
163     CmmPut(hostTable, 1, &tag, msg);
164   }
165   myrank = rec->rank%rec->ncores;
166   topomsg->nodes[pe] = rec->nodenum;
167   rec->rank ++;
168   count ++;
169   if (count == CmiNumPes()) {
170     CmiPrintf("Charm++> %d unique compute nodes detected! \n", CmmEntries(hostTable));
171     //hostnameMsg *tmpm;
172     tag = CmmWildCard;
173     while (tmpm = (hostnameMsg *)CmmGet(hostTable, 1, &tag, &tag1)) CmiFree(tmpm);
174     CmmFree(hostTable);
175     CmiSyncBroadcastAllAndFree(sizeof(nodeTopoMsg)+CmiNumPes()*sizeof(int), (char *)topomsg);
176   }
177 }
178
179 /* called on each processor */
180 static void cpuTopoRecvHandler(void *msg)
181 {
182   int myrank;
183   nodeTopoMsg *m = (nodeTopoMsg *)msg;
184   m->nodes = (int *)((char*)m + sizeof(nodeTopoMsg));
185
186   CmiLock(topoLock);
187   if (cpuTopo.nodenum == NULL) {
188     cpuTopo.nodenum = m->nodes;
189     cpuTopo.sort();
190   }
191   else
192     CmiFree(m);
193   CmiUnlock(topoLock);
194
195   // if (CmiMyPe() == 0) cpuTopo.print();
196 }
197
198
199 extern "C" int CmiOnSamePhysicalNode(int pe1, int pe2)
200 {
201   int *nodenum = cpuTopo.nodenum;
202   return nodenum==NULL?-1:nodenum[pe1] == nodenum[pe2];
203 }
204
205 extern "C" int CmiNumPhysicalNodes()
206 {
207   return cpuTopo.numUniqNodes();
208 }
209
210 extern "C" int CmiNumPesOnPhysicalNode(int pe)
211 {
212   return cpuTopo.bynodes==NULL?-1:cpuTopo.bynodes[cpuTopo.nodenum[pe]].size();
213 }
214
215 extern "C" void CmiGetPesOnPhysicalNode(int pe, int **pelist, int *num)
216 {
217   CmiAssert(pe >=0 && pe < CmiNumPes());
218   *num = cpuTopo.numUniqNodes();
219   if (pelist!=NULL && *num>0) *pelist = cpuTopo.bynodes[cpuTopo.nodenum[pe]].getVec();
220 }
221
222 #if CMK_CRAYXT
223 extern int getXTNodeID(int mype, int numpes);
224 #endif
225
226 extern "C" void CmiInitCPUTopology(char **argv)
227 {
228   static skt_ip_t myip;
229   int ret, i;
230   hostnameMsg  *msg;
231  
232   if (CmiMyRank() ==0) {
233      topoLock = CmiCreateLock();
234   }
235
236   int obtain_flag = CmiGetArgFlagDesc(argv,"+obtain_cpu_topology",
237                                                 "obtain cpu topology info");
238   obtain_flag = 1;
239
240   cpuTopoHandlerIdx =
241      CmiRegisterHandler((CmiHandler)cpuTopoHandler);
242   cpuTopoRecvHandlerIdx =
243      CmiRegisterHandler((CmiHandler)cpuTopoRecvHandler);
244
245   if (!obtain_flag) return;
246   else if (CmiMyPe() == 0) {
247      CmiPrintf("Charm++> cpu topology info is being gathered! \n");
248   }
249
250   if (CmiMyPe() >= CmiNumPes()) {
251       /* comm thread either can float around, or pin down to the last rank.
252          however it seems to be reportedly slower if it is floating */
253     CmiNodeAllBarrier();
254     return;    /* comm thread return */
255   }
256
257 #if 0
258   if (gethostname(hostname, 999)!=0) {
259       strcpy(hostname, "");
260   }
261 #endif
262
263     /* get my ip address */
264   if (CmiMyRank() == 0)
265   {
266 #if CMK_CRAYXT
267     ret = getXTNodeID(CmiMyPe(), CmiNumPes());
268     memcpy(&myip, &ret, sizeof(int));
269 #elif CMK_HAS_GETHOSTNAME
270     myip = skt_my_ip();        /* not thread safe, so only calls on rank 0 */
271 #else
272     CmiAbort("Can not get unique name for the compute nodes. \n");
273 #endif
274   }
275   CmiNodeAllBarrier();
276
277     /* prepare a msg to send */
278   msg = (hostnameMsg *)CmiAlloc(sizeof(hostnameMsg));
279   CmiSetHandler((char *)msg, cpuTopoHandlerIdx);
280   msg->pe = CmiMyPe();
281   msg->ip = myip;
282   msg->ncores = CmiNumCores();
283   msg->rank = 0;
284   CmiSyncSendAndFree(0, sizeof(hostnameMsg), (char *)msg);
285
286   if (CmiMyPe() == 0) {
287     int i;
288     hostTable = CmmNew();
289     topomsg = (nodeTopoMsg *)CmiAlloc(sizeof(nodeTopoMsg)+CmiNumPes()*sizeof(int));
290     CmiSetHandler((char *)topomsg, cpuTopoRecvHandlerIdx);
291     topomsg->nodes = (int *)((char*)topomsg + sizeof(nodeTopoMsg));
292     for (i=0; i<CmiNumPes(); i++) topomsg->nodes[i] = -1;
293     CsdScheduleCount(CmiNumPes());
294   }
295
296     // receive broadcast from PE 0
297   CsdScheduleCount(1);
298
299     // now every one should have the node info
300 }
301
302 #else           /* not supporting affinity */
303
304
305 extern "C" void CmiInitCPUTopology(char **argv)
306 {
307   /* do nothing */
308   int obtain_flag = CmiGetArgFlagDesc(argv,"+obtain_cpu_topology",
309                                                 "obtain cpu topology info");
310 }
311
312 #endif