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