/* * Copyright © 2009 CNRS * Copyright © 2009-2011 INRIA. All rights reserved. * Copyright © 2009-2011 Université Bordeaux 1 * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2010 IBM * See COPYING in top-level directory. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined HWLOC_HAVE_SET_MEMPOLICY || defined HWLOC_HAVE_MBIND #define migratepages migrate_pages /* workaround broken migratepages prototype in numaif.h before libnuma 2.0.2 */ #include #endif #if !defined(HWLOC_HAVE_CPU_SET) && !(defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY)) && defined(HWLOC_HAVE__SYSCALL3) /* libc doesn't have support for sched_setaffinity, build system call * ourselves: */ # include # ifndef __NR_sched_setaffinity # ifdef __i386__ # define __NR_sched_setaffinity 241 # elif defined(__x86_64__) # define __NR_sched_setaffinity 203 # elif defined(__ia64__) # define __NR_sched_setaffinity 1231 # elif defined(__hppa__) # define __NR_sched_setaffinity 211 # elif defined(__alpha__) # define __NR_sched_setaffinity 395 # elif defined(__s390__) # define __NR_sched_setaffinity 239 # elif defined(__sparc__) # define __NR_sched_setaffinity 261 # elif defined(__m68k__) # define __NR_sched_setaffinity 311 # elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__powerpc64__) || defined(__ppc64__) # define __NR_sched_setaffinity 222 # elif defined(__arm__) # define __NR_sched_setaffinity 241 # elif defined(__cris__) # define __NR_sched_setaffinity 241 /*# elif defined(__mips__) # define __NR_sched_setaffinity TODO (32/64/nabi) */ # else # warning "don't know the syscall number for sched_setaffinity on this architecture, will not support binding" # define sched_setaffinity(pid, lg, mask) (errno = ENOSYS, -1) # endif # endif # ifndef sched_setaffinity _syscall3(int, sched_setaffinity, pid_t, pid, unsigned int, lg, const void *, mask) # endif # ifndef __NR_sched_getaffinity # ifdef __i386__ # define __NR_sched_getaffinity 242 # elif defined(__x86_64__) # define __NR_sched_getaffinity 204 # elif defined(__ia64__) # define __NR_sched_getaffinity 1232 # elif defined(__hppa__) # define __NR_sched_getaffinity 212 # elif defined(__alpha__) # define __NR_sched_getaffinity 396 # elif defined(__s390__) # define __NR_sched_getaffinity 240 # elif defined(__sparc__) # define __NR_sched_getaffinity 260 # elif defined(__m68k__) # define __NR_sched_getaffinity 312 # elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__powerpc64__) || defined(__ppc64__) # define __NR_sched_getaffinity 223 # elif defined(__arm__) # define __NR_sched_getaffinity 242 # elif defined(__cris__) # define __NR_sched_getaffinity 242 /*# elif defined(__mips__) # define __NR_sched_getaffinity TODO (32/64/nabi) */ # else # warning "don't know the syscall number for sched_getaffinity on this architecture, will not support getting binding" # define sched_getaffinity(pid, lg, mask) (errno = ENOSYS, -1) # endif # endif # ifndef sched_getaffinity _syscall3(int, sched_getaffinity, pid_t, pid, unsigned int, lg, void *, mask) # endif #endif /* Added for ntohl() */ #include #ifdef HAVE_OPENAT /* Use our own filesystem functions if we have openat */ static const char * hwloc_checkat(const char *path, int fsroot_fd) { const char *relative_path; if (fsroot_fd < 0) { errno = EBADF; return NULL; } /* Skip leading slashes. */ for (relative_path = path; *relative_path == '/'; relative_path++); return relative_path; } static int hwloc_openat(const char *path, int fsroot_fd) { const char *relative_path; relative_path = hwloc_checkat(path, fsroot_fd); if (!relative_path) return -1; return openat (fsroot_fd, relative_path, O_RDONLY); } static FILE * hwloc_fopenat(const char *path, const char *mode, int fsroot_fd) { int fd; if (strcmp(mode, "r")) { errno = ENOTSUP; return NULL; } fd = hwloc_openat (path, fsroot_fd); if (fd == -1) return NULL; return fdopen(fd, mode); } static int hwloc_accessat(const char *path, int mode, int fsroot_fd) { const char *relative_path; relative_path = hwloc_checkat(path, fsroot_fd); if (!relative_path) return -1; return faccessat(fsroot_fd, relative_path, mode, 0); } static int hwloc_fstatat(const char *path, struct stat *st, int flags, int fsroot_fd) { const char *relative_path; relative_path = hwloc_checkat(path, fsroot_fd); if (!relative_path) return -1; return fstatat(fsroot_fd, relative_path, st, flags); } static DIR* hwloc_opendirat(const char *path, int fsroot_fd) { int dir_fd; const char *relative_path; relative_path = hwloc_checkat(path, fsroot_fd); if (!relative_path) return NULL; dir_fd = openat(fsroot_fd, relative_path, O_RDONLY | O_DIRECTORY); if (dir_fd < 0) return NULL; return fdopendir(dir_fd); } #endif /* HAVE_OPENAT */ /* Static inline version of fopen so that we can use openat if we have it, but still preserve compiler parameter checking */ static __hwloc_inline int hwloc_open(const char *p, int d __hwloc_attribute_unused) { #ifdef HAVE_OPENAT return hwloc_openat(p, d); #else return open(p, O_RDONLY); #endif } static __hwloc_inline FILE * hwloc_fopen(const char *p, const char *m, int d __hwloc_attribute_unused) { #ifdef HAVE_OPENAT return hwloc_fopenat(p, m, d); #else return fopen(p, m); #endif } /* Static inline version of access so that we can use openat if we have it, but still preserve compiler parameter checking */ static __hwloc_inline int hwloc_access(const char *p, int m, int d __hwloc_attribute_unused) { #ifdef HAVE_OPENAT return hwloc_accessat(p, m, d); #else return access(p, m); #endif } static __hwloc_inline int hwloc_stat(const char *p, struct stat *st, int d __hwloc_attribute_unused) { #ifdef HAVE_OPENAT return hwloc_fstatat(p, st, 0, d); #else return stat(p, st); #endif } /* Static inline version of opendir so that we can use openat if we have it, but still preserve compiler parameter checking */ static __hwloc_inline DIR * hwloc_opendir(const char *p, int d __hwloc_attribute_unused) { #ifdef HAVE_OPENAT return hwloc_opendirat(p, d); #else return opendir(p); #endif } int hwloc_linux_set_tid_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, pid_t tid __hwloc_attribute_unused, hwloc_const_bitmap_t hwloc_set __hwloc_attribute_unused) { /* TODO Kerrighed: Use * int migrate (pid_t pid, int destination_node); * int migrate_self (int destination_node); * int thread_migrate (int thread_id, int destination_node); */ /* The resulting binding is always strict */ #if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) cpu_set_t *plinux_set; unsigned cpu; int last; size_t setsize; int err; last = hwloc_bitmap_last(hwloc_set); if (last == -1) { errno = EINVAL; return -1; } setsize = CPU_ALLOC_SIZE(last+1); plinux_set = CPU_ALLOC(last+1); CPU_ZERO_S(setsize, plinux_set); hwloc_bitmap_foreach_begin(cpu, hwloc_set) CPU_SET_S(cpu, setsize, plinux_set); hwloc_bitmap_foreach_end(); err = sched_setaffinity(tid, setsize, plinux_set); CPU_FREE(plinux_set); return err; #elif defined(HWLOC_HAVE_CPU_SET) cpu_set_t linux_set; unsigned cpu; CPU_ZERO(&linux_set); hwloc_bitmap_foreach_begin(cpu, hwloc_set) CPU_SET(cpu, &linux_set); hwloc_bitmap_foreach_end(); #ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY return sched_setaffinity(tid, &linux_set); #else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ return sched_setaffinity(tid, sizeof(linux_set), &linux_set); #endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ #elif defined(HWLOC_HAVE__SYSCALL3) unsigned long mask = hwloc_bitmap_to_ulong(hwloc_set); #ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY return sched_setaffinity(tid, (void*) &mask); #else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ return sched_setaffinity(tid, sizeof(mask), (void*) &mask); #endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ #else /* !_SYSCALL3 */ errno = ENOSYS; return -1; #endif /* !_SYSCALL3 */ } #if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) /* * On some kernels, sched_getaffinity requires the output size to be larger * than the kernel cpu_set size (defined by CONFIG_NR_CPUS). * Try sched_affinity on ourself until we find a nr_cpus value that makes * the kernel happy. */ static int hwloc_linux_find_kernel_nr_cpus(hwloc_topology_t topology) { static int nr_cpus = -1; if (nr_cpus != -1) /* already computed */ return nr_cpus; /* start with a nr_cpus that may contain the whole topology */ nr_cpus = hwloc_bitmap_last(topology->levels[0][0]->complete_cpuset) + 1; while (1) { cpu_set_t *set = CPU_ALLOC(nr_cpus); size_t setsize = CPU_ALLOC_SIZE(nr_cpus); int err = sched_getaffinity(0, setsize, set); /* always works, unless setsize is too small */ CPU_FREE(set); if (!err) /* found it */ return nr_cpus; nr_cpus *= 2; } } #endif int hwloc_linux_get_tid_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, pid_t tid __hwloc_attribute_unused, hwloc_bitmap_t hwloc_set __hwloc_attribute_unused) { int err __hwloc_attribute_unused; /* TODO Kerrighed */ #if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) cpu_set_t *plinux_set; unsigned cpu; int last; size_t setsize; int kernel_nr_cpus; /* find the kernel nr_cpus so as to use a large enough cpu_set size */ kernel_nr_cpus = hwloc_linux_find_kernel_nr_cpus(topology); setsize = CPU_ALLOC_SIZE(kernel_nr_cpus); plinux_set = CPU_ALLOC(kernel_nr_cpus); err = sched_getaffinity(tid, setsize, plinux_set); if (err < 0) { CPU_FREE(plinux_set); return -1; } last = hwloc_bitmap_last(topology->levels[0][0]->complete_cpuset); assert(last != -1); hwloc_bitmap_zero(hwloc_set); for(cpu=0; cpu<=(unsigned) last; cpu++) if (CPU_ISSET_S(cpu, setsize, plinux_set)) hwloc_bitmap_set(hwloc_set, cpu); CPU_FREE(plinux_set); #elif defined(HWLOC_HAVE_CPU_SET) cpu_set_t linux_set; unsigned cpu; #ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY err = sched_getaffinity(tid, &linux_set); #else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ err = sched_getaffinity(tid, sizeof(linux_set), &linux_set); #endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ if (err < 0) return -1; hwloc_bitmap_zero(hwloc_set); for(cpu=0; cpud_name, ".") || !strcmp(dirent->d_name, "..")) continue; tids[nr_tids++] = atoi(dirent->d_name); } *nr_tidsp = nr_tids; *tidsp = tids; return 0; } /* Callbacks for binding each process sub-tid */ typedef int (*hwloc_linux_foreach_proc_tid_cb_t)(hwloc_topology_t topology, pid_t tid, void *data, int idx, int flags); static int hwloc_linux_foreach_proc_tid_set_cpubind_cb(hwloc_topology_t topology, pid_t tid, void *data, int idx __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { hwloc_bitmap_t cpuset = data; return hwloc_linux_set_tid_cpubind(topology, tid, cpuset); } static int hwloc_linux_foreach_proc_tid_get_cpubind_cb(hwloc_topology_t topology, pid_t tid, void *data, int idx, int flags) { hwloc_bitmap_t *cpusets = data; hwloc_bitmap_t cpuset = cpusets[0]; hwloc_bitmap_t tidset = cpusets[1]; if (hwloc_linux_get_tid_cpubind(topology, tid, tidset)) return -1; /* reset the cpuset on first iteration */ if (!idx) hwloc_bitmap_zero(cpuset); if (flags & HWLOC_CPUBIND_STRICT) { /* if STRICT, we want all threads to have the same binding */ if (!idx) { /* this is the first thread, copy its binding */ hwloc_bitmap_copy(cpuset, tidset); } else if (!hwloc_bitmap_isequal(cpuset, tidset)) { /* this is not the first thread, and it's binding is different */ errno = EXDEV; return -1; } } else { /* if not STRICT, just OR all thread bindings */ hwloc_bitmap_or(cpuset, cpuset, tidset); } return 0; } /* Call the callback for each process tid. */ static int hwloc_linux_foreach_proc_tid(hwloc_topology_t topology, pid_t pid, hwloc_linux_foreach_proc_tid_cb_t cb, void *data, int flags) { char taskdir_path[128]; DIR *taskdir; pid_t *tids, *newtids; unsigned i, nr, newnr; int err; if (pid) snprintf(taskdir_path, sizeof(taskdir_path), "/proc/%u/task", (unsigned) pid); else snprintf(taskdir_path, sizeof(taskdir_path), "/proc/self/task"); taskdir = opendir(taskdir_path); if (!taskdir) { errno = ENOSYS; err = -1; goto out; } /* read the current list of threads */ err = hwloc_linux_get_proc_tids(taskdir, &nr, &tids); if (err < 0) goto out_with_dir; retry: /* apply the callback to all threads */ for(i=0; ipid; if (flags & HWLOC_CPUBIND_THREAD) return hwloc_linux_set_tid_cpubind(topology, pid, hwloc_set); else return hwloc_linux_set_pid_cpubind(topology, pid, hwloc_set, flags); } static int hwloc_linux_get_proc_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_bitmap_t hwloc_set, int flags) { if (pid == 0) pid = topology->pid; if (flags & HWLOC_CPUBIND_THREAD) return hwloc_linux_get_tid_cpubind(topology, pid, hwloc_set); else return hwloc_linux_get_pid_cpubind(topology, pid, hwloc_set, flags); } static int hwloc_linux_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) { return hwloc_linux_set_pid_cpubind(topology, topology->pid, hwloc_set, flags); } static int hwloc_linux_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) { return hwloc_linux_get_pid_cpubind(topology, topology->pid, hwloc_set, flags); } static int hwloc_linux_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) { if (topology->pid) { errno = ENOSYS; return -1; } return hwloc_linux_set_tid_cpubind(topology, 0, hwloc_set); } static int hwloc_linux_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) { if (topology->pid) { errno = ENOSYS; return -1; } return hwloc_linux_get_tid_cpubind(topology, 0, hwloc_set); } #if HAVE_DECL_PTHREAD_SETAFFINITY_NP #pragma weak pthread_setaffinity_np #pragma weak pthread_self static int hwloc_linux_set_thread_cpubind(hwloc_topology_t topology, pthread_t tid, hwloc_const_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) { int err; if (topology->pid) { errno = ENOSYS; return -1; } if (!pthread_self) { /* ?! Application uses set_thread_cpubind, but doesn't link against libpthread ?! */ errno = ENOSYS; return -1; } if (tid == pthread_self()) return hwloc_linux_set_tid_cpubind(topology, 0, hwloc_set); if (!pthread_setaffinity_np) { errno = ENOSYS; return -1; } /* TODO Kerrighed: Use * int migrate (pid_t pid, int destination_node); * int migrate_self (int destination_node); * int thread_migrate (int thread_id, int destination_node); */ #if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) /* Use a separate block so that we can define specific variable types here */ { cpu_set_t *plinux_set; unsigned cpu; int last; size_t setsize; last = hwloc_bitmap_last(hwloc_set); if (last == -1) { errno = EINVAL; return -1; } setsize = CPU_ALLOC_SIZE(last+1); plinux_set = CPU_ALLOC(last+1); CPU_ZERO_S(setsize, plinux_set); hwloc_bitmap_foreach_begin(cpu, hwloc_set) CPU_SET_S(cpu, setsize, plinux_set); hwloc_bitmap_foreach_end(); err = pthread_setaffinity_np(tid, setsize, plinux_set); CPU_FREE(plinux_set); } #elif defined(HWLOC_HAVE_CPU_SET) /* Use a separate block so that we can define specific variable types here */ { cpu_set_t linux_set; unsigned cpu; CPU_ZERO(&linux_set); hwloc_bitmap_foreach_begin(cpu, hwloc_set) CPU_SET(cpu, &linux_set); hwloc_bitmap_foreach_end(); #ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY err = pthread_setaffinity_np(tid, &linux_set); #else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ err = pthread_setaffinity_np(tid, sizeof(linux_set), &linux_set); #endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ } #else /* CPU_SET */ /* Use a separate block so that we can define specific variable types here */ { unsigned long mask = hwloc_bitmap_to_ulong(hwloc_set); #ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY err = pthread_setaffinity_np(tid, (void*) &mask); #else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ err = pthread_setaffinity_np(tid, sizeof(mask), (void*) &mask); #endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ } #endif /* CPU_SET */ if (err) { errno = err; return -1; } return 0; } #endif /* HAVE_DECL_PTHREAD_SETAFFINITY_NP */ #if HAVE_DECL_PTHREAD_GETAFFINITY_NP #pragma weak pthread_getaffinity_np #pragma weak pthread_self static int hwloc_linux_get_thread_cpubind(hwloc_topology_t topology, pthread_t tid, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) { int err; if (topology->pid) { errno = ENOSYS; return -1; } if (!pthread_self) { /* ?! Application uses set_thread_cpubind, but doesn't link against libpthread ?! */ errno = ENOSYS; return -1; } if (tid == pthread_self()) return hwloc_linux_get_tid_cpubind(topology, 0, hwloc_set); if (!pthread_getaffinity_np) { errno = ENOSYS; return -1; } /* TODO Kerrighed */ #if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) /* Use a separate block so that we can define specific variable types here */ { cpu_set_t *plinux_set; unsigned cpu; int last; size_t setsize; last = hwloc_bitmap_last(topology->levels[0][0]->complete_cpuset); assert (last != -1); setsize = CPU_ALLOC_SIZE(last+1); plinux_set = CPU_ALLOC(last+1); err = pthread_getaffinity_np(tid, setsize, plinux_set); if (err) { CPU_FREE(plinux_set); errno = err; return -1; } hwloc_bitmap_zero(hwloc_set); for(cpu=0; cpu<(unsigned) last; cpu++) if (CPU_ISSET_S(cpu, setsize, plinux_set)) hwloc_bitmap_set(hwloc_set, cpu); CPU_FREE(plinux_set); } #elif defined(HWLOC_HAVE_CPU_SET) /* Use a separate block so that we can define specific variable types here */ { cpu_set_t linux_set; unsigned cpu; #ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY err = pthread_getaffinity_np(tid, &linux_set); #else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ err = pthread_getaffinity_np(tid, sizeof(linux_set), &linux_set); #endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ if (err) { errno = err; return -1; } hwloc_bitmap_zero(hwloc_set); for(cpu=0; cpupid; if (flags & HWLOC_CPUBIND_THREAD) return hwloc_linux_get_tid_last_cpu_location(topology, pid, hwloc_set); else return hwloc_linux_get_pid_last_cpu_location(topology, pid, hwloc_set, flags); } static int hwloc_linux_get_thisproc_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) { return hwloc_linux_get_pid_last_cpu_location(topology, topology->pid, hwloc_set, flags); } static int hwloc_linux_get_thisthread_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) { if (topology->pid) { errno = ENOSYS; return -1; } return hwloc_linux_get_tid_last_cpu_location(topology, 0, hwloc_set); } #if defined HWLOC_HAVE_SET_MEMPOLICY || defined HWLOC_HAVE_MBIND static int hwloc_linux_membind_policy_from_hwloc(int *linuxpolicy, hwloc_membind_policy_t policy, int flags) { switch (policy) { case HWLOC_MEMBIND_DEFAULT: case HWLOC_MEMBIND_FIRSTTOUCH: *linuxpolicy = MPOL_DEFAULT; break; case HWLOC_MEMBIND_BIND: if (flags & HWLOC_MEMBIND_STRICT) *linuxpolicy = MPOL_BIND; else *linuxpolicy = MPOL_PREFERRED; break; case HWLOC_MEMBIND_INTERLEAVE: *linuxpolicy = MPOL_INTERLEAVE; break; /* TODO: next-touch when (if?) patch applied upstream */ default: errno = ENOSYS; return -1; } return 0; } static int hwloc_linux_membind_mask_from_nodeset(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_nodeset_t nodeset, unsigned *max_os_index_p, unsigned long **linuxmaskp) { unsigned max_os_index = 0; /* highest os_index + 1 */ unsigned long *linuxmask; unsigned i; hwloc_nodeset_t linux_nodeset = NULL; if (hwloc_bitmap_isfull(nodeset)) { linux_nodeset = hwloc_bitmap_alloc(); hwloc_bitmap_only(linux_nodeset, 0); nodeset = linux_nodeset; } max_os_index = hwloc_bitmap_last(nodeset); if (max_os_index == (unsigned) -1) max_os_index = 0; /* add 1 to convert the last os_index into a max_os_index, * and round up to the nearest multiple of BITS_PER_LONG */ max_os_index = (max_os_index + 1 + HWLOC_BITS_PER_LONG - 1) & ~(HWLOC_BITS_PER_LONG - 1); linuxmask = calloc(max_os_index/HWLOC_BITS_PER_LONG, sizeof(long)); if (!linuxmask) { errno = ENOMEM; return -1; } for(i=0; ibackend_type == HWLOC_BACKEND_NONE); if (!fsroot_path) fsroot_path = "/"; root = open(fsroot_path, O_RDONLY | O_DIRECTORY); if (root < 0) return -1; if (strcmp(fsroot_path, "/")) topology->is_thissystem = 0; topology->backend_params.sysfs.root_path = strdup(fsroot_path); topology->backend_params.sysfs.root_fd = root; #else topology->backend_params.sysfs.root_path = NULL; topology->backend_params.sysfs.root_fd = -1; #endif topology->backend_type = HWLOC_BACKEND_SYSFS; return 0; } void hwloc_backend_sysfs_exit(struct hwloc_topology *topology) { assert(topology->backend_type == HWLOC_BACKEND_SYSFS); #ifdef HAVE_OPENAT close(topology->backend_params.sysfs.root_fd); free(topology->backend_params.sysfs.root_path); topology->backend_params.sysfs.root_path = NULL; #endif topology->backend_type = HWLOC_BACKEND_NONE; } static int hwloc_parse_sysfs_unsigned(const char *mappath, unsigned *value, int fsroot_fd) { char string[11]; FILE * fd; fd = hwloc_fopen(mappath, "r", fsroot_fd); if (!fd) { *value = -1; return -1; } if (!fgets(string, 11, fd)) { *value = -1; fclose(fd); return -1; } *value = strtoul(string, NULL, 10); fclose(fd); return 0; } /* kernel cpumaps are composed of an array of 32bits cpumasks */ #define KERNEL_CPU_MASK_BITS 32 #define KERNEL_CPU_MAP_LEN (KERNEL_CPU_MASK_BITS/4+2) int hwloc_linux_parse_cpumap_file(FILE *file, hwloc_bitmap_t set) { unsigned long *maps; unsigned long map; int nr_maps = 0; static int nr_maps_allocated = 8; /* only compute the power-of-two above the kernel cpumask size once */ int i; maps = malloc(nr_maps_allocated * sizeof(*maps)); /* reset to zero first */ hwloc_bitmap_zero(set); /* parse the whole mask */ while (fscanf(file, "%lx,", &map) == 1) /* read one kernel cpu mask and the ending comma */ { if (nr_maps == nr_maps_allocated) { nr_maps_allocated *= 2; maps = realloc(maps, nr_maps_allocated * sizeof(*maps)); } if (!map && !nr_maps) /* ignore the first map if it's empty */ continue; memmove(&maps[1], &maps[0], nr_maps*sizeof(*maps)); maps[0] = map; nr_maps++; } /* convert into a set */ #if KERNEL_CPU_MASK_BITS == HWLOC_BITS_PER_LONG for(i=0; i. If cpuset are used they get /proc/pid/cpuset * containing . */ static char * hwloc_read_linux_cpuset_name(int fsroot_fd, hwloc_pid_t pid) { #define CPUSET_NAME_LEN 128 char cpuset_name[CPUSET_NAME_LEN]; FILE *fd; char *tmp; /* check whether a cgroup-cpuset is enabled */ if (!pid) fd = hwloc_fopen("/proc/self/cgroup", "r", fsroot_fd); else { char path[] = "/proc/XXXXXXXXXX/cgroup"; snprintf(path, sizeof(path), "/proc/%d/cgroup", pid); fd = hwloc_fopen(path, "r", fsroot_fd); } if (fd) { /* find a cpuset line */ #define CGROUP_LINE_LEN 256 char line[CGROUP_LINE_LEN]; while (fgets(line, sizeof(line), fd)) { char *end, *colon = strchr(line, ':'); if (!colon) continue; if (strncmp(colon, ":cpuset:", 8)) continue; /* found a cgroup-cpuset line, return the name */ fclose(fd); end = strchr(colon, '\n'); if (end) *end = '\0'; hwloc_debug("Found cgroup-cpuset %s\n", colon+8); return strdup(colon+8); } fclose(fd); } /* check whether a cpuset is enabled */ if (!pid) fd = hwloc_fopen("/proc/self/cpuset", "r", fsroot_fd); else { char path[] = "/proc/XXXXXXXXXX/cpuset"; snprintf(path, sizeof(path), "/proc/%d/cpuset", pid); fd = hwloc_fopen(path, "r", fsroot_fd); } if (!fd) { /* found nothing */ hwloc_debug("%s", "No cgroup or cpuset found\n"); return NULL; } /* found a cpuset, return the name */ tmp = fgets(cpuset_name, sizeof(cpuset_name), fd); fclose(fd); if (!tmp) return NULL; tmp = strchr(cpuset_name, '\n'); if (tmp) *tmp = '\0'; hwloc_debug("Found cpuset %s\n", cpuset_name); return strdup(cpuset_name); } /* * Then, the cpuset description is available from either the cgroup or * the cpuset filesystem (usually mounted in / or /dev) where there * are cgroup/cpuset.{cpus,mems} or cpuset/{cpus,mems} files. */ static char * hwloc_read_linux_cpuset_mask(const char *cgroup_mntpnt, const char *cpuset_mntpnt, const char *cpuset_name, const char *attr_name, int fsroot_fd) { #define CPUSET_FILENAME_LEN 256 char cpuset_filename[CPUSET_FILENAME_LEN]; FILE *fd; char *info = NULL, *tmp; ssize_t ssize; size_t size; if (cgroup_mntpnt) { /* try to read the cpuset from cgroup */ snprintf(cpuset_filename, CPUSET_FILENAME_LEN, "%s%s/cpuset.%s", cgroup_mntpnt, cpuset_name, attr_name); hwloc_debug("Trying to read cgroup file <%s>\n", cpuset_filename); fd = hwloc_fopen(cpuset_filename, "r", fsroot_fd); if (fd) goto gotfile; } else if (cpuset_mntpnt) { /* try to read the cpuset directly */ snprintf(cpuset_filename, CPUSET_FILENAME_LEN, "%s%s/%s", cpuset_mntpnt, cpuset_name, attr_name); hwloc_debug("Trying to read cpuset file <%s>\n", cpuset_filename); fd = hwloc_fopen(cpuset_filename, "r", fsroot_fd); if (fd) goto gotfile; } /* found no cpuset description, ignore it */ hwloc_debug("Couldn't find cpuset <%s> description, ignoring\n", cpuset_name); goto out; gotfile: ssize = getline(&info, &size, fd); fclose(fd); if (ssize < 0) goto out; if (!info) goto out; tmp = strchr(info, '\n'); if (tmp) *tmp = '\0'; out: return info; } static void hwloc_admin_disable_set_from_cpuset(struct hwloc_topology *topology, const char *cgroup_mntpnt, const char *cpuset_mntpnt, const char *cpuset_name, const char *attr_name, hwloc_bitmap_t admin_enabled_cpus_set) { char *cpuset_mask; char *current, *comma, *tmp; int prevlast, nextfirst, nextlast; /* beginning/end of enabled-segments */ hwloc_bitmap_t tmpset; cpuset_mask = hwloc_read_linux_cpuset_mask(cgroup_mntpnt, cpuset_mntpnt, cpuset_name, attr_name, topology->backend_params.sysfs.root_fd); if (!cpuset_mask) return; hwloc_debug("found cpuset %s: %s\n", attr_name, cpuset_mask); current = cpuset_mask; prevlast = -1; while (1) { /* save a pointer to the next comma and erase it to simplify things */ comma = strchr(current, ','); if (comma) *comma = '\0'; /* find current enabled-segment bounds */ nextfirst = strtoul(current, &tmp, 0); if (*tmp == '-') nextlast = strtoul(tmp+1, NULL, 0); else nextlast = nextfirst; if (prevlast+1 <= nextfirst-1) { hwloc_debug("%s [%d:%d] excluded by cpuset\n", attr_name, prevlast+1, nextfirst-1); hwloc_bitmap_clr_range(admin_enabled_cpus_set, prevlast+1, nextfirst-1); } /* switch to next enabled-segment */ prevlast = nextlast; if (!comma) break; current = comma+1; } hwloc_debug("%s [%d:%d] excluded by cpuset\n", attr_name, prevlast+1, nextfirst-1); /* no easy way to clear until the infinity */ tmpset = hwloc_bitmap_alloc(); hwloc_bitmap_set_range(tmpset, 0, prevlast); hwloc_bitmap_and(admin_enabled_cpus_set, admin_enabled_cpus_set, tmpset); hwloc_bitmap_free(tmpset); free(cpuset_mask); } static void hwloc_parse_meminfo_info(struct hwloc_topology *topology, const char *path, int prefixlength, uint64_t *local_memory, uint64_t *meminfo_hugepages_count, uint64_t *meminfo_hugepages_size, int onlytotal) { char string[64]; FILE *fd; fd = hwloc_fopen(path, "r", topology->backend_params.sysfs.root_fd); if (!fd) return; while (fgets(string, sizeof(string), fd) && *string != '\0') { unsigned long long number; if (strlen(string) < (size_t) prefixlength) continue; if (sscanf(string+prefixlength, "MemTotal: %llu kB", (unsigned long long *) &number) == 1) { *local_memory = number << 10; if (onlytotal) break; } else if (!onlytotal) { if (sscanf(string+prefixlength, "Hugepagesize: %llu", (unsigned long long *) &number) == 1) *meminfo_hugepages_size = number << 10; else if (sscanf(string+prefixlength, "HugePages_Free: %llu", (unsigned long long *) &number) == 1) /* these are free hugepages, not the total amount of huge pages */ *meminfo_hugepages_count = number; } } fclose(fd); } #define SYSFS_NUMA_NODE_PATH_LEN 128 static void hwloc_parse_hugepages_info(struct hwloc_topology *topology, const char *dirpath, struct hwloc_obj_memory_s *memory, uint64_t *remaining_local_memory) { DIR *dir; struct dirent *dirent; unsigned long index_ = 1; FILE *hpfd; char line[64]; char path[SYSFS_NUMA_NODE_PATH_LEN]; dir = hwloc_opendir(dirpath, topology->backend_params.sysfs.root_fd); if (dir) { while ((dirent = readdir(dir)) != NULL) { if (strncmp(dirent->d_name, "hugepages-", 10)) continue; memory->page_types[index_].size = strtoul(dirent->d_name+10, NULL, 0) * 1024ULL; sprintf(path, "%s/%s/nr_hugepages", dirpath, dirent->d_name); hpfd = hwloc_fopen(path, "r", topology->backend_params.sysfs.root_fd); if (hpfd) { if (fgets(line, sizeof(line), hpfd)) { fclose(hpfd); /* these are the actual total amount of huge pages */ memory->page_types[index_].count = strtoull(line, NULL, 0); *remaining_local_memory -= memory->page_types[index_].count * memory->page_types[index_].size; index_++; } } } closedir(dir); memory->page_types_len = index_; } } static void hwloc_get_kerrighed_node_meminfo_info(struct hwloc_topology *topology, unsigned long node, struct hwloc_obj_memory_s *memory) { char path[128]; uint64_t meminfo_hugepages_count, meminfo_hugepages_size = 0; if (topology->is_thissystem) { memory->page_types_len = 2; memory->page_types = malloc(2*sizeof(*memory->page_types)); memset(memory->page_types, 0, 2*sizeof(*memory->page_types)); /* Try to get the hugepage size from sysconf in case we fail to get it from /proc/meminfo later */ #ifdef HAVE__SC_LARGE_PAGESIZE memory->page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); #endif memory->page_types[0].size = getpagesize(); } snprintf(path, sizeof(path), "/proc/nodes/node%lu/meminfo", node); hwloc_parse_meminfo_info(topology, path, 0 /* no prefix */, &memory->local_memory, &meminfo_hugepages_count, &meminfo_hugepages_size, memory->page_types == NULL); if (memory->page_types) { uint64_t remaining_local_memory = memory->local_memory; if (meminfo_hugepages_size) { memory->page_types[1].size = meminfo_hugepages_size; memory->page_types[1].count = meminfo_hugepages_count; remaining_local_memory -= meminfo_hugepages_count * meminfo_hugepages_size; } else { memory->page_types_len = 1; } memory->page_types[0].count = remaining_local_memory / memory->page_types[0].size; } } static void hwloc_get_procfs_meminfo_info(struct hwloc_topology *topology, struct hwloc_obj_memory_s *memory) { uint64_t meminfo_hugepages_count, meminfo_hugepages_size = 0; struct stat st; int has_sysfs_hugepages = 0; int types = 2; int err; err = hwloc_stat("/sys/kernel/mm/hugepages", &st, topology->backend_params.sysfs.root_fd); if (!err) { types = 1 + st.st_nlink-2; has_sysfs_hugepages = 1; } if (topology->is_thissystem) { memory->page_types_len = types; memory->page_types = malloc(types*sizeof(*memory->page_types)); memset(memory->page_types, 0, types*sizeof(*memory->page_types)); /* Try to get the hugepage size from sysconf in case we fail to get it from /proc/meminfo later */ #ifdef HAVE__SC_LARGE_PAGESIZE memory->page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); #endif memory->page_types[0].size = getpagesize(); } hwloc_parse_meminfo_info(topology, "/proc/meminfo", 0 /* no prefix */, &memory->local_memory, &meminfo_hugepages_count, &meminfo_hugepages_size, memory->page_types == NULL); if (memory->page_types) { uint64_t remaining_local_memory = memory->local_memory; if (has_sysfs_hugepages) { /* read from node%d/hugepages/hugepages-%skB/nr_hugepages */ hwloc_parse_hugepages_info(topology, "/sys/kernel/mm/hugepages", memory, &remaining_local_memory); } else { /* use what we found in meminfo */ if (meminfo_hugepages_size) { memory->page_types[1].size = meminfo_hugepages_size; memory->page_types[1].count = meminfo_hugepages_count; remaining_local_memory -= meminfo_hugepages_count * meminfo_hugepages_size; } else { memory->page_types_len = 1; } } memory->page_types[0].count = remaining_local_memory / memory->page_types[0].size; } } static void hwloc_sysfs_node_meminfo_info(struct hwloc_topology *topology, const char *syspath, int node, struct hwloc_obj_memory_s *memory) { char path[SYSFS_NUMA_NODE_PATH_LEN]; char meminfopath[SYSFS_NUMA_NODE_PATH_LEN]; uint64_t meminfo_hugepages_count = 0; uint64_t meminfo_hugepages_size = 0; struct stat st; int has_sysfs_hugepages = 0; int types = 2; int err; sprintf(path, "%s/node%d/hugepages", syspath, node); err = hwloc_stat(path, &st, topology->backend_params.sysfs.root_fd); if (!err) { types = 1 + st.st_nlink-2; has_sysfs_hugepages = 1; } if (topology->is_thissystem) { memory->page_types_len = types; memory->page_types = malloc(types*sizeof(*memory->page_types)); memset(memory->page_types, 0, types*sizeof(*memory->page_types)); } sprintf(meminfopath, "%s/node%d/meminfo", syspath, node); hwloc_parse_meminfo_info(topology, meminfopath, hwloc_snprintf(NULL, 0, "Node %d ", node), &memory->local_memory, &meminfo_hugepages_count, NULL /* no hugepage size in node-specific meminfo */, memory->page_types == NULL); if (memory->page_types) { uint64_t remaining_local_memory = memory->local_memory; if (has_sysfs_hugepages) { /* read from node%d/hugepages/hugepages-%skB/nr_hugepages */ hwloc_parse_hugepages_info(topology, path, memory, &remaining_local_memory); } else { /* get hugepage size from machine-specific meminfo since there is no size in node-specific meminfo, * hwloc_get_procfs_meminfo_info must have been called earlier */ meminfo_hugepages_size = topology->levels[0][0]->memory.page_types[1].size; /* use what we found in meminfo */ if (meminfo_hugepages_size) { memory->page_types[1].count = meminfo_hugepages_count; memory->page_types[1].size = meminfo_hugepages_size; remaining_local_memory -= meminfo_hugepages_count * meminfo_hugepages_size; } else { memory->page_types_len = 1; } } /* update what's remaining as normal pages */ memory->page_types[0].size = getpagesize(); memory->page_types[0].count = remaining_local_memory / memory->page_types[0].size; } } static void hwloc_parse_node_distance(const char *distancepath, unsigned nbnodes, float *distances, int fsroot_fd) { char string[4096]; /* enough for hundreds of nodes */ char *tmp, *next; FILE * fd; fd = hwloc_fopen(distancepath, "r", fsroot_fd); if (!fd) return; if (!fgets(string, sizeof(string), fd)) { fclose(fd); return; } tmp = string; while (tmp) { unsigned distance = strtoul(tmp, &next, 0); if (next == tmp) break; *distances = (float) distance; distances++; nbnodes--; if (!nbnodes) break; tmp = next+1; } fclose(fd); } static void look_sysfsnode(struct hwloc_topology *topology, const char *path, unsigned *found) { unsigned osnode; unsigned nbnodes = 0; DIR *dir; struct dirent *dirent; hwloc_obj_t node; hwloc_bitmap_t nodeset = hwloc_bitmap_alloc(); *found = 0; /* Get the list of nodes first */ dir = hwloc_opendir(path, topology->backend_params.sysfs.root_fd); if (dir) { while ((dirent = readdir(dir)) != NULL) { if (strncmp(dirent->d_name, "node", 4)) continue; osnode = strtoul(dirent->d_name+4, NULL, 0); hwloc_bitmap_set(nodeset, osnode); nbnodes++; } closedir(dir); } if (nbnodes <= 1) { hwloc_bitmap_free(nodeset); return; } /* For convenience, put these declarations inside a block. */ { hwloc_obj_t * nodes = calloc(nbnodes, sizeof(hwloc_obj_t)); float * distances = calloc(nbnodes*nbnodes, sizeof(float)); unsigned *indexes = calloc(nbnodes, sizeof(unsigned)); unsigned index_; if (NULL == indexes || NULL == distances || NULL == nodes) { free(nodes); free(indexes); free(distances); goto out; } /* Get node indexes now. We need them in order since Linux groups * sparse distances but keep them in order in the sysfs distance files. */ index_ = 0; hwloc_bitmap_foreach_begin (osnode, nodeset) { indexes[index_] = osnode; index_++; } hwloc_bitmap_foreach_end(); hwloc_bitmap_free(nodeset); #ifdef HWLOC_DEBUG hwloc_debug("%s", "numa distance indexes: "); for (index_ = 0; index_ < nbnodes; index_++) { hwloc_debug(" %u", indexes[index_]); } hwloc_debug("%s", "\n"); #endif /* Get actual distances now */ for (index_ = 0; index_ < nbnodes; index_++) { char nodepath[SYSFS_NUMA_NODE_PATH_LEN]; hwloc_bitmap_t cpuset; osnode = indexes[index_]; sprintf(nodepath, "%s/node%u/cpumap", path, osnode); cpuset = hwloc_parse_cpumap(nodepath, topology->backend_params.sysfs.root_fd); if (!cpuset) continue; node = hwloc_alloc_setup_object(HWLOC_OBJ_NODE, osnode); node->cpuset = cpuset; node->nodeset = hwloc_bitmap_alloc(); hwloc_bitmap_set(node->nodeset, osnode); hwloc_sysfs_node_meminfo_info(topology, path, osnode, &node->memory); hwloc_debug_1arg_bitmap("os node %u has cpuset %s\n", osnode, node->cpuset); hwloc_insert_object_by_cpuset(topology, node); nodes[index_] = node; /* Linux nodeX/distance file contains distance from X to other localities (from ACPI SLIT table or so), * store them in slots X*N...X*N+N-1 */ sprintf(nodepath, "%s/node%u/distance", path, osnode); hwloc_parse_node_distance(nodepath, nbnodes, distances+index_*nbnodes, topology->backend_params.sysfs.root_fd); } hwloc_topology__set_distance_matrix(topology, HWLOC_OBJ_NODE, nbnodes, indexes, nodes, distances); } out: *found = nbnodes; } /* Reads the entire file and returns bytes read if bytes_read != NULL * Returned pointer can be freed by using free(). */ static void * hwloc_read_raw(const char *p, const char *p1, size_t *bytes_read, int root_fd) { char *fname = NULL; char *ret = NULL; struct stat fs; int file = -1; unsigned len; len = strlen(p) + 1 + strlen(p1) + 1; fname = malloc(len); if (NULL == fname) { return NULL; } snprintf(fname, len, "%s/%s", p, p1); file = hwloc_open(fname, root_fd); if (-1 == file) { goto out; } if (fstat(file, &fs)) { goto out; } ret = (char *) malloc(fs.st_size); if (NULL != ret) { ssize_t cb = read(file, ret, fs.st_size); if (cb == -1) { free(ret); ret = NULL; } else { if (NULL != bytes_read) *bytes_read = cb; } } out: close(file); if (NULL != fname) { free(fname); } return ret; } /* Reads the entire file and returns it as a 0-terminated string * Returned pointer can be freed by using free(). */ static char * hwloc_read_str(const char *p, const char *p1, int root_fd) { size_t cb = 0; char *ret = hwloc_read_raw(p, p1, &cb, root_fd); if ((NULL != ret) && (0 < cb) && (0 != ret[cb-1])) { ret = realloc(ret, cb + 1); ret[cb] = 0; } return ret; } /* Reads first 32bit bigendian value */ static ssize_t hwloc_read_unit32be(const char *p, const char *p1, uint32_t *buf, int root_fd) { size_t cb = 0; uint32_t *tmp = hwloc_read_raw(p, p1, &cb, root_fd); if (sizeof(*buf) != cb) { errno = EINVAL; return -1; } *buf = htonl(*tmp); free(tmp); return sizeof(*buf); } typedef struct { unsigned int n, allocated; struct { hwloc_bitmap_t cpuset; uint32_t phandle; uint32_t l2_cache; char *name; } *p; } device_tree_cpus_t; static void add_device_tree_cpus_node(device_tree_cpus_t *cpus, hwloc_bitmap_t cpuset, uint32_t l2_cache, uint32_t phandle, const char *name) { if (cpus->n == cpus->allocated) { if (!cpus->allocated) cpus->allocated = 64; else cpus->allocated *= 2; cpus->p = realloc(cpus->p, cpus->allocated * sizeof(cpus->p[0])); } cpus->p[cpus->n].phandle = phandle; cpus->p[cpus->n].cpuset = (NULL == cpuset)?NULL:hwloc_bitmap_dup(cpuset); cpus->p[cpus->n].l2_cache = l2_cache; cpus->p[cpus->n].name = strdup(name); ++cpus->n; } /* Walks over the cache list in order to detect nested caches and CPU mask for each */ static int look_powerpc_device_tree_discover_cache(device_tree_cpus_t *cpus, uint32_t phandle, unsigned int *level, hwloc_bitmap_t cpuset) { unsigned int i; int ret = -1; if ((NULL == level) || (NULL == cpuset) || phandle == (uint32_t) -1) return ret; for (i = 0; i < cpus->n; ++i) { if (phandle != cpus->p[i].l2_cache) continue; if (NULL != cpus->p[i].cpuset) { hwloc_bitmap_or(cpuset, cpuset, cpus->p[i].cpuset); ret = 0; } else { ++(*level); if (0 == look_powerpc_device_tree_discover_cache(cpus, cpus->p[i].phandle, level, cpuset)) ret = 0; } } return ret; } static void try_add_cache_from_device_tree_cpu(struct hwloc_topology *topology, const char *cpu, unsigned int level, hwloc_bitmap_t cpuset) { /* Ignore Instruction caches */ /* d-cache-block-size - ignore */ /* d-cache-line-size - to read, in bytes */ /* d-cache-sets - ignore */ /* d-cache-size - to read, in bytes */ /* d-tlb-sets - ignore */ /* d-tlb-size - ignore, always 0 on power6 */ /* i-cache-* and i-tlb-* represent instruction cache, ignore */ uint32_t d_cache_line_size = 0, d_cache_size = 0; struct hwloc_obj *c = NULL; hwloc_read_unit32be(cpu, "d-cache-line-size", &d_cache_line_size, topology->backend_params.sysfs.root_fd); hwloc_read_unit32be(cpu, "d-cache-size", &d_cache_size, topology->backend_params.sysfs.root_fd); if ( (0 == d_cache_line_size) && (0 == d_cache_size) ) return; c = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, -1); c->attr->cache.depth = level; c->attr->cache.linesize = d_cache_line_size; c->attr->cache.size = d_cache_size; c->cpuset = hwloc_bitmap_dup(cpuset); hwloc_debug_1arg_bitmap("cache depth %d has cpuset %s\n", level, c->cpuset); hwloc_insert_object_by_cpuset(topology, c); } /* * Discovers L1/L2/L3 cache information on IBM PowerPC systems for old kernels (RHEL5.*) * which provide NUMA nodes information without any details */ static void look_powerpc_device_tree(struct hwloc_topology *topology) { device_tree_cpus_t cpus; const char ofroot[] = "/proc/device-tree/cpus"; unsigned int i; int root_fd = topology->backend_params.sysfs.root_fd; DIR *dt = hwloc_opendir(ofroot, root_fd); struct dirent *dirent; cpus.n = 0; cpus.p = NULL; cpus.allocated = 0; if (NULL == dt) return; while (NULL != (dirent = readdir(dt))) { struct stat statbuf; int err; char *cpu; char *device_type; uint32_t reg = -1, l2_cache = -1, phandle = -1; unsigned len; if ('.' == dirent->d_name[0]) continue; len = sizeof(ofroot) + 1 + strlen(dirent->d_name) + 1; cpu = malloc(len); if (NULL == cpu) { continue; } snprintf(cpu, len, "%s/%s", ofroot, dirent->d_name); err = hwloc_stat(cpu, &statbuf, root_fd); if (err < 0 || !S_ISDIR(statbuf.st_mode)) goto cont; device_type = hwloc_read_str(cpu, "device_type", root_fd); if (NULL == device_type) goto cont; hwloc_read_unit32be(cpu, "reg", ®, root_fd); if (hwloc_read_unit32be(cpu, "next-level-cache", &l2_cache, root_fd) == -1) hwloc_read_unit32be(cpu, "l2-cache", &l2_cache, root_fd); if (hwloc_read_unit32be(cpu, "phandle", &phandle, root_fd) == -1) if (hwloc_read_unit32be(cpu, "ibm,phandle", &phandle, root_fd) == -1) hwloc_read_unit32be(cpu, "linux,phandle", &phandle, root_fd); if (0 == strcmp(device_type, "cache")) { add_device_tree_cpus_node(&cpus, NULL, l2_cache, phandle, dirent->d_name); } else if (0 == strcmp(device_type, "cpu")) { /* Found CPU */ hwloc_bitmap_t cpuset = NULL; size_t cb = 0; uint32_t *threads = hwloc_read_raw(cpu, "ibm,ppc-interrupt-server#s", &cb, root_fd); uint32_t nthreads = cb / sizeof(threads[0]); if (NULL != threads) { cpuset = hwloc_bitmap_alloc(); for (i = 0; i < nthreads; ++i) { if (hwloc_bitmap_isset(topology->levels[0][0]->complete_cpuset, ntohl(threads[i]))) hwloc_bitmap_set(cpuset, ntohl(threads[i])); } free(threads); } else if ((unsigned int)-1 != reg) { cpuset = hwloc_bitmap_alloc(); hwloc_bitmap_set(cpuset, reg); } if (NULL == cpuset) { hwloc_debug("%s has no \"reg\" property, skipping\n", cpu); } else { struct hwloc_obj *core = NULL; add_device_tree_cpus_node(&cpus, cpuset, l2_cache, phandle, dirent->d_name); /* Add core */ core = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, reg); core->cpuset = hwloc_bitmap_dup(cpuset); hwloc_insert_object_by_cpuset(topology, core); /* Add L1 cache */ try_add_cache_from_device_tree_cpu(topology, cpu, 1, cpuset); hwloc_bitmap_free(cpuset); } free(device_type); } cont: free(cpu); } closedir(dt); /* No cores and L2 cache were found, exiting */ if (0 == cpus.n) { hwloc_debug("No cores and L2 cache were found in %s, exiting\n", ofroot); return; } #ifdef HWLOC_DEBUG for (i = 0; i < cpus.n; ++i) { hwloc_debug("%i: %s ibm,phandle=%08X l2_cache=%08X ", i, cpus.p[i].name, cpus.p[i].phandle, cpus.p[i].l2_cache); if (NULL == cpus.p[i].cpuset) { hwloc_debug("%s\n", "no cpuset"); } else { hwloc_debug_bitmap("cpuset %s\n", cpus.p[i].cpuset); } } #endif /* Scan L2/L3/... caches */ for (i = 0; i < cpus.n; ++i) { unsigned int level = 2; hwloc_bitmap_t cpuset; /* Skip real CPUs */ if (NULL != cpus.p[i].cpuset) continue; /* Calculate cache level and CPU mask */ cpuset = hwloc_bitmap_alloc(); if (0 == look_powerpc_device_tree_discover_cache(&cpus, cpus.p[i].phandle, &level, cpuset)) { char *cpu; unsigned len; len = sizeof(ofroot) + 1 + strlen(cpus.p[i].name) + 1; cpu = malloc(len); if (NULL == cpu) { return; } snprintf(cpu, len, "%s/%s", ofroot, cpus.p[i].name); try_add_cache_from_device_tree_cpu(topology, cpu, level, cpuset); free(cpu); } hwloc_bitmap_free(cpuset); } /* Do cleanup */ for (i = 0; i < cpus.n; ++i) { hwloc_bitmap_free(cpus.p[i].cpuset); free(cpus.p[i].name); } free(cpus.p); } /* Look at Linux' /sys/devices/system/cpu/cpu%d/topology/ */ static void look_sysfscpu(struct hwloc_topology *topology, const char *path) { hwloc_bitmap_t cpuset; /* Set of cpus for which we have topology information */ #define CPU_TOPOLOGY_STR_LEN 128 char str[CPU_TOPOLOGY_STR_LEN]; DIR *dir; int i,j; FILE *fd; unsigned caches_added; cpuset = hwloc_bitmap_alloc(); /* fill the cpuset of interesting cpus */ dir = hwloc_opendir(path, topology->backend_params.sysfs.root_fd); if (dir) { struct dirent *dirent; while ((dirent = readdir(dir)) != NULL) { unsigned long cpu; char online[2]; if (strncmp(dirent->d_name, "cpu", 3)) continue; cpu = strtoul(dirent->d_name+3, NULL, 0); /* Maybe we don't have topology information but at least it exists */ hwloc_bitmap_set(topology->levels[0][0]->complete_cpuset, cpu); /* check whether this processor is online */ sprintf(str, "%s/cpu%lu/online", path, cpu); fd = hwloc_fopen(str, "r", topology->backend_params.sysfs.root_fd); if (fd) { if (fgets(online, sizeof(online), fd)) { fclose(fd); if (atoi(online)) { hwloc_debug("os proc %lu is online\n", cpu); } else { hwloc_debug("os proc %lu is offline\n", cpu); hwloc_bitmap_clr(topology->levels[0][0]->online_cpuset, cpu); } } else { fclose(fd); } } /* check whether the kernel exports topology information for this cpu */ sprintf(str, "%s/cpu%lu/topology", path, cpu); if (hwloc_access(str, X_OK, topology->backend_params.sysfs.root_fd) < 0 && errno == ENOENT) { hwloc_debug("os proc %lu has no accessible %s/cpu%lu/topology\n", cpu, path, cpu); continue; } hwloc_bitmap_set(cpuset, cpu); } closedir(dir); } topology->support.discovery->pu = 1; hwloc_debug_1arg_bitmap("found %d cpu topologies, cpuset %s\n", hwloc_bitmap_weight(cpuset), cpuset); caches_added = 0; hwloc_bitmap_foreach_begin(i, cpuset) { struct hwloc_obj *sock, *core, *thread; hwloc_bitmap_t socketset, coreset, threadset, savedcoreset; unsigned mysocketid, mycoreid; int threadwithcoreid = 0; /* look at the socket */ mysocketid = 0; /* shut-up the compiler */ sprintf(str, "%s/cpu%d/topology/physical_package_id", path, i); hwloc_parse_sysfs_unsigned(str, &mysocketid, topology->backend_params.sysfs.root_fd); sprintf(str, "%s/cpu%d/topology/core_siblings", path, i); socketset = hwloc_parse_cpumap(str, topology->backend_params.sysfs.root_fd); if (socketset && hwloc_bitmap_first(socketset) == i) { /* first cpu in this socket, add the socket */ sock = hwloc_alloc_setup_object(HWLOC_OBJ_SOCKET, mysocketid); sock->cpuset = socketset; hwloc_debug_1arg_bitmap("os socket %u has cpuset %s\n", mysocketid, socketset); hwloc_insert_object_by_cpuset(topology, sock); socketset = NULL; /* don't free it */ } hwloc_bitmap_free(socketset); /* look at the core */ mycoreid = 0; /* shut-up the compiler */ sprintf(str, "%s/cpu%d/topology/core_id", path, i); hwloc_parse_sysfs_unsigned(str, &mycoreid, topology->backend_params.sysfs.root_fd); sprintf(str, "%s/cpu%d/topology/thread_siblings", path, i); coreset = hwloc_parse_cpumap(str, topology->backend_params.sysfs.root_fd); savedcoreset = coreset; /* store it for later work-arounds */ if (coreset && hwloc_bitmap_weight(coreset) > 1) { /* check if this is hyperthreading or different coreids */ unsigned siblingid, siblingcoreid; hwloc_bitmap_t set = hwloc_bitmap_dup(coreset); hwloc_bitmap_clr(set, i); siblingid = hwloc_bitmap_first(set); siblingcoreid = mycoreid; sprintf(str, "%s/cpu%d/topology/core_id", path, siblingid); hwloc_parse_sysfs_unsigned(str, &siblingcoreid, topology->backend_params.sysfs.root_fd); threadwithcoreid = (siblingcoreid != mycoreid); hwloc_bitmap_free(set); } if (coreset && (hwloc_bitmap_first(coreset) == i || threadwithcoreid)) { /* regular core */ core = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, mycoreid); if (threadwithcoreid) { /* amd multicore compute-unit, create one core per thread */ core->cpuset = hwloc_bitmap_alloc(); hwloc_bitmap_set(core->cpuset, i); } else { core->cpuset = coreset; } hwloc_debug_1arg_bitmap("os core %u has cpuset %s\n", mycoreid, coreset); hwloc_insert_object_by_cpuset(topology, core); coreset = NULL; /* don't free it */ } /* look at the thread */ threadset = hwloc_bitmap_alloc(); hwloc_bitmap_only(threadset, i); /* add the thread */ thread = hwloc_alloc_setup_object(HWLOC_OBJ_PU, i); thread->cpuset = threadset; hwloc_debug_1arg_bitmap("thread %d has cpuset %s\n", i, threadset); hwloc_insert_object_by_cpuset(topology, thread); /* look at the caches */ for(j=0; j<10; j++) { #define SHARED_CPU_MAP_STRLEN 128 char mappath[SHARED_CPU_MAP_STRLEN]; char str2[20]; /* enough for a level number (one digit) or a type (Data/Instruction/Unified) */ struct hwloc_obj *cache; hwloc_bitmap_t cacheset; unsigned long kB = 0; unsigned linesize = 0; int depth; /* 0 for L1, .... */ /* get the cache level depth */ sprintf(mappath, "%s/cpu%d/cache/index%d/level", path, i, j); fd = hwloc_fopen(mappath, "r", topology->backend_params.sysfs.root_fd); if (fd) { if (fgets(str2,sizeof(str2), fd)) depth = strtoul(str2, NULL, 10)-1; else continue; fclose(fd); } else continue; /* ignore Instruction caches */ sprintf(mappath, "%s/cpu%d/cache/index%d/type", path, i, j); fd = hwloc_fopen(mappath, "r", topology->backend_params.sysfs.root_fd); if (fd) { if (fgets(str2, sizeof(str2), fd)) { fclose(fd); if (!strncmp(str2, "Instruction", 11)) continue; } else { fclose(fd); continue; } } else continue; /* get the cache size */ sprintf(mappath, "%s/cpu%d/cache/index%d/size", path, i, j); fd = hwloc_fopen(mappath, "r", topology->backend_params.sysfs.root_fd); if (fd) { if (fgets(str2,sizeof(str2), fd)) kB = atol(str2); /* in kB */ fclose(fd); } /* get the line size */ sprintf(mappath, "%s/cpu%d/cache/index%d/coherency_line_size", path, i, j); fd = hwloc_fopen(mappath, "r", topology->backend_params.sysfs.root_fd); if (fd) { if (fgets(str2,sizeof(str2), fd)) linesize = atol(str2); /* in bytes */ fclose(fd); } sprintf(mappath, "%s/cpu%d/cache/index%d/shared_cpu_map", path, i, j); cacheset = hwloc_parse_cpumap(mappath, topology->backend_params.sysfs.root_fd); if (cacheset) { if (hwloc_bitmap_weight(cacheset) < 1) { /* mask is wrong (useful for many itaniums) */ if (savedcoreset) /* assume it's a core-specific cache */ hwloc_bitmap_copy(cacheset, savedcoreset); else /* assumes it's not shared */ hwloc_bitmap_only(cacheset, i); } if (hwloc_bitmap_first(cacheset) == i) { /* first cpu in this cache, add the cache */ cache = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, -1); cache->attr->cache.size = kB << 10; cache->attr->cache.depth = depth+1; cache->attr->cache.linesize = linesize; cache->cpuset = cacheset; hwloc_debug_1arg_bitmap("cache depth %d has cpuset %s\n", depth, cacheset); hwloc_insert_object_by_cpuset(topology, cache); cacheset = NULL; /* don't free it */ ++caches_added; } } hwloc_bitmap_free(cacheset); } hwloc_bitmap_free(coreset); } hwloc_bitmap_foreach_end(); if (0 == caches_added) look_powerpc_device_tree(topology); hwloc_bitmap_free(cpuset); } /* Look at Linux' /proc/cpuinfo */ # define PROCESSOR "processor" # define PHYSID "physical id" # define COREID "core id" #define HWLOC_NBMAXCPUS 1024 /* FIXME: drop */ static int look_cpuinfo(struct hwloc_topology *topology, const char *path, hwloc_bitmap_t online_cpuset) { FILE *fd; char *str = NULL; char *endptr; unsigned len; unsigned proc_physids[HWLOC_NBMAXCPUS]; unsigned osphysids[HWLOC_NBMAXCPUS]; unsigned proc_coreids[HWLOC_NBMAXCPUS]; unsigned oscoreids[HWLOC_NBMAXCPUS]; unsigned proc_osphysids[HWLOC_NBMAXCPUS]; unsigned core_osphysids[HWLOC_NBMAXCPUS]; unsigned procid_max=0; unsigned numprocs=0; unsigned numsockets=0; unsigned numcores=0; unsigned long physid; unsigned long coreid; unsigned missingsocket; unsigned missingcore; unsigned long processor = (unsigned long) -1; unsigned i; hwloc_bitmap_t cpuset; hwloc_obj_t obj; for (i = 0; i < HWLOC_NBMAXCPUS; i++) { proc_physids[i] = -1; osphysids[i] = -1; proc_coreids[i] = -1; oscoreids[i] = -1; proc_osphysids[i] = -1; core_osphysids[i] = -1; } if (!(fd=hwloc_fopen(path,"r", topology->backend_params.sysfs.root_fd))) { hwloc_debug("%s", "could not open /proc/cpuinfo\n"); return -1; } cpuset = hwloc_bitmap_alloc(); /* Just record information and count number of sockets and cores */ len = strlen(PHYSID) + 1 + 9 + 1 + 1; str = malloc(len); hwloc_debug("%s", "\n\n * Topology extraction from /proc/cpuinfo *\n\n"); while (fgets(str,len,fd)!=NULL) { # define getprocnb_begin(field, var) \ if ( !strncmp(field,str,strlen(field))) \ { \ char *c = strchr(str, ':')+1; \ var = strtoul(c,&endptr,0); \ if (endptr==c) \ { \ hwloc_debug("%s", "no number in "field" field of /proc/cpuinfo\n"); \ hwloc_bitmap_free(cpuset); \ free(str); \ return -1; \ } \ else if (var==ULONG_MAX) \ { \ hwloc_debug("%s", "too big "field" number in /proc/cpuinfo\n"); \ hwloc_bitmap_free(cpuset); \ free(str); \ return -1; \ } \ hwloc_debug(field " %lu\n", var) # define getprocnb_end() \ } getprocnb_begin(PROCESSOR,processor); hwloc_bitmap_set(cpuset, processor); obj = hwloc_alloc_setup_object(HWLOC_OBJ_PU, processor); obj->cpuset = hwloc_bitmap_alloc(); hwloc_bitmap_only(obj->cpuset, processor); hwloc_debug_2args_bitmap("cpu %u (os %lu) has cpuset %s\n", numprocs, processor, obj->cpuset); numprocs++; hwloc_insert_object_by_cpuset(topology, obj); getprocnb_end() else getprocnb_begin(PHYSID,physid); proc_osphysids[processor]=physid; for (i=0; isupport.discovery->pu = 1; /* setup the final number of procs */ procid_max = processor + 1; hwloc_bitmap_copy(online_cpuset, cpuset); hwloc_bitmap_free(cpuset); hwloc_debug("%u online processors found, with id max %u\n", numprocs, procid_max); hwloc_debug_bitmap("online processor cpuset: %s\n", online_cpuset); hwloc_debug("%s", "\n * Topology summary *\n"); hwloc_debug("%u processors (%u max id)\n", numprocs, procid_max); /* Some buggy Linuxes don't provide numbers for processor 0, which makes us * provide bogus information. We should rather drop it. */ missingsocket=0; missingcore=0; hwloc_bitmap_foreach_begin(processor, online_cpuset) if (proc_physids[processor] == (unsigned) -1) missingsocket=1; if (proc_coreids[processor] == (unsigned) -1) missingcore=1; if (missingcore && missingsocket) /* No usable information, no need to continue */ break; hwloc_bitmap_foreach_end(); hwloc_debug("%u sockets%s\n", numsockets, missingsocket ? ", but some missing socket" : ""); if (!missingsocket && numsockets>0) hwloc_setup_level(procid_max, numsockets, osphysids, proc_physids, topology, HWLOC_OBJ_SOCKET); look_powerpc_device_tree(topology); hwloc_debug("%u cores%s\n", numcores, missingcore ? ", but some missing core" : ""); if (!missingcore && numcores>0) hwloc_setup_level(procid_max, numcores, oscoreids, proc_coreids, topology, HWLOC_OBJ_CORE); return 0; } static void hwloc__get_dmi_one_info(struct hwloc_topology *topology, hwloc_obj_t obj, const char *sysfs_name, const char *hwloc_name) { char sysfs_path[128]; char dmi_line[64]; char *tmp; FILE *fd; snprintf(sysfs_path, sizeof(sysfs_path), "/sys/class/dmi/id/%s", sysfs_name); dmi_line[0] = '\0'; fd = hwloc_fopen(sysfs_path, "r", topology->backend_params.sysfs.root_fd); if (fd) { tmp = fgets(dmi_line, sizeof(dmi_line), fd); fclose (fd); if (tmp && dmi_line[0] != '\0') { tmp = strchr(dmi_line, '\n'); if (tmp) *tmp = '\0'; hwloc_debug("found %s '%s'\n", hwloc_name, dmi_line); hwloc_add_object_info(obj, hwloc_name, dmi_line); } } } static void hwloc__get_dmi_info(struct hwloc_topology *topology, hwloc_obj_t obj) { hwloc__get_dmi_one_info(topology, obj, "product_name", "DMIProductName"); hwloc__get_dmi_one_info(topology, obj, "product_version", "DMIProductVersion"); hwloc__get_dmi_one_info(topology, obj, "product_serial", "DMIProductSerial"); hwloc__get_dmi_one_info(topology, obj, "product_uuid", "DMIProductUUID"); hwloc__get_dmi_one_info(topology, obj, "board_vendor", "DMIBoardVendor"); hwloc__get_dmi_one_info(topology, obj, "board_name", "DMIBoardName"); hwloc__get_dmi_one_info(topology, obj, "board_version", "DMIBoardVersion"); hwloc__get_dmi_one_info(topology, obj, "board_serial", "DMIBoardSerial"); hwloc__get_dmi_one_info(topology, obj, "board_asset_tag", "DMIBoardAssetTag"); hwloc__get_dmi_one_info(topology, obj, "chassis_vendor", "DMIChassisVendor"); hwloc__get_dmi_one_info(topology, obj, "chassis_type", "DMIChassisType"); hwloc__get_dmi_one_info(topology, obj, "chassis_version", "DMIChassisVersion"); hwloc__get_dmi_one_info(topology, obj, "chassis_serial", "DMIChassisSerial"); hwloc__get_dmi_one_info(topology, obj, "chassis_asset_tag", "DMIChassisAssetTag"); hwloc__get_dmi_one_info(topology, obj, "bios_vendor", "DMIBIOSVendor"); hwloc__get_dmi_one_info(topology, obj, "bios_version", "DMIBIOSVersion"); hwloc__get_dmi_one_info(topology, obj, "bios_date", "DMIBIOSDate"); hwloc__get_dmi_one_info(topology, obj, "sys_vendor", "DMISysVendor"); } void hwloc_look_linux(struct hwloc_topology *topology) { DIR *nodes_dir; unsigned nbnodes; char *cpuset_mntpnt, *cgroup_mntpnt, *cpuset_name = NULL; int err; /* Gather the list of admin-disabled cpus and mems */ hwloc_find_linux_cpuset_mntpnt(&cgroup_mntpnt, &cpuset_mntpnt, topology->backend_params.sysfs.root_fd); if (cgroup_mntpnt || cpuset_mntpnt) { cpuset_name = hwloc_read_linux_cpuset_name(topology->backend_params.sysfs.root_fd, topology->pid); if (cpuset_name) { hwloc_admin_disable_set_from_cpuset(topology, cgroup_mntpnt, cpuset_mntpnt, cpuset_name, "cpus", topology->levels[0][0]->allowed_cpuset); hwloc_admin_disable_set_from_cpuset(topology, cgroup_mntpnt, cpuset_mntpnt, cpuset_name, "mems", topology->levels[0][0]->allowed_nodeset); } free(cgroup_mntpnt); free(cpuset_mntpnt); } nodes_dir = hwloc_opendir("/proc/nodes", topology->backend_params.sysfs.root_fd); if (nodes_dir) { /* Kerrighed */ struct dirent *dirent; char path[128]; hwloc_obj_t machine; hwloc_bitmap_t machine_online_set; /* replace top-level object type with SYSTEM and add some MACHINE underneath */ topology->levels[0][0]->type = HWLOC_OBJ_SYSTEM; topology->levels[0][0]->name = strdup("Kerrighed"); /* No cpuset support for now. */ /* No sys support for now. */ while ((dirent = readdir(nodes_dir)) != NULL) { unsigned long node; if (strncmp(dirent->d_name, "node", 4)) continue; machine_online_set = hwloc_bitmap_alloc(); node = strtoul(dirent->d_name+4, NULL, 0); snprintf(path, sizeof(path), "/proc/nodes/node%lu/cpuinfo", node); err = look_cpuinfo(topology, path, machine_online_set); if (err < 0) continue; hwloc_bitmap_or(topology->levels[0][0]->online_cpuset, topology->levels[0][0]->online_cpuset, machine_online_set); machine = hwloc_alloc_setup_object(HWLOC_OBJ_MACHINE, node); machine->cpuset = machine_online_set; hwloc_debug_1arg_bitmap("machine number %lu has cpuset %s\n", node, machine_online_set); hwloc_insert_object_by_cpuset(topology, machine); /* Get the machine memory attributes */ hwloc_get_kerrighed_node_meminfo_info(topology, node, &machine->memory); /* Gather DMI info */ /* FIXME: get the right DMI info of each machine */ hwloc__get_dmi_info(topology, machine); } closedir(nodes_dir); } else { /* Get the machine memory attributes */ hwloc_get_procfs_meminfo_info(topology, &topology->levels[0][0]->memory); /* Gather NUMA information. Must be after hwloc_get_procfs_meminfo_info so that the hugepage size is known */ look_sysfsnode(topology, "/sys/devices/system/node", &nbnodes); /* if we found some numa nodes, the machine object has no local memory */ if (nbnodes) { unsigned i; topology->levels[0][0]->memory.local_memory = 0; if (topology->levels[0][0]->memory.page_types) for(i=0; ilevels[0][0]->memory.page_types_len; i++) topology->levels[0][0]->memory.page_types[i].count = 0; } /* Gather the list of cpus now */ if (getenv("HWLOC_LINUX_USE_CPUINFO") || (hwloc_access("/sys/devices/system/cpu/cpu0/topology/core_siblings", R_OK, topology->backend_params.sysfs.root_fd) < 0 && hwloc_access("/sys/devices/system/cpu/cpu0/topology/thread_siblings", R_OK, topology->backend_params.sysfs.root_fd) < 0)) { /* revert to reading cpuinfo only if /sys/.../topology unavailable (before 2.6.16) * or not containing anything interesting */ err = look_cpuinfo(topology, "/proc/cpuinfo", topology->levels[0][0]->online_cpuset); if (err < 0) { if (topology->is_thissystem) hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology)); else /* fsys-root but not this system, no way, assume there's just 1 * processor :/ */ hwloc_setup_pu_level(topology, 1); } } else { look_sysfscpu(topology, "/sys/devices/system/cpu"); } /* Gather DMI info */ hwloc__get_dmi_info(topology, topology->levels[0][0]); } hwloc_add_object_info(topology->levels[0][0], "Backend", "Linux"); if (cpuset_name) { hwloc_add_object_info(topology->levels[0][0], "LinuxCgroup", cpuset_name); free(cpuset_name); } /* gather uname info if fsroot wasn't changed */ if (topology->is_thissystem) hwloc_add_uname_info(topology); } void hwloc_set_linux_hooks(struct hwloc_topology *topology) { topology->set_thisthread_cpubind = hwloc_linux_set_thisthread_cpubind; topology->get_thisthread_cpubind = hwloc_linux_get_thisthread_cpubind; topology->set_thisproc_cpubind = hwloc_linux_set_thisproc_cpubind; topology->get_thisproc_cpubind = hwloc_linux_get_thisproc_cpubind; topology->set_proc_cpubind = hwloc_linux_set_proc_cpubind; topology->get_proc_cpubind = hwloc_linux_get_proc_cpubind; #if HAVE_DECL_PTHREAD_SETAFFINITY_NP topology->set_thread_cpubind = hwloc_linux_set_thread_cpubind; #endif /* HAVE_DECL_PTHREAD_SETAFFINITY_NP */ #if HAVE_DECL_PTHREAD_GETAFFINITY_NP topology->get_thread_cpubind = hwloc_linux_get_thread_cpubind; #endif /* HAVE_DECL_PTHREAD_GETAFFINITY_NP */ topology->get_thisthread_last_cpu_location = hwloc_linux_get_thisthread_last_cpu_location; topology->get_thisproc_last_cpu_location = hwloc_linux_get_thisproc_last_cpu_location; topology->get_proc_last_cpu_location = hwloc_linux_get_proc_last_cpu_location; #ifdef HWLOC_HAVE_SET_MEMPOLICY topology->set_thisthread_membind = hwloc_linux_set_thisthread_membind; topology->get_thisthread_membind = hwloc_linux_get_thisthread_membind; #endif /* HWLOC_HAVE_SET_MEMPOLICY */ #ifdef HWLOC_HAVE_MBIND topology->set_area_membind = hwloc_linux_set_area_membind; topology->alloc_membind = hwloc_linux_alloc_membind; topology->alloc = hwloc_alloc_mmap; topology->free_membind = hwloc_free_mmap; topology->support.membind->firsttouch_membind = 1; topology->support.membind->bind_membind = 1; topology->support.membind->interleave_membind = 1; #endif /* HWLOC_HAVE_MBIND */ #if (defined HWLOC_HAVE_MIGRATE_PAGES) || ((defined HWLOC_HAVE_MBIND) && (defined MPOL_MF_MOVE)) topology->support.membind->migrate_membind = 1; #endif }