/* * Copyright © 2009 CNRS * Copyright © 2009-2011 INRIA. All rights reserved. * Copyright © 2009-2010 Université Bordeaux 1 * Copyright © 2011 Cisco Systems, Inc. All rights reserved. * See COPYING in top-level directory. */ #include #include #include #include #ifdef HAVE_SYS_MMAN_H # include #endif #ifdef HAVE_MALLOC_H # include #endif #include #include #include /* TODO: HWLOC_GNU_SYS, HWLOC_IRIX_SYS, * * IRIX: see MP_MUSTRUN / _DSM_MUSTRUN, pthread_setrunon_np, /hw, procss_cpulink, numa_create * * We could use glibc's sched_setaffinity generically when it is available * * Darwin and OpenBSD don't seem to have binding facilities. */ static hwloc_const_bitmap_t hwloc_fix_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t set) { hwloc_const_bitmap_t topology_set = hwloc_topology_get_topology_cpuset(topology); hwloc_const_bitmap_t complete_set = hwloc_topology_get_complete_cpuset(topology); if (!topology_set) { /* The topology is composed of several systems, the cpuset is ambiguous. */ errno = EXDEV; return NULL; } if (hwloc_bitmap_iszero(set)) { errno = EINVAL; return NULL; } if (!hwloc_bitmap_isincluded(set, complete_set)) { errno = EINVAL; return NULL; } if (hwloc_bitmap_isincluded(topology_set, set)) set = complete_set; return set; } int hwloc_set_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t set, int flags) { set = hwloc_fix_cpubind(topology, set); if (!set) return -1; if (flags & HWLOC_CPUBIND_PROCESS) { if (topology->set_thisproc_cpubind) return topology->set_thisproc_cpubind(topology, set, flags); } else if (flags & HWLOC_CPUBIND_THREAD) { if (topology->set_thisthread_cpubind) return topology->set_thisthread_cpubind(topology, set, flags); } else { if (topology->set_thisproc_cpubind) return topology->set_thisproc_cpubind(topology, set, flags); else if (topology->set_thisthread_cpubind) return topology->set_thisthread_cpubind(topology, set, flags); } errno = ENOSYS; return -1; } int hwloc_get_cpubind(hwloc_topology_t topology, hwloc_bitmap_t set, int flags) { if (flags & HWLOC_CPUBIND_PROCESS) { if (topology->get_thisproc_cpubind) return topology->get_thisproc_cpubind(topology, set, flags); } else if (flags & HWLOC_CPUBIND_THREAD) { if (topology->get_thisthread_cpubind) return topology->get_thisthread_cpubind(topology, set, flags); } else { if (topology->get_thisproc_cpubind) return topology->get_thisproc_cpubind(topology, set, flags); else if (topology->get_thisthread_cpubind) return topology->get_thisthread_cpubind(topology, set, flags); } errno = ENOSYS; return -1; } int hwloc_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t set, int flags) { set = hwloc_fix_cpubind(topology, set); if (!set) return -1; if (topology->set_proc_cpubind) return topology->set_proc_cpubind(topology, pid, set, flags); errno = ENOSYS; return -1; } int hwloc_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t set, int flags) { if (topology->get_proc_cpubind) return topology->get_proc_cpubind(topology, pid, set, flags); errno = ENOSYS; return -1; } #ifdef hwloc_thread_t int hwloc_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_const_bitmap_t set, int flags) { set = hwloc_fix_cpubind(topology, set); if (!set) return -1; if (topology->set_thread_cpubind) return topology->set_thread_cpubind(topology, tid, set, flags); errno = ENOSYS; return -1; } int hwloc_get_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_bitmap_t set, int flags) { if (topology->get_thread_cpubind) return topology->get_thread_cpubind(topology, tid, set, flags); errno = ENOSYS; return -1; } #endif int hwloc_get_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t set, int flags) { if (flags & HWLOC_CPUBIND_PROCESS) { if (topology->get_thisproc_last_cpu_location) return topology->get_thisproc_last_cpu_location(topology, set, flags); } else if (flags & HWLOC_CPUBIND_THREAD) { if (topology->get_thisthread_last_cpu_location) return topology->get_thisthread_last_cpu_location(topology, set, flags); } else { if (topology->get_thisproc_last_cpu_location) return topology->get_thisproc_last_cpu_location(topology, set, flags); else if (topology->get_thisthread_last_cpu_location) return topology->get_thisthread_last_cpu_location(topology, set, flags); } errno = ENOSYS; return -1; } int hwloc_get_proc_last_cpu_location(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t set, int flags) { if (topology->get_proc_last_cpu_location) return topology->get_proc_last_cpu_location(topology, pid, set, flags); errno = ENOSYS; return -1; } static hwloc_const_nodeset_t hwloc_fix_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset) { hwloc_const_bitmap_t topology_nodeset = hwloc_topology_get_topology_nodeset(topology); hwloc_const_bitmap_t complete_nodeset = hwloc_topology_get_complete_nodeset(topology); if (!hwloc_topology_get_topology_cpuset(topology)) { /* The topology is composed of several systems, the nodeset is thus * ambiguous. */ errno = EXDEV; return NULL; } if (!complete_nodeset) { /* There is no NUMA node */ errno = ENODEV; return NULL; } if (hwloc_bitmap_iszero(nodeset)) { errno = EINVAL; return NULL; } if (!hwloc_bitmap_isincluded(nodeset, complete_nodeset)) { errno = EINVAL; return NULL; } if (hwloc_bitmap_isincluded(topology_nodeset, nodeset)) return complete_nodeset; return nodeset; } static int hwloc_fix_membind_cpuset(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_const_cpuset_t cpuset) { hwloc_const_bitmap_t topology_set = hwloc_topology_get_topology_cpuset(topology); hwloc_const_bitmap_t complete_set = hwloc_topology_get_complete_cpuset(topology); hwloc_const_bitmap_t complete_nodeset = hwloc_topology_get_complete_nodeset(topology); if (!topology_set) { /* The topology is composed of several systems, the cpuset is thus * ambiguous. */ errno = EXDEV; return -1; } if (!complete_nodeset) { /* There is no NUMA node */ errno = ENODEV; return -1; } if (hwloc_bitmap_iszero(cpuset)) { errno = EINVAL; return -1; } if (!hwloc_bitmap_isincluded(cpuset, complete_set)) { errno = EINVAL; return -1; } if (hwloc_bitmap_isincluded(topology_set, cpuset)) { hwloc_bitmap_copy(nodeset, complete_nodeset); return 0; } hwloc_cpuset_to_nodeset(topology, cpuset, nodeset); return 0; } int hwloc_set_membind_nodeset(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { nodeset = hwloc_fix_membind(topology, nodeset); if (!nodeset) return -1; if (flags & HWLOC_MEMBIND_PROCESS) { if (topology->set_thisproc_membind) return topology->set_thisproc_membind(topology, nodeset, policy, flags); } else if (flags & HWLOC_MEMBIND_THREAD) { if (topology->set_thisthread_membind) return topology->set_thisthread_membind(topology, nodeset, policy, flags); } else { if (topology->set_thisproc_membind) return topology->set_thisproc_membind(topology, nodeset, policy, flags); else if (topology->set_thisthread_membind) return topology->set_thisthread_membind(topology, nodeset, policy, flags); } errno = ENOSYS; return -1; } int hwloc_set_membind(hwloc_topology_t topology, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) { hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); int ret; if (hwloc_fix_membind_cpuset(topology, nodeset, set)) ret = -1; else ret = hwloc_set_membind_nodeset(topology, nodeset, policy, flags); hwloc_bitmap_free(nodeset); return ret; } int hwloc_get_membind_nodeset(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) { if (flags & HWLOC_MEMBIND_PROCESS) { if (topology->get_thisproc_membind) return topology->get_thisproc_membind(topology, nodeset, policy, flags); } else if (flags & HWLOC_MEMBIND_THREAD) { if (topology->get_thisthread_membind) return topology->get_thisthread_membind(topology, nodeset, policy, flags); } else { if (topology->get_thisproc_membind) return topology->get_thisproc_membind(topology, nodeset, policy, flags); else if (topology->get_thisthread_membind) return topology->get_thisthread_membind(topology, nodeset, policy, flags); } errno = ENOSYS; return -1; } int hwloc_get_membind(hwloc_topology_t topology, hwloc_cpuset_t set, hwloc_membind_policy_t * policy, int flags) { hwloc_nodeset_t nodeset; int ret; nodeset = hwloc_bitmap_alloc(); ret = hwloc_get_membind_nodeset(topology, nodeset, policy, flags); if (!ret) hwloc_cpuset_from_nodeset(topology, set, nodeset); return ret; } int hwloc_set_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { nodeset = hwloc_fix_membind(topology, nodeset); if (!nodeset) return -1; if (topology->set_proc_membind) return topology->set_proc_membind(topology, pid, nodeset, policy, flags); errno = ENOSYS; return -1; } int hwloc_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) { hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); int ret; if (hwloc_fix_membind_cpuset(topology, nodeset, set)) ret = -1; else ret = hwloc_set_proc_membind_nodeset(topology, pid, nodeset, policy, flags); hwloc_bitmap_free(nodeset); return ret; } int hwloc_get_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) { if (topology->get_proc_membind) return topology->get_proc_membind(topology, pid, nodeset, policy, flags); errno = ENOSYS; return -1; } int hwloc_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, hwloc_membind_policy_t * policy, int flags) { hwloc_nodeset_t nodeset; int ret; nodeset = hwloc_bitmap_alloc(); ret = hwloc_get_proc_membind_nodeset(topology, pid, nodeset, policy, flags); if (!ret) hwloc_cpuset_from_nodeset(topology, set, nodeset); return ret; } int hwloc_set_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { nodeset = hwloc_fix_membind(topology, nodeset); if (!nodeset) return -1; if (topology->set_area_membind) return topology->set_area_membind(topology, addr, len, nodeset, policy, flags); errno = ENOSYS; return -1; } int hwloc_set_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) { hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); int ret; if (hwloc_fix_membind_cpuset(topology, nodeset, set)) ret = -1; else ret = hwloc_set_area_membind_nodeset(topology, addr, len, nodeset, policy, flags); hwloc_bitmap_free(nodeset); return ret; } int hwloc_get_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) { if (topology->get_area_membind) return topology->get_area_membind(topology, addr, len, nodeset, policy, flags); errno = ENOSYS; return -1; } int hwloc_get_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_cpuset_t set, hwloc_membind_policy_t * policy, int flags) { hwloc_nodeset_t nodeset; int ret; nodeset = hwloc_bitmap_alloc(); ret = hwloc_get_area_membind_nodeset(topology, addr, len, nodeset, policy, flags); if (!ret) hwloc_cpuset_from_nodeset(topology, set, nodeset); return ret; } void * hwloc_alloc_heap(hwloc_topology_t topology __hwloc_attribute_unused, size_t len) { void *p; #if defined(HAVE_GETPAGESIZE) && defined(HAVE_POSIX_MEMALIGN) errno = posix_memalign(&p, getpagesize(), len); if (errno) p = NULL; #elif defined(HAVE_GETPAGESIZE) && defined(HAVE_MEMALIGN) p = memalign(getpagesize(), len); #else p = malloc(len); #endif return p; } #ifdef MAP_ANONYMOUS void * hwloc_alloc_mmap(hwloc_topology_t topology __hwloc_attribute_unused, size_t len) { return mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); } #endif int hwloc_free_heap(hwloc_topology_t topology __hwloc_attribute_unused, void *addr, size_t len __hwloc_attribute_unused) { free(addr); return 0; } #ifdef MAP_ANONYMOUS int hwloc_free_mmap(hwloc_topology_t topology __hwloc_attribute_unused, void *addr, size_t len) { if (!addr) return 0; return munmap(addr, len); } #endif void * hwloc_alloc(hwloc_topology_t topology, size_t len) { if (topology->alloc) return topology->alloc(topology, len); return hwloc_alloc_heap(topology, len); } void * hwloc_alloc_membind_nodeset(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { void *p; nodeset = hwloc_fix_membind(topology, nodeset); if (!nodeset) goto fallback; if (flags & HWLOC_MEMBIND_MIGRATE) { errno = EINVAL; goto fallback; } if (topology->alloc_membind) return topology->alloc_membind(topology, len, nodeset, policy, flags); else if (topology->set_area_membind) { p = hwloc_alloc(topology, len); if (!p) return NULL; if (topology->set_area_membind(topology, p, len, nodeset, policy, flags) && flags & HWLOC_MEMBIND_STRICT) { int error = errno; free(p); errno = error; return NULL; } return p; } else { errno = ENOSYS; } fallback: if (flags & HWLOC_MEMBIND_STRICT) /* Report error */ return NULL; /* Never mind, allocate anyway */ return hwloc_alloc(topology, len); } void * hwloc_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) { hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); void *ret; if (!hwloc_fix_membind_cpuset(topology, nodeset, set)) { if (flags & HWLOC_MEMBIND_STRICT) ret = NULL; else ret = hwloc_alloc(topology, len); } else ret = hwloc_alloc_membind_nodeset(topology, len, nodeset, policy, flags); hwloc_bitmap_free(nodeset); return ret; } int hwloc_free(hwloc_topology_t topology, void *addr, size_t len) { if (topology->free_membind) return topology->free_membind(topology, addr, len); return hwloc_free_heap(topology, addr, len); }