/* * Copyright © 2009 CNRS * Copyright © 2009-2011 INRIA. All rights reserved. * Copyright © 2009-2011 Université Bordeaux 1 * Copyright © 2011 Cisco Systems, Inc. All rights reserved. * See COPYING in top-level directory. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBLGRP # include #endif /* TODO: use psets? (only for root) * TODO: get cache info from prtdiag? (it is setgid sys to be able to read from * crw-r----- 1 root sys 88, 0 nov 3 14:35 /devices/pseudo/devinfo@0:devinfo * and run (apparently undocumented) ioctls on it. */ static int hwloc_solaris_set_sth_cpubind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_const_bitmap_t hwloc_set, int flags) { unsigned target_cpu; /* The resulting binding is always strict */ if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) { if (processor_bind(idtype, id, PBIND_NONE, NULL) != 0) return -1; #ifdef HAVE_LIBLGRP if (!(flags & HWLOC_CPUBIND_NOMEMBIND)) { int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE); if (depth >= 0) { int n = hwloc_get_nbobjs_by_depth(topology, depth); int i; for (i = 0; i < n; i++) { hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_NONE); } } } #endif /* HAVE_LIBLGRP */ return 0; } #ifdef HAVE_LIBLGRP if (!(flags & HWLOC_CPUBIND_NOMEMBIND)) { int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE); if (depth >= 0) { int n = hwloc_get_nbobjs_by_depth(topology, depth); int i; int ok; hwloc_bitmap_t target = hwloc_bitmap_alloc(); for (i = 0; i < n; i++) { hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); if (hwloc_bitmap_isincluded(obj->cpuset, hwloc_set)) hwloc_bitmap_or(target, target, obj->cpuset); } ok = hwloc_bitmap_isequal(target, hwloc_set); hwloc_bitmap_free(target); if (ok) { /* Ok, managed to achieve hwloc_set by just combining NUMA nodes */ for (i = 0; i < n; i++) { hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); if (hwloc_bitmap_isincluded(obj->cpuset, hwloc_set)) { lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_STRONG); } else { if (flags & HWLOC_CPUBIND_STRICT) lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_NONE); else lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_WEAK); } } return 0; } } } #endif /* HAVE_LIBLGRP */ if (hwloc_bitmap_weight(hwloc_set) != 1) { errno = EXDEV; return -1; } target_cpu = hwloc_bitmap_first(hwloc_set); if (processor_bind(idtype, id, (processorid_t) (target_cpu), NULL) != 0) return -1; return 0; } static int hwloc_solaris_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags) { return hwloc_solaris_set_sth_cpubind(topology, P_PID, pid, hwloc_set, flags); } static int hwloc_solaris_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) { return hwloc_solaris_set_sth_cpubind(topology, P_PID, P_MYID, hwloc_set, flags); } static int hwloc_solaris_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) { return hwloc_solaris_set_sth_cpubind(topology, P_LWPID, P_MYID, hwloc_set, flags); } #ifdef HAVE_LIBLGRP static int hwloc_solaris_get_sth_cpubind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) { int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE); int n; int i; if (depth < 0) { errno = ENOSYS; return -1; } hwloc_bitmap_zero(hwloc_set); n = hwloc_get_nbobjs_by_depth(topology, depth); for (i = 0; i < n; i++) { hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); lgrp_affinity_t aff = lgrp_affinity_get(idtype, id, obj->os_index); if (aff == LGRP_AFF_STRONG) hwloc_bitmap_or(hwloc_set, hwloc_set, obj->cpuset); } if (hwloc_bitmap_iszero(hwloc_set)) hwloc_bitmap_copy(hwloc_set, hwloc_topology_get_complete_cpuset(topology)); return 0; } static int hwloc_solaris_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_set, int flags) { return hwloc_solaris_get_sth_cpubind(topology, P_PID, pid, hwloc_set, flags); } static int hwloc_solaris_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) { return hwloc_solaris_get_sth_cpubind(topology, P_PID, P_MYID, hwloc_set, flags); } static int hwloc_solaris_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) { return hwloc_solaris_get_sth_cpubind(topology, P_LWPID, P_MYID, hwloc_set, flags); } #endif /* HAVE_LIBLGRP */ /* TODO: given thread, probably not easy because of the historical n:m implementation */ #ifdef HAVE_LIBLGRP static int hwloc_solaris_set_sth_membind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { int depth; int n, i; switch (policy) { case HWLOC_MEMBIND_DEFAULT: case HWLOC_MEMBIND_BIND: break; default: errno = ENOSYS; return -1; } if (flags & HWLOC_MEMBIND_NOCPUBIND) { errno = ENOSYS; return -1; } depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE); if (depth < 0) { errno = EXDEV; return -1; } n = hwloc_get_nbobjs_by_depth(topology, depth); for (i = 0; i < n; i++) { hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); if (hwloc_bitmap_isset(nodeset, obj->os_index)) { lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_STRONG); } else { if (flags & HWLOC_CPUBIND_STRICT) lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_NONE); else lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_WEAK); } } return 0; } static int hwloc_solaris_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { return hwloc_solaris_set_sth_membind(topology, P_PID, pid, nodeset, policy, flags); } static int hwloc_solaris_set_thisproc_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { return hwloc_solaris_set_sth_membind(topology, P_PID, P_MYID, nodeset, policy, flags); } static int hwloc_solaris_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { return hwloc_solaris_set_sth_membind(topology, P_LWPID, P_MYID, nodeset, policy, flags); } static int hwloc_solaris_get_sth_membind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags __hwloc_attribute_unused) { int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE); int n; int i; if (depth < 0) { errno = ENOSYS; return -1; } hwloc_bitmap_zero(nodeset); n = hwloc_get_nbobjs_by_depth(topology, depth); for (i = 0; i < n; i++) { hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); lgrp_affinity_t aff = lgrp_affinity_get(idtype, id, obj->os_index); if (aff == LGRP_AFF_STRONG) hwloc_bitmap_set(nodeset, obj->os_index); } if (hwloc_bitmap_iszero(nodeset)) hwloc_bitmap_copy(nodeset, hwloc_topology_get_complete_nodeset(topology)); *policy = HWLOC_MEMBIND_DEFAULT; return 0; } static int hwloc_solaris_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags) { return hwloc_solaris_get_sth_membind(topology, P_PID, pid, nodeset, policy, flags); } static int hwloc_solaris_get_thisproc_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags) { return hwloc_solaris_get_sth_membind(topology, P_PID, P_MYID, nodeset, policy, flags); } static int hwloc_solaris_get_thisthread_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags) { return hwloc_solaris_get_sth_membind(topology, P_LWPID, P_MYID, nodeset, policy, flags); } #endif /* HAVE_LIBLGRP */ #ifdef MADV_ACCESS_LWP static int hwloc_solaris_set_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags __hwloc_attribute_unused) { int advice; size_t remainder; /* Can not give a set of nodes just for an area. */ if (!hwloc_bitmap_isequal(nodeset, hwloc_topology_get_complete_nodeset(topology))) { errno = EXDEV; return -1; } switch (policy) { case HWLOC_MEMBIND_DEFAULT: case HWLOC_MEMBIND_BIND: advice = MADV_ACCESS_DEFAULT; break; case HWLOC_MEMBIND_FIRSTTOUCH: case HWLOC_MEMBIND_NEXTTOUCH: advice = MADV_ACCESS_LWP; break; case HWLOC_MEMBIND_INTERLEAVE: advice = MADV_ACCESS_MANY; break; default: errno = ENOSYS; return -1; } remainder = (uintptr_t) addr & (sysconf(_SC_PAGESIZE)-1); addr = (char*) addr - remainder; len += remainder; return madvise((void*) addr, len, advice); } #endif #ifdef HAVE_LIBLGRP static void browse(struct hwloc_topology *topology, lgrp_cookie_t cookie, lgrp_id_t lgrp, hwloc_obj_t *glob_lgrps, unsigned *curlgrp) { int n; hwloc_obj_t obj; lgrp_mem_size_t mem_size; n = lgrp_cpus(cookie, lgrp, NULL, 0, LGRP_CONTENT_HIERARCHY); if (n == -1) return; /* Is this lgrp a NUMA node? */ if ((mem_size = lgrp_mem_size(cookie, lgrp, LGRP_MEM_SZ_INSTALLED, LGRP_CONTENT_DIRECT)) > 0) { int i; processorid_t *cpuids; cpuids = malloc(sizeof(processorid_t) * n); assert(cpuids != NULL); obj = hwloc_alloc_setup_object(HWLOC_OBJ_NODE, lgrp); obj->nodeset = hwloc_bitmap_alloc(); hwloc_bitmap_set(obj->nodeset, lgrp); obj->cpuset = hwloc_bitmap_alloc(); glob_lgrps[(*curlgrp)++] = obj; lgrp_cpus(cookie, lgrp, cpuids, n, LGRP_CONTENT_HIERARCHY); for (i = 0; i < n ; i++) { hwloc_debug("node %ld's cpu %d is %d\n", lgrp, i, cpuids[i]); hwloc_bitmap_set(obj->cpuset, cpuids[i]); } hwloc_debug_1arg_bitmap("node %ld has cpuset %s\n", lgrp, obj->cpuset); /* or LGRP_MEM_SZ_FREE */ hwloc_debug("node %ld has %lldkB\n", lgrp, mem_size/1024); obj->memory.local_memory = mem_size; obj->memory.page_types_len = 2; obj->memory.page_types = malloc(2*sizeof(*obj->memory.page_types)); memset(obj->memory.page_types, 0, 2*sizeof(*obj->memory.page_types)); obj->memory.page_types[0].size = getpagesize(); #ifdef HAVE__SC_LARGE_PAGESIZE obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); #endif hwloc_insert_object_by_cpuset(topology, obj); free(cpuids); } n = lgrp_children(cookie, lgrp, NULL, 0); { lgrp_id_t *lgrps; int i; lgrps = malloc(sizeof(lgrp_id_t) * n); assert(lgrps != NULL); lgrp_children(cookie, lgrp, lgrps, n); hwloc_debug("lgrp %ld has %d children\n", lgrp, n); for (i = 0; i < n ; i++) { browse(topology, cookie, lgrps[i], glob_lgrps, curlgrp); } hwloc_debug("lgrp %ld's children done\n", lgrp); free(lgrps); } } static void hwloc_look_lgrp(struct hwloc_topology *topology) { lgrp_cookie_t cookie; unsigned curlgrp = 0; int nlgrps; lgrp_id_t root; if ((topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM)) cookie = lgrp_init(LGRP_VIEW_OS); else cookie = lgrp_init(LGRP_VIEW_CALLER); if (cookie == LGRP_COOKIE_NONE) { hwloc_debug("lgrp_init failed: %s\n", strerror(errno)); return; } nlgrps = lgrp_nlgrps(cookie); root = lgrp_root(cookie); { hwloc_obj_t *glob_lgrps = calloc(nlgrps, sizeof(hwloc_obj_t)); browse(topology, cookie, root, glob_lgrps, &curlgrp); #ifdef HAVE_LGRP_LATENCY_COOKIE { float *distances = calloc(curlgrp*curlgrp, sizeof(float)); unsigned *indexes = calloc(curlgrp,sizeof(unsigned)); unsigned i, j; for (i = 0; i < curlgrp; i++) { indexes[i] = glob_lgrps[i]->os_index; for (j = 0; j < curlgrp; j++) distances[i*curlgrp+j] = (float) lgrp_latency_cookie(cookie, glob_lgrps[i]->os_index, glob_lgrps[j]->os_index, LGRP_LAT_CPU_TO_MEM); } hwloc_topology__set_distance_matrix(topology, HWLOC_OBJ_NODE, curlgrp, indexes, glob_lgrps, distances); } #endif /* HAVE_LGRP_LATENCY_COOKIE */ } lgrp_fini(cookie); } #endif /* LIBLGRP */ #ifdef HAVE_LIBKSTAT #include #define HWLOC_NBMAXCPUS 1024 /* FIXME: drop */ static int hwloc_look_kstat(struct hwloc_topology *topology) { kstat_ctl_t *kc = kstat_open(); kstat_t *ksp; kstat_named_t *stat; unsigned look_cores = 1, look_chips = 1; unsigned numsockets = 0; unsigned proc_physids[HWLOC_NBMAXCPUS]; unsigned proc_osphysids[HWLOC_NBMAXCPUS]; unsigned osphysids[HWLOC_NBMAXCPUS]; unsigned numcores = 0; unsigned proc_coreids[HWLOC_NBMAXCPUS]; unsigned oscoreids[HWLOC_NBMAXCPUS]; unsigned core_osphysids[HWLOC_NBMAXCPUS]; unsigned numprocs = 0; unsigned proc_procids[HWLOC_NBMAXCPUS]; unsigned osprocids[HWLOC_NBMAXCPUS]; unsigned physid, coreid, cpuid; unsigned procid_max = 0; unsigned i; for (cpuid = 0; cpuid < HWLOC_NBMAXCPUS; cpuid++) { proc_procids[cpuid] = -1; proc_physids[cpuid] = -1; proc_osphysids[cpuid] = -1; proc_coreids[cpuid] = -1; } if (!kc) { hwloc_debug("kstat_open failed: %s\n", strerror(errno)); return 0; } for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (strncmp("cpu_info", ksp->ks_module, 8)) continue; cpuid = ksp->ks_instance; if (cpuid > HWLOC_NBMAXCPUS) { fprintf(stderr,"CPU id too big: %u\n", cpuid); continue; } if (kstat_read(kc, ksp, NULL) == -1) { fprintf(stderr, "kstat_read failed for CPU%u: %s\n", cpuid, strerror(errno)); continue; } hwloc_debug("cpu%u\n", cpuid); proc_procids[cpuid] = numprocs; osprocids[numprocs] = cpuid; numprocs++; if (cpuid >= procid_max) procid_max = cpuid + 1; stat = (kstat_named_t *) kstat_data_lookup(ksp, "state"); if (!stat) hwloc_debug("could not read state for CPU%u: %s\n", cpuid, strerror(errno)); else if (stat->data_type != KSTAT_DATA_CHAR) hwloc_debug("unknown kstat type %d for cpu state\n", stat->data_type); else { hwloc_debug("cpu%u's state is %s\n", cpuid, stat->value.c); if (strcmp(stat->value.c, "on-line")) /* not online */ hwloc_bitmap_clr(topology->levels[0][0]->online_cpuset, cpuid); } if (look_chips) do { /* Get Chip ID */ stat = (kstat_named_t *) kstat_data_lookup(ksp, "chip_id"); if (!stat) { if (numsockets) fprintf(stderr, "could not read socket id for CPU%u: %s\n", cpuid, strerror(errno)); else hwloc_debug("could not read socket id for CPU%u: %s\n", cpuid, strerror(errno)); look_chips = 0; continue; } switch (stat->data_type) { case KSTAT_DATA_INT32: physid = stat->value.i32; break; case KSTAT_DATA_UINT32: physid = stat->value.ui32; break; #ifdef _INT64_TYPE case KSTAT_DATA_UINT64: physid = stat->value.ui64; break; case KSTAT_DATA_INT64: physid = stat->value.i64; break; #endif default: fprintf(stderr, "chip_id type %d unknown\n", stat->data_type); look_chips = 0; continue; } proc_osphysids[cpuid] = physid; for (i = 0; i < numsockets; i++) if (physid == osphysids[i]) break; proc_physids[cpuid] = i; hwloc_debug("%u on socket %u (%u)\n", cpuid, i, physid); if (i == numsockets) osphysids[numsockets++] = physid; } while(0); if (look_cores) do { /* Get Core ID */ stat = (kstat_named_t *) kstat_data_lookup(ksp, "core_id"); if (!stat) { if (numcores) fprintf(stderr, "could not read core id for CPU%u: %s\n", cpuid, strerror(errno)); else hwloc_debug("could not read core id for CPU%u: %s\n", cpuid, strerror(errno)); look_cores = 0; continue; } switch (stat->data_type) { case KSTAT_DATA_INT32: coreid = stat->value.i32; break; case KSTAT_DATA_UINT32: coreid = stat->value.ui32; break; #ifdef _INT64_TYPE case KSTAT_DATA_UINT64: coreid = stat->value.ui64; break; case KSTAT_DATA_INT64: coreid = stat->value.i64; break; #endif default: fprintf(stderr, "core_id type %d unknown\n", stat->data_type); look_cores = 0; continue; } for (i = 0; i < numcores; i++) if (coreid == oscoreids[i] && proc_osphysids[cpuid] == core_osphysids[i]) break; proc_coreids[cpuid] = i; hwloc_debug("%u on core %u (%u)\n", cpuid, i, coreid); if (i == numcores) { core_osphysids[numcores] = proc_osphysids[cpuid]; oscoreids[numcores++] = coreid; } } while(0); /* Note: there is also clog_id for the Thread ID (not unique) and * pkg_core_id for the core ID (not unique). They are not useful to us * however. */ } if (look_chips) hwloc_setup_level(procid_max, numsockets, osphysids, proc_physids, topology, HWLOC_OBJ_SOCKET); if (look_cores) hwloc_setup_level(procid_max, numcores, oscoreids, proc_coreids, topology, HWLOC_OBJ_CORE); if (numprocs) hwloc_setup_level(procid_max, numprocs, osprocids, proc_procids, topology, HWLOC_OBJ_PU); kstat_close(kc); return numprocs > 0; } #endif /* LIBKSTAT */ void hwloc_look_solaris(struct hwloc_topology *topology) { unsigned nbprocs = hwloc_fallback_nbprocessors (topology); #ifdef HAVE_LIBLGRP hwloc_look_lgrp(topology); #endif /* HAVE_LIBLGRP */ #ifdef HAVE_LIBKSTAT nbprocs = 0; if (hwloc_look_kstat(topology)) return; #endif /* HAVE_LIBKSTAT */ hwloc_setup_pu_level(topology, nbprocs); hwloc_add_object_info(topology->levels[0][0], "Backend", "Solaris"); } void hwloc_set_solaris_hooks(struct hwloc_topology *topology) { topology->set_proc_cpubind = hwloc_solaris_set_proc_cpubind; topology->set_thisproc_cpubind = hwloc_solaris_set_thisproc_cpubind; topology->set_thisthread_cpubind = hwloc_solaris_set_thisthread_cpubind; #ifdef HAVE_LIBLGRP topology->get_proc_cpubind = hwloc_solaris_get_proc_cpubind; topology->get_thisproc_cpubind = hwloc_solaris_get_thisproc_cpubind; topology->get_thisthread_cpubind = hwloc_solaris_get_thisthread_cpubind; topology->set_proc_membind = hwloc_solaris_set_proc_membind; topology->set_thisproc_membind = hwloc_solaris_set_thisproc_membind; topology->set_thisthread_membind = hwloc_solaris_set_thisthread_membind; topology->get_proc_membind = hwloc_solaris_get_proc_membind; topology->get_thisproc_membind = hwloc_solaris_get_thisproc_membind; topology->get_thisthread_membind = hwloc_solaris_get_thisthread_membind; #endif /* HAVE_LIBLGRP */ #ifdef MADV_ACCESS_LWP topology->set_area_membind = hwloc_solaris_set_area_membind; topology->support.membind->firsttouch_membind = 1; topology->support.membind->bind_membind = 1; topology->support.membind->interleave_membind = 1; topology->support.membind->nexttouch_membind = 1; #endif }