root/opal/mca/hwloc/hwloc201/hwloc/hwloc/topology-darwin.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hwloc_look_darwin
  2. hwloc_set_darwin_hooks
  3. hwloc_darwin_component_instantiate

   1 /*
   2  * Copyright © 2009 CNRS
   3  * Copyright © 2009-2018 Inria.  All rights reserved.
   4  * Copyright © 2009-2013 Université Bordeaux
   5  * Copyright © 2009-2011 Cisco Systems, Inc.  All rights reserved.
   6  * See COPYING in top-level directory.
   7  */
   8 
   9 /* Detect topology change: registering for power management changes and check
  10  * if for example hw.activecpu changed */
  11 
  12 /* Apparently, Darwin people do not _want_ to provide binding functions.  */
  13 
  14 #include <private/autogen/config.h>
  15 
  16 #include <sys/types.h>
  17 #include <sys/sysctl.h>
  18 #include <stdlib.h>
  19 #include <inttypes.h>
  20 
  21 #include <hwloc.h>
  22 #include <private/private.h>
  23 #include <private/debug.h>
  24 
  25 static int
  26 hwloc_look_darwin(struct hwloc_backend *backend)
  27 {
  28   struct hwloc_topology *topology = backend->topology;
  29   int64_t _nprocs;
  30   unsigned nprocs;
  31   int64_t _npackages;
  32   unsigned i, j, cpu;
  33   struct hwloc_obj *obj;
  34   size_t size;
  35   int64_t l1dcachesize, l1icachesize;
  36   int64_t cacheways[2];
  37   int64_t l2cachesize;
  38   int64_t l3cachesize;
  39   int64_t cachelinesize;
  40   int64_t memsize;
  41   int64_t _tmp;
  42   char cpumodel[64];
  43   char cpuvendor[64];
  44   char cpufamilynumber[20], cpumodelnumber[20], cpustepping[20];
  45   int gotnuma = 0;
  46   int gotnumamemory = 0;
  47 
  48   if (topology->levels[0][0]->cpuset)
  49     /* somebody discovered things */
  50     return -1;
  51 
  52   hwloc_alloc_root_sets(topology->levels[0][0]);
  53 
  54   /* Don't use hwloc_fallback_nbprocessors() because it would return online cpus only,
  55    * while we need all cpus when computing logical_per_package, etc below.
  56    * We don't know which CPUs are offline, but Darwin doesn't support binding anyway.
  57    *
  58    * TODO: try hw.logicalcpu_max
  59    */
  60 
  61   if (hwloc_get_sysctlbyname("hw.logicalcpu", &_nprocs) || _nprocs <= 0)
  62     /* fallback to deprecated way */
  63     if (hwloc_get_sysctlbyname("hw.ncpu", &_nprocs) || _nprocs <= 0)
  64       return -1;
  65 
  66   nprocs = _nprocs;
  67   topology->support.discovery->pu = 1;
  68 
  69   hwloc_debug("%u procs\n", nprocs);
  70 
  71   size = sizeof(cpuvendor);
  72   if (sysctlbyname("machdep.cpu.vendor", cpuvendor, &size, NULL, 0))
  73     cpuvendor[0] = '\0';
  74 
  75   size = sizeof(cpumodel);
  76   if (sysctlbyname("machdep.cpu.brand_string", cpumodel, &size, NULL, 0))
  77     cpumodel[0] = '\0';
  78 
  79   if (hwloc_get_sysctlbyname("machdep.cpu.family", &_tmp))
  80     cpufamilynumber[0] = '\0';
  81   else
  82     snprintf(cpufamilynumber, sizeof(cpufamilynumber), "%lld", (long long) _tmp);
  83   if (hwloc_get_sysctlbyname("machdep.cpu.model", &_tmp))
  84     cpumodelnumber[0] = '\0';
  85   else
  86     snprintf(cpumodelnumber, sizeof(cpumodelnumber), "%lld", (long long) _tmp);
  87   /* .extfamily and .extmodel are already added to .family and .model */
  88   if (hwloc_get_sysctlbyname("machdep.cpu.stepping", &_tmp))
  89     cpustepping[0] = '\0';
  90   else
  91     snprintf(cpustepping, sizeof(cpustepping), "%lld", (long long) _tmp);
  92 
  93   if (!hwloc_get_sysctlbyname("hw.packages", &_npackages) && _npackages > 0) {
  94     unsigned npackages = _npackages;
  95     int64_t _cores_per_package;
  96     unsigned cores_per_package;
  97     int64_t _logical_per_package;
  98     unsigned logical_per_package;
  99 
 100     hwloc_debug("%u packages\n", npackages);
 101 
 102     if (!hwloc_get_sysctlbyname("machdep.cpu.thread_count", &_logical_per_package) && _logical_per_package > 0)
 103       /* official/modern way */
 104       logical_per_package = _logical_per_package;
 105     else if (!hwloc_get_sysctlbyname("machdep.cpu.logical_per_package", &_logical_per_package) && _logical_per_package > 0)
 106       /* old way, gives the max supported by this "kind" of processor,
 107        * can be larger than the actual number for this model.
 108        */
 109       logical_per_package = _logical_per_package;
 110     else
 111       /* Assume the trivia.  */
 112       logical_per_package = nprocs / npackages;
 113 
 114     hwloc_debug("%u threads per package\n", logical_per_package);
 115 
 116     if (nprocs == npackages * logical_per_package
 117         && hwloc_filter_check_keep_object_type(topology, HWLOC_OBJ_PACKAGE))
 118       for (i = 0; i < npackages; i++) {
 119         obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_PACKAGE, i);
 120         obj->cpuset = hwloc_bitmap_alloc();
 121         for (cpu = i*logical_per_package; cpu < (i+1)*logical_per_package; cpu++)
 122           hwloc_bitmap_set(obj->cpuset, cpu);
 123 
 124         hwloc_debug_1arg_bitmap("package %u has cpuset %s\n",
 125                    i, obj->cpuset);
 126 
 127         if (cpuvendor[0] != '\0')
 128           hwloc_obj_add_info(obj, "CPUVendor", cpuvendor);
 129         if (cpumodel[0] != '\0')
 130           hwloc_obj_add_info(obj, "CPUModel", cpumodel);
 131         if (cpufamilynumber[0] != '\0')
 132           hwloc_obj_add_info(obj, "CPUFamilyNumber", cpufamilynumber);
 133         if (cpumodelnumber[0] != '\0')
 134           hwloc_obj_add_info(obj, "CPUModelNumber", cpumodelnumber);
 135         if (cpustepping[0] != '\0')
 136           hwloc_obj_add_info(obj, "CPUStepping", cpustepping);
 137 
 138         hwloc_insert_object_by_cpuset(topology, obj);
 139       }
 140     else {
 141       if (cpuvendor[0] != '\0')
 142         hwloc_obj_add_info(topology->levels[0][0], "CPUVendor", cpuvendor);
 143       if (cpumodel[0] != '\0')
 144         hwloc_obj_add_info(topology->levels[0][0], "CPUModel", cpumodel);
 145       if (cpufamilynumber[0] != '\0')
 146         hwloc_obj_add_info(topology->levels[0][0], "CPUFamilyNumber", cpufamilynumber);
 147       if (cpumodelnumber[0] != '\0')
 148         hwloc_obj_add_info(topology->levels[0][0], "CPUModelNumber", cpumodelnumber);
 149       if (cpustepping[0] != '\0')
 150         hwloc_obj_add_info(topology->levels[0][0], "CPUStepping", cpustepping);
 151     }
 152 
 153     if (!hwloc_get_sysctlbyname("machdep.cpu.core_count", &_cores_per_package) && _cores_per_package > 0)
 154       /* official/modern way */
 155       cores_per_package = _cores_per_package;
 156     else if (!hwloc_get_sysctlbyname("machdep.cpu.cores_per_package", &_cores_per_package) && _cores_per_package > 0)
 157       /* old way, gives the max supported by this "kind" of processor,
 158        * can be larger than the actual number for this model.
 159        */
 160       cores_per_package = _cores_per_package;
 161     else
 162       /* no idea */
 163       cores_per_package = 0;
 164 
 165     if (cores_per_package > 0
 166         && hwloc_filter_check_keep_object_type(topology, HWLOC_OBJ_CORE)) {
 167       hwloc_debug("%u cores per package\n", cores_per_package);
 168 
 169       if (!(logical_per_package % cores_per_package))
 170         for (i = 0; i < npackages * cores_per_package; i++) {
 171           obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_CORE, i);
 172           obj->cpuset = hwloc_bitmap_alloc();
 173           for (cpu = i*(logical_per_package/cores_per_package);
 174                cpu < (i+1)*(logical_per_package/cores_per_package);
 175                cpu++)
 176             hwloc_bitmap_set(obj->cpuset, cpu);
 177 
 178           hwloc_debug_1arg_bitmap("core %u has cpuset %s\n",
 179                      i, obj->cpuset);
 180           hwloc_insert_object_by_cpuset(topology, obj);
 181         }
 182     }
 183   } else {
 184     if (cpuvendor[0] != '\0')
 185       hwloc_obj_add_info(topology->levels[0][0], "CPUVendor", cpuvendor);
 186     if (cpumodel[0] != '\0')
 187       hwloc_obj_add_info(topology->levels[0][0], "CPUModel", cpumodel);
 188     if (cpufamilynumber[0] != '\0')
 189       hwloc_obj_add_info(topology->levels[0][0], "CPUFamilyNumber", cpufamilynumber);
 190     if (cpumodelnumber[0] != '\0')
 191       hwloc_obj_add_info(topology->levels[0][0], "CPUModelNumber", cpumodelnumber);
 192     if (cpustepping[0] != '\0')
 193       hwloc_obj_add_info(topology->levels[0][0], "CPUStepping", cpustepping);
 194   }
 195 
 196   if (hwloc_get_sysctlbyname("hw.l1dcachesize", &l1dcachesize))
 197     l1dcachesize = 0;
 198 
 199   if (hwloc_get_sysctlbyname("hw.l1icachesize", &l1icachesize))
 200     l1icachesize = 0;
 201 
 202   if (hwloc_get_sysctlbyname("hw.l2cachesize", &l2cachesize))
 203     l2cachesize = 0;
 204 
 205   if (hwloc_get_sysctlbyname("hw.l3cachesize", &l3cachesize))
 206     l3cachesize = 0;
 207 
 208   if (hwloc_get_sysctlbyname("machdep.cpu.cache.L1_associativity", &cacheways[0]))
 209     cacheways[0] = 0;
 210   else if (cacheways[0] == 0xff)
 211     cacheways[0] = -1;
 212 
 213   if (hwloc_get_sysctlbyname("machdep.cpu.cache.L2_associativity", &cacheways[1]))
 214     cacheways[1] = 0;
 215   else if (cacheways[1] == 0xff)
 216     cacheways[1] = -1;
 217 
 218   if (hwloc_get_sysctlbyname("hw.cachelinesize", &cachelinesize))
 219     cachelinesize = 0;
 220 
 221   if (hwloc_get_sysctlbyname("hw.memsize", &memsize))
 222     memsize = 0;
 223 
 224   if (!sysctlbyname("hw.cacheconfig", NULL, &size, NULL, 0)) {
 225     unsigned n = size / sizeof(uint32_t);
 226     uint64_t cacheconfig[n];
 227     uint64_t cachesize[n];
 228     uint32_t cacheconfig32[n];
 229 
 230     if ((!sysctlbyname("hw.cacheconfig", cacheconfig, &size, NULL, 0))) {
 231       /* Yeech. Darwin seemingly has changed from 32bit to 64bit integers for
 232        * cacheconfig, with apparently no way for detection. Assume the machine
 233        * won't have more than 4 billion cpus */
 234       if (cacheconfig[0] > 0xFFFFFFFFUL) {
 235         memcpy(cacheconfig32, cacheconfig, size);
 236         for (i = 0 ; i < size / sizeof(uint32_t); i++)
 237           cacheconfig[i] = cacheconfig32[i];
 238       }
 239 
 240       memset(cachesize, 0, sizeof(uint64_t) * n);
 241       size = sizeof(uint64_t) * n;
 242       if (sysctlbyname("hw.cachesize", cachesize, &size, NULL, 0)) {
 243         if (n > 0)
 244           cachesize[0] = memsize;
 245         if (n > 1)
 246           cachesize[1] = l1dcachesize;
 247         if (n > 2)
 248           cachesize[2] = l2cachesize;
 249         if (n > 3)
 250           cachesize[3] = l3cachesize;
 251       }
 252 
 253       hwloc_debug("%s", "caches");
 254       for (i = 0; i < n && cacheconfig[i]; i++)
 255         hwloc_debug(" %"PRIu64"(%"PRIu64"kB)", cacheconfig[i], cachesize[i] / 1024);
 256 
 257       /* Now we know how many caches there are */
 258       n = i;
 259       hwloc_debug("\n%u cache levels\n", n - 1);
 260 
 261       /* For each cache level (0 is memory) */
 262       for (i = 0; i < n; i++) {
 263         /* cacheconfig tells us how many cpus share it, let's iterate on each cache */
 264         for (j = 0; j < (nprocs / cacheconfig[i]); j++) {
 265           if (!i) {
 266             obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_NUMANODE, j);
 267             obj->nodeset = hwloc_bitmap_alloc();
 268             hwloc_bitmap_set(obj->nodeset, j);
 269             gotnuma++;
 270           } else {
 271             obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_L1CACHE+i-1, HWLOC_UNKNOWN_INDEX);
 272           }
 273           obj->cpuset = hwloc_bitmap_alloc();
 274           for (cpu = j*cacheconfig[i];
 275                cpu < ((j+1)*cacheconfig[i]);
 276                cpu++)
 277             hwloc_bitmap_set(obj->cpuset, cpu);
 278 
 279           if (i == 1 && l1icachesize
 280               && hwloc_filter_check_keep_object_type(topology, HWLOC_OBJ_L1ICACHE)) {
 281             /* FIXME assuming that L1i and L1d are shared the same way. Darwin
 282              * does not yet provide a way to know.  */
 283             hwloc_obj_t l1i = hwloc_alloc_setup_object(topology, HWLOC_OBJ_L1ICACHE, HWLOC_UNKNOWN_INDEX);
 284             l1i->cpuset = hwloc_bitmap_dup(obj->cpuset);
 285             hwloc_debug_1arg_bitmap("L1icache %u has cpuset %s\n",
 286                 j, l1i->cpuset);
 287             l1i->attr->cache.depth = i;
 288             l1i->attr->cache.size = l1icachesize;
 289             l1i->attr->cache.linesize = cachelinesize;
 290             l1i->attr->cache.associativity = 0;
 291             l1i->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION;
 292 
 293             hwloc_insert_object_by_cpuset(topology, l1i);
 294           }
 295           if (i) {
 296             hwloc_debug_2args_bitmap("L%ucache %u has cpuset %s\n",
 297                 i, j, obj->cpuset);
 298             obj->attr->cache.depth = i;
 299             obj->attr->cache.size = cachesize[i];
 300             obj->attr->cache.linesize = cachelinesize;
 301             if (i <= sizeof(cacheways) / sizeof(cacheways[0]))
 302               obj->attr->cache.associativity = cacheways[i-1];
 303             else
 304               obj->attr->cache.associativity = 0;
 305             if (i == 1 && l1icachesize)
 306               obj->attr->cache.type = HWLOC_OBJ_CACHE_DATA;
 307             else
 308               obj->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED;
 309           } else {
 310             hwloc_debug_1arg_bitmap("node %u has cpuset %s\n",
 311                 j, obj->cpuset);
 312             if (cachesize[i]) {
 313               obj->attr->numanode.local_memory = cachesize[i];
 314               gotnumamemory++;
 315             }
 316             obj->attr->numanode.page_types_len = 2;
 317             obj->attr->numanode.page_types = malloc(2*sizeof(*obj->attr->numanode.page_types));
 318             memset(obj->attr->numanode.page_types, 0, 2*sizeof(*obj->attr->numanode.page_types));
 319             obj->attr->numanode.page_types[0].size = hwloc_getpagesize();
 320 #if HAVE_DECL__SC_LARGE_PAGESIZE
 321             obj->attr->numanode.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE);
 322 #endif
 323           }
 324 
 325           if (hwloc_filter_check_keep_object_type(topology, obj->type))
 326             hwloc_insert_object_by_cpuset(topology, obj);
 327           else
 328             hwloc_free_unlinked_object(obj); /* FIXME: don't built at all, just build the cpuset in case l1i needs it */
 329         }
 330       }
 331     }
 332   }
 333 
 334   if (gotnuma)
 335     topology->support.discovery->numa = 1;
 336   if (gotnumamemory)
 337     topology->support.discovery->numa = 1;
 338 
 339   /* add PU objects */
 340   hwloc_setup_pu_level(topology, nprocs);
 341 
 342   hwloc_obj_add_info(topology->levels[0][0], "Backend", "Darwin");
 343   hwloc_add_uname_info(topology, NULL);
 344   return 0;
 345 }
 346 
 347 void
 348 hwloc_set_darwin_hooks(struct hwloc_binding_hooks *hooks __hwloc_attribute_unused,
 349                        struct hwloc_topology_support *support __hwloc_attribute_unused)
 350 {
 351 }
 352 
 353 static struct hwloc_backend *
 354 hwloc_darwin_component_instantiate(struct hwloc_disc_component *component,
 355                                    const void *_data1 __hwloc_attribute_unused,
 356                                    const void *_data2 __hwloc_attribute_unused,
 357                                    const void *_data3 __hwloc_attribute_unused)
 358 {
 359   struct hwloc_backend *backend;
 360   backend = hwloc_backend_alloc(component);
 361   if (!backend)
 362     return NULL;
 363   backend->discover = hwloc_look_darwin;
 364   return backend;
 365 }
 366 
 367 static struct hwloc_disc_component hwloc_darwin_disc_component = {
 368   HWLOC_DISC_COMPONENT_TYPE_CPU,
 369   "darwin",
 370   HWLOC_DISC_COMPONENT_TYPE_GLOBAL,
 371   hwloc_darwin_component_instantiate,
 372   50,
 373   1,
 374   NULL
 375 };
 376 
 377 const struct hwloc_component hwloc_darwin_component = {
 378   HWLOC_COMPONENT_ABI,
 379   NULL, NULL,
 380   HWLOC_COMPONENT_TYPE_DISC,
 381   0,
 382   &hwloc_darwin_disc_component
 383 };

/* [<][>][^][v][top][bottom][index][help] */