Commit bc87a8ff authored by Hisham Muhammad's avatar Hisham Muhammad
Browse files

Remove bundled hwloc-1.2.1. Use either native Linux affinity support or an external libhwloc.

(for details see https://sourceforge.net/mailarchive/forum.php?thread_name=CAJpkDYeZpwqcWxZ77wq6bMrnhn-KzkU1xAqb3cU0drfnA3n9FQ%40mail.gmail.com&forum_name=htop-general )
parent 7ca10817
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2010 INRIA. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux 1
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
/* Misc internals routines. */
#ifndef HWLOC_PRIVATE_MISC_H
#define HWLOC_PRIVATE_MISC_H
#include <hwloc/autogen/config.h>
#include <private/autogen/config.h>
#include <private/private.h>
/* On some systems, snprintf returns the size of written data, not the actually
* required size. hwloc_snprintf always report the actually required size. */
int hwloc_snprintf(char *str, size_t size, const char *format, ...) __hwloc_attribute_format(printf, 3, 4);
/* Check whether needle matches the beginning of haystack, at least n, and up
* to a colon or \0 */
HWLOC_DECLSPEC
int hwloc_namecoloncmp(const char *haystack, const char *needle, size_t n);
/* Compile-time assertion */
#define HWLOC_BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)]))
#define HWLOC_BITS_PER_LONG (HWLOC_SIZEOF_UNSIGNED_LONG * 8)
#define HWLOC_BITS_PER_INT (HWLOC_SIZEOF_UNSIGNED_INT * 8)
#if (HWLOC_BITS_PER_LONG != 32) && (HWLOC_BITS_PER_LONG != 64)
#error "unknown size for unsigned long."
#endif
#if (HWLOC_BITS_PER_INT != 16) && (HWLOC_BITS_PER_INT != 32) && (HWLOC_BITS_PER_INT != 64)
#error "unknown size for unsigned int."
#endif
/**
* ffsl helpers.
*/
#ifdef __GNUC__
# if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))
/* Starting from 3.4, gcc has a long variant. */
# define hwloc_ffsl(x) __builtin_ffsl(x)
# else
# define hwloc_ffs(x) __builtin_ffs(x)
# define HWLOC_NEED_FFSL
# endif
#elif defined(HWLOC_HAVE_FFSL)
# ifndef HWLOC_HAVE_DECL_FFSL
extern int ffsl(long) __hwloc_attribute_const;
# endif
# define hwloc_ffsl(x) ffsl(x)
#elif defined(HWLOC_HAVE_FFS)
# ifndef HWLOC_HAVE_DECL_FFS
extern int ffs(int) __hwloc_attribute_const;
# endif
# define hwloc_ffs(x) ffs(x)
# define HWLOC_NEED_FFSL
#else /* no ffs implementation */
static __hwloc_inline int __hwloc_attribute_const
hwloc_ffsl(unsigned long x)
{
int i;
if (!x)
return 0;
i = 1;
#if HWLOC_BITS_PER_LONG >= 64
if (!(x & 0xfffffffful)) {
x >>= 32;
i += 32;
}
#endif
if (!(x & 0xffffu)) {
x >>= 16;
i += 16;
}
if (!(x & 0xff)) {
x >>= 8;
i += 8;
}
if (!(x & 0xf)) {
x >>= 4;
i += 4;
}
if (!(x & 0x3)) {
x >>= 2;
i += 2;
}
if (!(x & 0x1)) {
x >>= 1;
i += 1;
}
return i;
}
#endif
#ifdef HWLOC_NEED_FFSL
/* We only have an int ffs(int) implementation, build a long one. */
/* First make it 32 bits if it was only 16. */
static __hwloc_inline int __hwloc_attribute_const
hwloc_ffs32(unsigned long x)
{
#if HWLOC_BITS_PER_INT == 16
int low_ffs, hi_ffs;
low_ffs = hwloc_ffs(x & 0xfffful);
if (low_ffs)
return low_ffs;
hi_ffs = hwloc_ffs(x >> 16);
if (hi_ffs)
return hi_ffs + 16;
return 0;
#else
return hwloc_ffs(x);
#endif
}
/* Then make it 64 bit if longs are. */
static __hwloc_inline int __hwloc_attribute_const
hwloc_ffsl(unsigned long x)
{
#if HWLOC_BITS_PER_LONG == 64
int low_ffs, hi_ffs;
low_ffs = hwloc_ffs32(x & 0xfffffffful);
if (low_ffs)
return low_ffs;
hi_ffs = hwloc_ffs32(x >> 32);
if (hi_ffs)
return hi_ffs + 32;
return 0;
#else
return hwloc_ffs32(x);
#endif
}
#endif
/**
* flsl helpers.
*/
#ifdef __GNUC_____
# if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))
# define hwloc_flsl(x) (x ? 8*sizeof(long) - __builtin_clzl(x) : 0)
# else
# define hwloc_fls(x) (x ? 8*sizeof(int) - __builtin_clz(x) : 0)
# define HWLOC_NEED_FLSL
# endif
#elif defined(HWLOC_HAVE_FLSL)
# ifndef HWLOC_HAVE_DECL_FLSL
extern int flsl(long) __hwloc_attribute_const;
# endif
# define hwloc_flsl(x) flsl(x)
#elif defined(HWLOC_HAVE_CLZL)
# ifndef HWLOC_HAVE_DECL_CLZL
extern int clzl(long) __hwloc_attribute_const;
# endif
# define hwloc_flsl(x) (x ? 8*sizeof(long) - clzl(x) : 0)
#elif defined(HWLOC_HAVE_FLS)
# ifndef HWLOC_HAVE_DECL_FLS
extern int fls(int) __hwloc_attribute_const;
# endif
# define hwloc_fls(x) fls(x)
# define HWLOC_NEED_FLSL
#elif defined(HWLOC_HAVE_CLZ)
# ifndef HWLOC_HAVE_DECL_CLZ
extern int clz(int) __hwloc_attribute_const;
# endif
# define hwloc_fls(x) (x ? 8*sizeof(int) - clz(x) : 0)
# define HWLOC_NEED_FLSL
#else /* no fls implementation */
static __hwloc_inline int __hwloc_attribute_const
hwloc_flsl(unsigned long x)
{
int i = 0;
if (!x)
return 0;
i = 1;
#if HWLOC_BITS_PER_LONG >= 64
if ((x & 0xffffffff00000000ul)) {
x >>= 32;
i += 32;
}
#endif
if ((x & 0xffff0000u)) {
x >>= 16;
i += 16;
}
if ((x & 0xff00)) {
x >>= 8;
i += 8;
}
if ((x & 0xf0)) {
x >>= 4;
i += 4;
}
if ((x & 0xc)) {
x >>= 2;
i += 2;
}
if ((x & 0x2)) {
x >>= 1;
i += 1;
}
return i;
}
#endif
#ifdef HWLOC_NEED_FLSL
/* We only have an int fls(int) implementation, build a long one. */
/* First make it 32 bits if it was only 16. */
static __hwloc_inline int __hwloc_attribute_const
hwloc_fls32(unsigned long x)
{
#if HWLOC_BITS_PER_INT == 16
int low_fls, hi_fls;
hi_fls = hwloc_fls(x >> 16);
if (hi_fls)
return hi_fls + 16;
low_fls = hwloc_fls(x & 0xfffful);
if (low_fls)
return low_fls;
return 0;
#else
return hwloc_fls(x);
#endif
}
/* Then make it 64 bit if longs are. */
static __hwloc_inline int __hwloc_attribute_const
hwloc_flsl(unsigned long x)
{
#if HWLOC_BITS_PER_LONG == 64
int low_fls, hi_fls;
hi_fls = hwloc_fls32(x >> 32);
if (hi_fls)
return hi_fls + 32;
low_fls = hwloc_fls32(x & 0xfffffffful);
if (low_fls)
return low_fls;
return 0;
#else
return hwloc_fls32(x);
#endif
}
#endif
static __hwloc_inline int __hwloc_attribute_const
hwloc_weight_long(unsigned long w)
{
#if HWLOC_BITS_PER_LONG == 32
#if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__) >= 4)
return __builtin_popcount(w);
#else
unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
#endif
#else /* HWLOC_BITS_PER_LONG == 32 */
#if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__) >= 4)
return __builtin_popcountll(w);
#else
unsigned long res;
res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
#endif
#endif /* HWLOC_BITS_PER_LONG == 64 */
}
#endif /* HWLOC_PRIVATE_MISC_H */
/*
* 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.
*
* See COPYING in top-level directory.
*/
/* Internal types and helpers. */
#ifndef HWLOC_PRIVATE_H
#define HWLOC_PRIVATE_H
#include <private/autogen/config.h>
#include <hwloc.h>
#include <hwloc/bitmap.h>
#include <private/debug.h>
#include <sys/types.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <string.h>
#ifdef HWLOC_HAVE_ATTRIBUTE_FORMAT
# if HWLOC_HAVE_ATTRIBUTE_FORMAT
# define __hwloc_attribute_format(type, str, arg) __attribute__((__format__(type, str, arg)))
# else
# define __hwloc_attribute_format(type, str, arg)
# endif
#else
# define __hwloc_attribute_format(type, str, arg)
#endif
enum hwloc_ignore_type_e {
HWLOC_IGNORE_TYPE_NEVER = 0,
HWLOC_IGNORE_TYPE_KEEP_STRUCTURE,
HWLOC_IGNORE_TYPE_ALWAYS
};
#define HWLOC_DEPTH_MAX 128
typedef enum hwloc_backend_e {
HWLOC_BACKEND_NONE,
HWLOC_BACKEND_SYNTHETIC,
#ifdef HWLOC_LINUX_SYS
HWLOC_BACKEND_SYSFS,
#endif
#ifdef HWLOC_HAVE_XML
HWLOC_BACKEND_XML,
#endif
/* This value is only here so that we can end the enum list without
a comma (thereby preventing compiler warnings) */
HWLOC_BACKEND_MAX
} hwloc_backend_t;
struct hwloc_topology {
unsigned nb_levels; /* Number of horizontal levels */
unsigned next_group_depth; /* Depth of the next Group object that we may create */
unsigned level_nbobjects[HWLOC_DEPTH_MAX]; /* Number of objects on each horizontal level */
struct hwloc_obj **levels[HWLOC_DEPTH_MAX]; /* Direct access to levels, levels[l = 0 .. nblevels-1][0..level_nbobjects[l]] */
unsigned long flags;
int type_depth[HWLOC_OBJ_TYPE_MAX];
enum hwloc_ignore_type_e ignored_types[HWLOC_OBJ_TYPE_MAX];
int is_thissystem;
int is_loaded;
hwloc_pid_t pid; /* Process ID the topology is view from, 0 for self */
int (*set_thisproc_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags);
int (*get_thisproc_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
int (*set_thisthread_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags);
int (*get_thisthread_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
int (*set_proc_cpubind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_cpuset_t set, int flags);
int (*get_proc_cpubind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, int flags);
#ifdef hwloc_thread_t
int (*set_thread_cpubind)(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_const_cpuset_t set, int flags);
int (*get_thread_cpubind)(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_cpuset_t set, int flags);
#endif
int (*get_thisproc_last_cpu_location)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
int (*get_thisthread_last_cpu_location)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
int (*get_proc_last_cpu_location)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, int flags);
int (*set_thisproc_membind)(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
int (*get_thisproc_membind)(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
int (*set_thisthread_membind)(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
int (*get_thisthread_membind)(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
int (*set_proc_membind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
int (*get_proc_membind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
int (*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);
int (*get_area_membind)(hwloc_topology_t topology, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
/* This has to return the same kind of pointer as alloc_membind, so that free_membind can be used on it */
void *(*alloc)(hwloc_topology_t topology, size_t len);
/* alloc_membind has to always succeed if !(flags & HWLOC_MEMBIND_STRICT).
* see hwloc_alloc_or_fail which is convenient for that. */
void *(*alloc_membind)(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
int (*free_membind)(hwloc_topology_t topology, void *addr, size_t len);
struct hwloc_topology_support support;
struct hwloc_os_distances_s {
int nbobjs;
unsigned *indexes; /* array of OS indexes before we can convert them into objs. always available.
*/
struct hwloc_obj **objs; /* array of objects, in the same order as above.
* either given (by a backend) together with the indexes array above.
* or build from the above indexes array when not given (by the user).
*/
float *distances; /* distance matrices, ordered according to the above indexes/objs array.
* distance from i to j is stored in slot i*nbnodes+j.
* will be copied into the main logical-index-ordered distance at the end of the discovery.
*/
} os_distances[HWLOC_OBJ_TYPE_MAX];
hwloc_backend_t backend_type;
union hwloc_backend_params_u {
#ifdef HWLOC_LINUX_SYS
struct hwloc_backend_params_sysfs_s {
/* sysfs backend parameters */
char *root_path; /* The path of the file system root, used when browsing, e.g., Linux' sysfs and procfs. */
int root_fd; /* The file descriptor for the file system root, used when browsing, e.g., Linux' sysfs and procfs. */
} sysfs;
#endif /* HWLOC_LINUX_SYS */
#if defined(HWLOC_OSF_SYS) || defined(HWLOC_COMPILE_PORTS)
struct hwloc_backend_params_osf {
int nbnodes;
} osf;
#endif /* HWLOC_OSF_SYS */
#ifdef HWLOC_HAVE_XML
struct hwloc_backend_params_xml_s {
/* xml backend parameters */
void *doc;
} xml;
#endif /* HWLOC_HAVE_XML */
struct hwloc_backend_params_synthetic_s {
/* synthetic backend parameters */
#define HWLOC_SYNTHETIC_MAX_DEPTH 128
unsigned arity[HWLOC_SYNTHETIC_MAX_DEPTH];
hwloc_obj_type_t type[HWLOC_SYNTHETIC_MAX_DEPTH];
unsigned id[HWLOC_SYNTHETIC_MAX_DEPTH];
unsigned depth[HWLOC_SYNTHETIC_MAX_DEPTH]; /* For cache/misc */
} synthetic;
} backend_params;
};
extern void hwloc_setup_pu_level(struct hwloc_topology *topology, unsigned nb_pus);
extern int hwloc_get_sysctlbyname(const char *name, int64_t *n);
extern int hwloc_get_sysctl(int name[], unsigned namelen, int *n);
extern unsigned hwloc_fallback_nbprocessors(struct hwloc_topology *topology);
#if defined(HWLOC_LINUX_SYS)
extern void hwloc_look_linux(struct hwloc_topology *topology);
extern void hwloc_set_linux_hooks(struct hwloc_topology *topology);
extern int hwloc_backend_sysfs_init(struct hwloc_topology *topology, const char *fsroot_path);
extern void hwloc_backend_sysfs_exit(struct hwloc_topology *topology);
#endif /* HWLOC_LINUX_SYS */
#ifdef HWLOC_HAVE_XML
extern int hwloc_backend_xml_init(struct hwloc_topology *topology, const char *xmlpath, const char *xmlbuffer, int buflen);
extern void hwloc_xml_check_distances(struct hwloc_topology *topology);
extern void hwloc_look_xml(struct hwloc_topology *topology);
extern void hwloc_backend_xml_exit(struct hwloc_topology *topology);
#endif /* HWLOC_HAVE_XML */
#ifdef HWLOC_SOLARIS_SYS
extern void hwloc_look_solaris(struct hwloc_topology *topology);
extern void hwloc_set_solaris_hooks(struct hwloc_topology *topology);
#endif /* HWLOC_SOLARIS_SYS */
#ifdef HWLOC_AIX_SYS
extern void hwloc_look_aix(struct hwloc_topology *topology);
extern void hwloc_set_aix_hooks(struct hwloc_topology *topology);
#endif /* HWLOC_AIX_SYS */
#ifdef HWLOC_OSF_SYS
extern void hwloc_look_osf(struct hwloc_topology *topology);
extern void hwloc_set_osf_hooks(struct hwloc_topology *topology);
#endif /* HWLOC_OSF_SYS */
#ifdef HWLOC_WIN_SYS
extern void hwloc_look_windows(struct hwloc_topology *topology);
extern void hwloc_set_windows_hooks(struct hwloc_topology *topology);
#endif /* HWLOC_WIN_SYS */
#ifdef HWLOC_DARWIN_SYS
extern void hwloc_look_darwin(struct hwloc_topology *topology);
extern void hwloc_set_darwin_hooks(struct hwloc_topology *topology);
#endif /* HWLOC_DARWIN_SYS */
#ifdef HWLOC_FREEBSD_SYS
extern void hwloc_look_freebsd(struct hwloc_topology *topology);
extern void hwloc_set_freebsd_hooks(struct hwloc_topology *topology);
#endif /* HWLOC_FREEBSD_SYS */
#ifdef HWLOC_HPUX_SYS
extern void hwloc_look_hpux(struct hwloc_topology *topology);
extern void hwloc_set_hpux_hooks(struct hwloc_topology *topology);
#endif /* HWLOC_HPUX_SYS */
extern void hwloc_look_x86(struct hwloc_topology *topology, unsigned nbprocs);
extern int hwloc_backend_synthetic_init(struct hwloc_topology *topology, const char *description);
extern void hwloc_backend_synthetic_exit(struct hwloc_topology *topology);
extern void hwloc_look_synthetic (struct hwloc_topology *topology);
/*
* Add an object to the topology.
* It is sorted along the tree of other objects according to the inclusion of
* cpusets, to eventually be added as a child of the smallest object including
* this object.
*
* If the cpuset is empty, the type of the object (and maybe some attributes)
* must be enough to find where to insert the object. This is especially true
* for NUMA nodes with memory and no CPUs.
*
* The given object should not have children.
*
* This shall only be called before levels are built.
*
* In case of error, hwloc_report_os_error() is called.
*/
extern void hwloc_insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj);
/*
* Add an object to the topology and specify which error callback to use
*/
typedef void (*hwloc_report_error_t)(const char * msg, int line);
extern void hwloc_report_os_error(const char * msg, int line);
extern int hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj, hwloc_report_error_t report_error);
/*
* Insert an object somewhere in the topology.
*
* It is added as the last child of the given parent.
* The cpuset is completely ignored, so strange objects such as I/O devices should
* preferably be inserted with this.
*
* The given object may have children.
*
* Remember to call topology_connect() afterwards to fix handy pointers.
*/
extern void hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj);
/* Insert name/value in the object infos array. name and value are copied by the callee. */
extern void hwloc_add_object_info(hwloc_obj_t obj, const char *name, const char *value);
/* Insert uname-specific names/values in the object infos array */
extern void hwloc_add_uname_info(struct hwloc_topology *topology);
/** \brief Return a locally-allocated stringified bitmap for printf-like calls. */
static __hwloc_inline char *
hwloc_bitmap_printf_value(hwloc_const_bitmap_t bitmap)
{
char *buf;
hwloc_bitmap_asprintf(&buf, bitmap);
return buf;
}
static __hwloc_inline struct hwloc_obj *
hwloc_alloc_setup_object(hwloc_obj_type_t type, signed idx)
{
struct hwloc_obj *obj = malloc(sizeof(*obj));
memset(obj, 0, sizeof(*obj));
obj->type = type;
obj->os_index = idx;
obj->os_level = -1;
obj->attr = malloc(sizeof(*obj->attr));
memset(obj->attr, 0, sizeof(*obj->attr));
/* do not allocate the cpuset here, let the caller do it */
return obj;
}
extern void hwloc_free_unlinked_object(hwloc_obj_t obj);
#define hwloc_object_cpuset_from_array(l, _value, _array, _max) do { \
struct hwloc_obj *__l = (l); \
unsigned int *__a = (_array); \
int k; \
__l->cpuset = hwloc_bitmap_alloc(); \
for(k=0; k<_max; k++) \
if (__a[k] == _value) \
hwloc_bitmap_set(__l->cpuset, k); \
} while (0)
/* Configures an array of NUM objects of type TYPE with physical IDs OSPHYSIDS
* and for which processors have ID PROC_PHYSIDS, and add them to the topology.
* */
static __hwloc_inline void
hwloc_setup_level(int procid_max, unsigned num, unsigned *osphysids, unsigned *proc_physids, struct hwloc_topology *topology, hwloc_obj_type_t type)
{
struct hwloc_obj *obj;
unsigned j;
hwloc_debug("%d %s\n", num, hwloc_obj_type_string(type));
for (j = 0; j < num; j++)
{
obj = hwloc_alloc_setup_object(type, osphysids[j]);
hwloc_object_cpuset_from_array(obj, j, proc_physids, procid_max);
hwloc_debug_2args_bitmap("%s %d has cpuset %s\n",
hwloc_obj_type_string(type),
j, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj);
}
hwloc_debug("%s", "\n");
}
/* This can be used for the alloc field to get allocated data that can be freed by free() */
void *hwloc_alloc_heap(hwloc_topology_t topology, size_t len);
/* This can be used for the alloc field to get allocated data that can be freed by munmap() */
void *hwloc_alloc_mmap(hwloc_topology_t topology, size_t len);
/* This can be used for the free_membind field to free data using free() */
int hwloc_free_heap(hwloc_topology_t topology, void *addr, size_t len);
/* This can be used for the free_membind field to free data using munmap() */
int hwloc_free_mmap(hwloc_topology_t topology, void *addr, size_t len);
/* Allocates unbound memory or fail, depending on whether STRICT is requested
* or not */
static __hwloc_inline void *
hwloc_alloc_or_fail(hwloc_topology_t topology, size_t len, int flags)
{
if (flags & HWLOC_MEMBIND_STRICT)
return NULL;
return hwloc_alloc(topology, len);
}
extern void hwloc_topology_distances_init(struct hwloc_topology *topology);
extern void hwloc_topology_distances_clear(struct hwloc_topology *topology);
extern void hwloc_topology_distances_destroy(struct hwloc_topology *topology);
extern void hwloc_topology__set_distance_matrix(struct hwloc_topology *topology, hwloc_obj_type_t type, unsigned nbobjs, unsigned *indexes, hwloc_obj_t *objs, float *distances);
extern void hwloc_store_distances_from_env(struct hwloc_topology *topology);
extern void hwloc_convert_distances_indexes_into_objects(struct hwloc_topology *topology);
extern void hwloc_finalize_logical_distances(struct hwloc_topology *topology);
extern void hwloc_restrict_distances(struct hwloc_topology *topology, unsigned long flags);
extern void hwloc_free_logical_distances(struct hwloc_distances_s *dist);
extern void hwloc_group_by_distances(struct hwloc_topology *topology);
#endif /* HWLOC_PRIVATE_H */
# Copyright © 2009-2010 INRIA. All rights reserved.
# Copyright © 2009-2010 Université Bordeaux 1
# Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
# See COPYING in top-level directory.
AM_CFLAGS = $(HWLOC_CFLAGS)
AM_CPPFLAGS = $(HWLOC_CPPFLAGS)
AM_LDFLAGS = $(HWLOC_LDFLAGS)
EXTRA_DIST = dolib.c
# If we're in standalone mode, build the installable library.
# Otherwise, build the embedded library.
if HWLOC_BUILD_STANDALONE
lib_LTLIBRARIES = libhwloc.la
else
noinst_LTLIBRARIES = libhwloc_embedded.la
endif
# Sources and ldflags
sources = \
topology.c \
traversal.c \
distances.c \
topology-synthetic.c \
bind.c \
cpuset.c \
misc.c
ldflags =
# Conditionally add to the sources and ldflags
if HWLOC_HAVE_XML
sources += topology-xml.c
endif HWLOC_HAVE_XML
if HWLOC_HAVE_SOLARIS
sources += topology-solaris.c
endif HWLOC_HAVE_SOLARIS
if HWLOC_HAVE_LINUX
sources += topology-linux.c
endif HWLOC_HAVE_LINUX
if HWLOC_HAVE_AIX
sources += topology-aix.c
ldflags += -lpthread
endif HWLOC_HAVE_AIX
if HWLOC_HAVE_OSF
sources += topology-osf.c
ldflags += -lnuma -lpthread
endif HWLOC_HAVE_OSF
if HWLOC_HAVE_HPUX
sources += topology-hpux.c
ldflags += -lpthread
endif HWLOC_HAVE_HPUX
if HWLOC_HAVE_WINDOWS
sources += topology-windows.c
endif HWLOC_HAVE_WINDOWS
if HWLOC_HAVE_DARWIN
sources += topology-darwin.c
endif HWLOC_HAVE_DARWIN
if HWLOC_HAVE_FREEBSD
sources += topology-freebsd.c
endif HWLOC_HAVE_FREEBSD
if HWLOC_HAVE_GCC
ldflags += -no-undefined
endif HWLOC_HAVE_GCC
if HWLOC_HAVE_WINDOWS
LC_MESSAGES=C
export LC_MESSAGES
ldflags += -Xlinker --output-def -Xlinker .libs/libhwloc.def
if HWLOC_HAVE_MS_LIB
.libs/libhwloc.lib: libhwloc.la dolib
./dolib "$(HWLOC_MS_LIB)" X86 .libs/libhwloc.def libhwloc-$(HWLOC_SOVERSION) .libs/libhwloc.lib
all-local: .libs/libhwloc.lib
endif HWLOC_HAVE_MS_LIB
install-exec-hook:
$(INSTALL) .libs/libhwloc.def $(DESTDIR)$(libdir)
if HWLOC_HAVE_MS_LIB
$(INSTALL) .libs/libhwloc.lib $(DESTDIR)$(libdir)
$(INSTALL) .libs/libhwloc.exp $(DESTDIR)$(libdir)
endif HWLOC_HAVE_MS_LIB
endif HWLOC_HAVE_WINDOWS
if HWLOC_HAVE_CPUID
sources += topology-x86.c
endif HWLOC_HAVE_CPUID
# Installable library
libhwloc_la_SOURCES = $(sources)
libhwloc_la_LDFLAGS = $(ldflags) -version-number $(libhwloc_so_version) $(HWLOC_XML_LIBS) $(HWLOC_LINUX_LIBNUMA_LIBS)
# Embedded library (note the lack of a .so version number -- that
# intentionally only appears in the installable library)
libhwloc_embedded_la_SOURCES = $(sources)
libhwloc_embedded_la_LDFLAGS = $(ldflags) $(HWLOC_XML_LIBS) $(HWLOC_LINUX_LIBNUMA_LIBS)
# XML data (only install if we're building in standalone mode)
if HWLOC_BUILD_STANDALONE
xml_DATA = $(srcdir)/hwloc.dtd
xmldir = $(pkgdatadir)
EXTRA_DIST += hwloc.dtd
endif
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
# Copyright © 2009-2010 INRIA. All rights reserved.
# Copyright © 2009-2010 Université Bordeaux 1
# Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
# See COPYING in top-level directory.
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
# Conditionally add to the sources and ldflags
@HWLOC_HAVE_XML_TRUE@am__append_1 = topology-xml.c
@HWLOC_HAVE_SOLARIS_TRUE@am__append_2 = topology-solaris.c
@HWLOC_HAVE_LINUX_TRUE@am__append_3 = topology-linux.c
@HWLOC_HAVE_AIX_TRUE@am__append_4 = topology-aix.c
@HWLOC_HAVE_AIX_TRUE@am__append_5 = -lpthread
@HWLOC_HAVE_OSF_TRUE@am__append_6 = topology-osf.c
@HWLOC_HAVE_OSF_TRUE@am__append_7 = -lnuma -lpthread
@HWLOC_HAVE_HPUX_TRUE@am__append_8 = topology-hpux.c
@HWLOC_HAVE_HPUX_TRUE@am__append_9 = -lpthread
@HWLOC_HAVE_WINDOWS_TRUE@am__append_10 = topology-windows.c
@HWLOC_HAVE_DARWIN_TRUE@am__append_11 = topology-darwin.c
@HWLOC_HAVE_FREEBSD_TRUE@am__append_12 = topology-freebsd.c
@HWLOC_HAVE_GCC_TRUE@am__append_13 = -no-undefined
@HWLOC_HAVE_WINDOWS_TRUE@am__append_14 = -Xlinker --output-def -Xlinker .libs/libhwloc.def
@HWLOC_HAVE_CPUID_TRUE@am__append_15 = topology-x86.c
@HWLOC_BUILD_STANDALONE_TRUE@am__append_16 = hwloc.dtd
subdir = hwloc-1.2.1/src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = \
$(top_srcdir)/hwloc-1.2.1/config/hwloc_check_attributes.m4 \
$(top_srcdir)/hwloc-1.2.1/config/hwloc_check_visibility.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/hwloc-1.2.1/config/hwloc.m4 \
$(top_srcdir)/hwloc-1.2.1/config/hwloc_pkg.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h \
$(top_builddir)/hwloc-1.2.1/include/private/autogen/config.h \
$(top_builddir)/hwloc-1.2.1/include/hwloc/autogen/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(xmldir)"
LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
libhwloc_la_LIBADD =
am__libhwloc_la_SOURCES_DIST = topology.c traversal.c distances.c \
topology-synthetic.c bind.c cpuset.c misc.c topology-xml.c \
topology-solaris.c topology-linux.c topology-aix.c \
topology-osf.c topology-hpux.c topology-windows.c \
topology-darwin.c topology-freebsd.c topology-x86.c
@HWLOC_HAVE_XML_TRUE@am__objects_1 = topology-xml.lo
@HWLOC_HAVE_SOLARIS_TRUE@am__objects_2 = topology-solaris.lo
@HWLOC_HAVE_LINUX_TRUE@am__objects_3 = topology-linux.lo
@HWLOC_HAVE_AIX_TRUE@am__objects_4 = topology-aix.lo
@HWLOC_HAVE_OSF_TRUE@am__objects_5 = topology-osf.lo
@HWLOC_HAVE_HPUX_TRUE@am__objects_6 = topology-hpux.lo
@HWLOC_HAVE_WINDOWS_TRUE@am__objects_7 = topology-windows.lo
@HWLOC_HAVE_DARWIN_TRUE@am__objects_8 = topology-darwin.lo
@HWLOC_HAVE_FREEBSD_TRUE@am__objects_9 = topology-freebsd.lo
@HWLOC_HAVE_CPUID_TRUE@am__objects_10 = topology-x86.lo
am__objects_11 = topology.lo traversal.lo distances.lo \
topology-synthetic.lo bind.lo cpuset.lo misc.lo \
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
$(am__objects_4) $(am__objects_5) $(am__objects_6) \
$(am__objects_7) $(am__objects_8) $(am__objects_9) \
$(am__objects_10)
am_libhwloc_la_OBJECTS = $(am__objects_11)
libhwloc_la_OBJECTS = $(am_libhwloc_la_OBJECTS)
libhwloc_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libhwloc_la_LDFLAGS) $(LDFLAGS) -o $@
@HWLOC_BUILD_STANDALONE_TRUE@am_libhwloc_la_rpath = -rpath $(libdir)
libhwloc_embedded_la_LIBADD =
am__libhwloc_embedded_la_SOURCES_DIST = topology.c traversal.c \
distances.c topology-synthetic.c bind.c cpuset.c misc.c \
topology-xml.c topology-solaris.c topology-linux.c \
topology-aix.c topology-osf.c topology-hpux.c \
topology-windows.c topology-darwin.c topology-freebsd.c \
topology-x86.c
am_libhwloc_embedded_la_OBJECTS = $(am__objects_11)
libhwloc_embedded_la_OBJECTS = $(am_libhwloc_embedded_la_OBJECTS)
libhwloc_embedded_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libhwloc_embedded_la_LDFLAGS) $(LDFLAGS) -o $@
@HWLOC_BUILD_STANDALONE_FALSE@am_libhwloc_embedded_la_rpath =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/hwloc-1.2.1/include/private/autogen -I$(top_builddir)/hwloc-1.2.1/include/hwloc/autogen
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(libhwloc_la_SOURCES) $(libhwloc_embedded_la_SOURCES)
DIST_SOURCES = $(am__libhwloc_la_SOURCES_DIST) \
$(am__libhwloc_embedded_la_SOURCES_DIST)
DATA = $(xml_DATA)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BASH = @BASH@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GREP = @GREP@
HWLOC_CFLAGS = @HWLOC_CFLAGS@
HWLOC_CPPFLAGS = @HWLOC_CPPFLAGS@
HWLOC_EMBEDDED_CFLAGS = @HWLOC_EMBEDDED_CFLAGS@
HWLOC_EMBEDDED_CPPFLAGS = @HWLOC_EMBEDDED_CPPFLAGS@
HWLOC_EMBEDDED_LDADD = @HWLOC_EMBEDDED_LDADD@
HWLOC_EMBEDDED_LIBS = @HWLOC_EMBEDDED_LIBS@
HWLOC_HAVE_XML = @HWLOC_HAVE_XML@
HWLOC_KERRIGHED_CFLAGS = @HWLOC_KERRIGHED_CFLAGS@
HWLOC_KERRIGHED_LIBS = @HWLOC_KERRIGHED_LIBS@
HWLOC_LDFLAGS = @HWLOC_LDFLAGS@
HWLOC_LIBS = @HWLOC_LIBS@
HWLOC_LINUX_LIBNUMA_LIBS = @HWLOC_LINUX_LIBNUMA_LIBS@
HWLOC_MS_LIB = @HWLOC_MS_LIB@
HWLOC_PKG_CONFIG = @HWLOC_PKG_CONFIG@
HWLOC_REQUIRES = @HWLOC_REQUIRES@
HWLOC_XML_CFLAGS = @HWLOC_XML_CFLAGS@
HWLOC_XML_LIBS = @HWLOC_XML_LIBS@
HWLOC_top_builddir = @HWLOC_top_builddir@
HWLOC_top_srcdir = @HWLOC_top_srcdir@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CFLAGS = $(HWLOC_CFLAGS)
AM_CPPFLAGS = $(HWLOC_CPPFLAGS)
AM_LDFLAGS = $(HWLOC_LDFLAGS)
EXTRA_DIST = dolib.c $(am__append_16)
# If we're in standalone mode, build the installable library.
# Otherwise, build the embedded library.
@HWLOC_BUILD_STANDALONE_TRUE@lib_LTLIBRARIES = libhwloc.la
@HWLOC_BUILD_STANDALONE_FALSE@noinst_LTLIBRARIES = libhwloc_embedded.la
# Sources and ldflags
sources = topology.c traversal.c distances.c topology-synthetic.c \
bind.c cpuset.c misc.c $(am__append_1) $(am__append_2) \
$(am__append_3) $(am__append_4) $(am__append_6) \
$(am__append_8) $(am__append_10) $(am__append_11) \
$(am__append_12) $(am__append_15)
ldflags = $(am__append_5) $(am__append_7) $(am__append_9) \
$(am__append_13) $(am__append_14)
@HWLOC_HAVE_WINDOWS_TRUE@LC_MESSAGES = C
# Installable library
libhwloc_la_SOURCES = $(sources)
libhwloc_la_LDFLAGS = $(ldflags) -version-number $(libhwloc_so_version) $(HWLOC_XML_LIBS) $(HWLOC_LINUX_LIBNUMA_LIBS)
# Embedded library (note the lack of a .so version number -- that
# intentionally only appears in the installable library)
libhwloc_embedded_la_SOURCES = $(sources)
libhwloc_embedded_la_LDFLAGS = $(ldflags) $(HWLOC_XML_LIBS) $(HWLOC_LINUX_LIBNUMA_LIBS)
# XML data (only install if we're building in standalone mode)
@HWLOC_BUILD_STANDALONE_TRUE@xml_DATA = $(srcdir)/hwloc.dtd
@HWLOC_BUILD_STANDALONE_TRUE@xmldir = $(pkgdatadir)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu hwloc-1.2.1/src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu hwloc-1.2.1/src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
test "$$dir" != "$$p" || dir=.; \
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
test "$$dir" != "$$p" || dir=.; \
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
libhwloc.la: $(libhwloc_la_OBJECTS) $(libhwloc_la_DEPENDENCIES)
$(libhwloc_la_LINK) $(am_libhwloc_la_rpath) $(libhwloc_la_OBJECTS) $(libhwloc_la_LIBADD) $(LIBS)
libhwloc_embedded.la: $(libhwloc_embedded_la_OBJECTS) $(libhwloc_embedded_la_DEPENDENCIES)
$(libhwloc_embedded_la_LINK) $(am_libhwloc_embedded_la_rpath) $(libhwloc_embedded_la_OBJECTS) $(libhwloc_embedded_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bind.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpuset.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/distances.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-aix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-darwin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-freebsd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-hpux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-osf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-solaris.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-synthetic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-windows.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-x86.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology-xml.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/topology.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traversal.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-xmlDATA: $(xml_DATA)
@$(NORMAL_INSTALL)
test -z "$(xmldir)" || $(MKDIR_P) "$(DESTDIR)$(xmldir)"
@list='$(xml_DATA)'; test -n "$(xmldir)" || list=; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(xmldir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(xmldir)" || exit $$?; \
done
uninstall-xmlDATA:
@$(NORMAL_UNINSTALL)
@list='$(xml_DATA)'; test -n "$(xmldir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(xmldir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(xmldir)" && rm -f $$files
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
@HWLOC_HAVE_MS_LIB_FALSE@all-local:
@HWLOC_HAVE_WINDOWS_FALSE@all-local:
all-am: Makefile $(LTLIBRARIES) $(DATA) all-local
installdirs:
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(xmldir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
@HWLOC_HAVE_WINDOWS_FALSE@install-exec-hook:
clean: clean-am
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
clean-noinstLTLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-xmlDATA
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-libLTLIBRARIES
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) install-exec-hook
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-libLTLIBRARIES uninstall-xmlDATA
.MAKE: install-am install-exec-am install-strip
.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \
clean-generic clean-libLTLIBRARIES clean-libtool \
clean-noinstLTLIBRARIES ctags distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-exec-hook install-html \
install-html-am install-info install-info-am \
install-libLTLIBRARIES install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip install-xmlDATA \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags uninstall uninstall-am uninstall-libLTLIBRARIES \
uninstall-xmlDATA
@HWLOC_HAVE_WINDOWS_TRUE@export LC_MESSAGES
@HWLOC_HAVE_MS_LIB_TRUE@@HWLOC_HAVE_WINDOWS_TRUE@.libs/libhwloc.lib: libhwloc.la dolib
@HWLOC_HAVE_MS_LIB_TRUE@@HWLOC_HAVE_WINDOWS_TRUE@ ./dolib "$(HWLOC_MS_LIB)" X86 .libs/libhwloc.def libhwloc-$(HWLOC_SOVERSION) .libs/libhwloc.lib
@HWLOC_HAVE_MS_LIB_TRUE@@HWLOC_HAVE_WINDOWS_TRUE@all-local: .libs/libhwloc.lib
@HWLOC_HAVE_WINDOWS_TRUE@install-exec-hook:
@HWLOC_HAVE_WINDOWS_TRUE@ $(INSTALL) .libs/libhwloc.def $(DESTDIR)$(libdir)
@HWLOC_HAVE_MS_LIB_TRUE@@HWLOC_HAVE_WINDOWS_TRUE@ $(INSTALL) .libs/libhwloc.lib $(DESTDIR)$(libdir)
@HWLOC_HAVE_MS_LIB_TRUE@@HWLOC_HAVE_WINDOWS_TRUE@ $(INSTALL) .libs/libhwloc.exp $(DESTDIR)$(libdir)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
/*
* 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 <private/autogen/config.h>
#include <hwloc.h>
#include <private/private.h>
#include <hwloc/helper.h>
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
/* 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);
}
/*
* 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.
* See COPYING in top-level directory.
*/
/* cpuset.h converts from the old cpuset API to the new bitmap API, we don't want it here */
#ifndef HWLOC_CPUSET_H
/* make sure cpuset.h will not be automatically included here */
#define HWLOC_CPUSET_H 1
#else
#error Do not include cpuset.h in cpuset.c
#endif
#include <private/autogen/config.h>
#include <private/misc.h>
#include <private/private.h>
#include <hwloc/bitmap.h>
#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>
/* TODO
* - have a way to change the initial allocation size
* - preallocate inside the bitmap structure (so that the whole structure is a cacheline for instance)
* and allocate a dedicated array only later when reallocating larger
*/
/* magic number */
#define HWLOC_BITMAP_MAGIC 0x20091007
/* actual opaque type internals */
struct hwloc_bitmap_s {
unsigned ulongs_count; /* how many ulong bitmasks are valid, >= 1 */
unsigned ulongs_allocated; /* how many ulong bitmasks are allocated, >= ulongs_count */
unsigned long *ulongs;
int infinite; /* set to 1 if all bits beyond ulongs are set */
#ifdef HWLOC_DEBUG
int magic;
#endif
};
/* overzealous check in debug-mode, not as powerful as valgrind but still useful */
#ifdef HWLOC_DEBUG
#define HWLOC__BITMAP_CHECK(set) do { \
assert((set)->magic == HWLOC_BITMAP_MAGIC); \
assert((set)->ulongs_count >= 1); \
assert((set)->ulongs_allocated >= (set)->ulongs_count); \
} while (0)
#else
#define HWLOC__BITMAP_CHECK(set)
#endif
/* extract a subset from a set using an index or a cpu */
#define HWLOC_SUBBITMAP_INDEX(cpu) ((cpu)/(HWLOC_BITS_PER_LONG))
#define HWLOC_SUBBITMAP_CPU_ULBIT(cpu) ((cpu)%(HWLOC_BITS_PER_LONG))
/* Read from a bitmap ulong without knowing whether x is valid.
* Writers should make sure that x is valid and modify set->ulongs[x] directly.
*/
#define HWLOC_SUBBITMAP_READULONG(set,x) ((x) < (set)->ulongs_count ? (set)->ulongs[x] : (set)->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO)
/* predefined subset values */
#define HWLOC_SUBBITMAP_ZERO 0UL
#define HWLOC_SUBBITMAP_FULL (~0UL)
#define HWLOC_SUBBITMAP_ULBIT(bit) (1UL<<(bit))
#define HWLOC_SUBBITMAP_CPU(cpu) HWLOC_SUBBITMAP_ULBIT(HWLOC_SUBBITMAP_CPU_ULBIT(cpu))
#define HWLOC_SUBBITMAP_ULBIT_TO(bit) (HWLOC_SUBBITMAP_FULL>>(HWLOC_BITS_PER_LONG-1-(bit)))
#define HWLOC_SUBBITMAP_ULBIT_FROM(bit) (HWLOC_SUBBITMAP_FULL<<(bit))
#define HWLOC_SUBBITMAP_ULBIT_FROMTO(begin,end) (HWLOC_SUBBITMAP_ULBIT_TO(end) & HWLOC_SUBBITMAP_ULBIT_FROM(begin))
struct hwloc_bitmap_s * hwloc_bitmap_alloc(void)
{
struct hwloc_bitmap_s * set;
set = malloc(sizeof(struct hwloc_bitmap_s));
if (!set)
return NULL;
set->ulongs_count = 1;
set->ulongs_allocated = 64/sizeof(unsigned long);
set->ulongs = malloc(64);
if (!set->ulongs) {
free(set);
return NULL;
}
set->ulongs[0] = HWLOC_SUBBITMAP_ZERO;
set->infinite = 0;
#ifdef HWLOC_DEBUG
set->magic = HWLOC_BITMAP_MAGIC;
#endif
return set;
}
struct hwloc_bitmap_s * hwloc_bitmap_alloc_full(void)
{
struct hwloc_bitmap_s * set = hwloc_bitmap_alloc();
if (set) {
set->infinite = 1;
set->ulongs[0] = HWLOC_SUBBITMAP_FULL;
}
return set;
}
void hwloc_bitmap_free(struct hwloc_bitmap_s * set)
{
if (!set)
return;
HWLOC__BITMAP_CHECK(set);
#ifdef HWLOC_DEBUG
set->magic = 0;
#endif
free(set->ulongs);
free(set);
}
/* enlarge until it contains at least needed_count ulongs.
*/
static void
hwloc_bitmap_enlarge_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count)
{
unsigned tmp = 1 << hwloc_flsl((unsigned long) needed_count - 1);
if (tmp > set->ulongs_allocated) {
set->ulongs = realloc(set->ulongs, tmp * sizeof(unsigned long));
assert(set->ulongs);
set->ulongs_allocated = tmp;
}
}
/* enlarge until it contains at least needed_count ulongs,
* and update new ulongs according to the infinite field.
*/
static void
hwloc_bitmap_realloc_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count)
{
unsigned i;
HWLOC__BITMAP_CHECK(set);
if (needed_count <= set->ulongs_count)
return;
/* realloc larger if needed */
hwloc_bitmap_enlarge_by_ulongs(set, needed_count);
/* fill the newly allocated subset depending on the infinite flag */
for(i=set->ulongs_count; i<needed_count; i++)
set->ulongs[i] = set->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO;
set->ulongs_count = needed_count;
}
/* realloc until it contains at least cpu+1 bits */
#define hwloc_bitmap_realloc_by_cpu_index(set, cpu) hwloc_bitmap_realloc_by_ulongs(set, ((cpu)/HWLOC_BITS_PER_LONG)+1)
/* reset a bitmap to exactely the needed size.
* the caller must reinitialize all ulongs and the infinite flag later.
*/
static void
hwloc_bitmap_reset_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count)
{
hwloc_bitmap_enlarge_by_ulongs(set, needed_count);
set->ulongs_count = needed_count;
}
/* reset until it contains exactly cpu+1 bits (roundup to a ulong).
* the caller must reinitialize all ulongs and the infinite flag later.
*/
#define hwloc_bitmap_reset_by_cpu_index(set, cpu) hwloc_bitmap_reset_by_ulongs(set, ((cpu)/HWLOC_BITS_PER_LONG)+1)
struct hwloc_bitmap_s * hwloc_bitmap_dup(const struct hwloc_bitmap_s * old)
{
struct hwloc_bitmap_s * new;
if (!old)
return NULL;
HWLOC__BITMAP_CHECK(old);
new = malloc(sizeof(struct hwloc_bitmap_s));
if (!new)
return NULL;
new->ulongs = malloc(old->ulongs_allocated * sizeof(unsigned long));
if (!new->ulongs) {
free(new);
return NULL;
}
new->ulongs_allocated = old->ulongs_allocated;
new->ulongs_count = old->ulongs_count;
memcpy(new->ulongs, old->ulongs, new->ulongs_count * sizeof(unsigned long));
new->infinite = old->infinite;
#ifdef HWLOC_DEBUG
new->magic = HWLOC_BITMAP_MAGIC;
#endif
return new;
}
void hwloc_bitmap_copy(struct hwloc_bitmap_s * dst, const struct hwloc_bitmap_s * src)
{
HWLOC__BITMAP_CHECK(dst);
HWLOC__BITMAP_CHECK(src);
hwloc_bitmap_reset_by_ulongs(dst, src->ulongs_count);
memcpy(dst->ulongs, src->ulongs, src->ulongs_count * sizeof(unsigned long));
dst->infinite = src->infinite;
}
/* Strings always use 32bit groups */
#define HWLOC_PRIxSUBBITMAP "%08lx"
#define HWLOC_BITMAP_SUBSTRING_SIZE 32
#define HWLOC_BITMAP_SUBSTRING_LENGTH (HWLOC_BITMAP_SUBSTRING_SIZE/4)
#define HWLOC_BITMAP_STRING_PER_LONG (HWLOC_BITS_PER_LONG/HWLOC_BITMAP_SUBSTRING_SIZE)
int hwloc_bitmap_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set)
{
ssize_t size = buflen;
char *tmp = buf;
int res, ret = 0;
int needcomma = 0;
int i;
unsigned long accum = 0;
int accumed = 0;
#if HWLOC_BITS_PER_LONG == HWLOC_BITMAP_SUBSTRING_SIZE
const unsigned long accum_mask = ~0UL;
#else /* HWLOC_BITS_PER_LONG != HWLOC_BITMAP_SUBSTRING_SIZE */
const unsigned long accum_mask = ((1UL << HWLOC_BITMAP_SUBSTRING_SIZE) - 1) << (HWLOC_BITS_PER_LONG - HWLOC_BITMAP_SUBSTRING_SIZE);
#endif /* HWLOC_BITS_PER_LONG != HWLOC_BITMAP_SUBSTRING_SIZE */
HWLOC__BITMAP_CHECK(set);
/* mark the end in case we do nothing later */
if (buflen > 0)
tmp[0] = '\0';
if (set->infinite) {
res = hwloc_snprintf(tmp, size, "0xf...f");
needcomma = 1;
if (res < 0)
return -1;
ret += res;
if (res >= size)
res = size>0 ? size - 1 : 0;
tmp += res;
size -= res;
/* optimize a common case: full bitmap should appear as 0xf...f instead of 0xf...f,0xffffffff */
if (set->ulongs_count == 1 && set->ulongs[0] == HWLOC_SUBBITMAP_FULL)
return ret;
}
i=set->ulongs_count-1;
while (i>=0 || accumed) {
/* Refill accumulator */
if (!accumed) {
accum = set->ulongs[i--];
accumed = HWLOC_BITS_PER_LONG;
}
if (accum & accum_mask) {
/* print the whole subset if not empty */
res = hwloc_snprintf(tmp, size, needcomma ? ",0x" HWLOC_PRIxSUBBITMAP : "0x" HWLOC_PRIxSUBBITMAP,
(accum & accum_mask) >> (HWLOC_BITS_PER_LONG - HWLOC_BITMAP_SUBSTRING_SIZE));
needcomma = 1;
} else if (i == -1 && accumed == HWLOC_BITMAP_SUBSTRING_SIZE) {
/* print a single 0 to mark the last subset */
res = hwloc_snprintf(tmp, size, needcomma ? ",0x0" : "0x0");
} else if (needcomma) {
res = hwloc_snprintf(tmp, size, ",");
} else {
res = 0;
}
if (res < 0)
return -1;
ret += res;
#if HWLOC_BITS_PER_LONG == HWLOC_BITMAP_SUBSTRING_SIZE
accum = 0;
accumed = 0;
#else
accum <<= HWLOC_BITMAP_SUBSTRING_SIZE;
accumed -= HWLOC_BITMAP_SUBSTRING_SIZE;
#endif
if (res >= size)
res = size>0 ? size - 1 : 0;
tmp += res;
size -= res;
}
return ret;
}
int hwloc_bitmap_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set)
{
int len;
char *buf;
HWLOC__BITMAP_CHECK(set);
len = hwloc_bitmap_snprintf(NULL, 0, set);
buf = malloc(len+1);
*strp = buf;
return hwloc_bitmap_snprintf(buf, len+1, set);
}
int hwloc_bitmap_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string)
{
const char * current = string;
unsigned long accum = 0;
int count=0;
int infinite = 0;
/* count how many substrings there are */
count++;
while ((current = strchr(current+1, ',')) != NULL)
count++;
current = string;
if (!strncmp("0xf...f", current, 7)) {
current += 7;
if (*current != ',') {
/* special case for infinite/full cpuset */
hwloc_bitmap_fill(set);
return 0;
}
current++;
infinite = 1;
count--;
}
hwloc_bitmap_reset_by_ulongs(set, (count + HWLOC_BITMAP_STRING_PER_LONG - 1) / HWLOC_BITMAP_STRING_PER_LONG);
set->infinite = 0;
while (*current != '\0') {
unsigned long val;
char *next;
val = strtoul(current, &next, 16);
assert(count > 0);
count--;
accum |= (val << ((count * HWLOC_BITMAP_SUBSTRING_SIZE) % HWLOC_BITS_PER_LONG));
if (!(count % HWLOC_BITMAP_STRING_PER_LONG)) {
set->ulongs[count / HWLOC_BITMAP_STRING_PER_LONG] = accum;
accum = 0;
}
if (*next != ',') {
if (*next || count > 0)
goto failed;
else
break;
}
current = (const char*) next+1;
}
set->infinite = infinite; /* set at the end, to avoid spurious realloc with filled new ulongs */
return 0;
failed:
/* failure to parse */
hwloc_bitmap_zero(set);
return -1;
}
int hwloc_bitmap_list_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set)
{
int prev = -1;
hwloc_bitmap_t reverse;
ssize_t size = buflen;
char *tmp = buf;
int res, ret = 0;
int needcomma = 0;
HWLOC__BITMAP_CHECK(set);
reverse = hwloc_bitmap_alloc(); /* FIXME: add hwloc_bitmap_alloc_size() + hwloc_bitmap_init_allocated() to avoid malloc? */
hwloc_bitmap_not(reverse, set);
/* mark the end in case we do nothing later */
if (buflen > 0)
tmp[0] = '\0';
while (1) {
int begin, end;
begin = hwloc_bitmap_next(set, prev);
if (begin == -1)
break;
end = hwloc_bitmap_next(reverse, begin);
if (end == begin+1) {
res = hwloc_snprintf(tmp, size, needcomma ? ",%d" : "%d", begin);
} else if (end == -1) {
res = hwloc_snprintf(tmp, size, needcomma ? ",%d-" : "%d-", begin);
} else {
res = hwloc_snprintf(tmp, size, needcomma ? ",%d-%d" : "%d-%d", begin, end-1);
}
if (res < 0) {
hwloc_bitmap_free(reverse);
return -1;
}
ret += res;
if (res >= size)
res = size>0 ? size - 1 : 0;
tmp += res;
size -= res;
needcomma = 1;
if (end == -1)
break;
else
prev = end - 1;
}
hwloc_bitmap_free(reverse);
return ret;
}
int hwloc_bitmap_list_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set)
{
int len;
char *buf;
HWLOC__BITMAP_CHECK(set);
len = hwloc_bitmap_list_snprintf(NULL, 0, set);
buf = malloc(len+1);
*strp = buf;
return hwloc_bitmap_list_snprintf(buf, len+1, set);
}
int hwloc_bitmap_list_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string)
{
const char * current = string;
char *next;
long begin = -1, val;
hwloc_bitmap_zero(set);
while (*current != '\0') {
/* ignore empty ranges */
while (*current == ',')
current++;
val = strtoul(current, &next, 0);
/* make sure we got at least one digit */
if (next == current)
goto failed;
if (begin != -1) {
/* finishing a range */
hwloc_bitmap_set_range(set, begin, val);
begin = -1;
} else if (*next == '-') {
/* starting a new range */
if (*(next+1) == '\0') {
/* infinite range */
hwloc_bitmap_set_range(set, val, -1);
break;
} else {
/* normal range */
begin = val;
}
} else if (*next == ',' || *next == '\0') {
/* single digit */
hwloc_bitmap_set(set, val);
}
if (*next == '\0')
break;
current = next+1;
}
return 0;
failed:
/* failure to parse */
hwloc_bitmap_zero(set);
return -1;
}
int hwloc_bitmap_taskset_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set)
{
ssize_t size = buflen;
char *tmp = buf;
int res, ret = 0;
int started = 0;
int i;
HWLOC__BITMAP_CHECK(set);
/* mark the end in case we do nothing later */
if (buflen > 0)
tmp[0] = '\0';
if (set->infinite) {
res = hwloc_snprintf(tmp, size, "0xf...f");
started = 1;
if (res < 0)
return -1;
ret += res;
if (res >= size)
res = size>0 ? size - 1 : 0;
tmp += res;
size -= res;
/* optimize a common case: full bitmap should appear as 0xf...f instead of 0xf...fffffffff */
if (set->ulongs_count == 1 && set->ulongs[0] == HWLOC_SUBBITMAP_FULL)
return ret;
}
i=set->ulongs_count-1;
while (i>=0) {
unsigned long val = set->ulongs[i--];
if (started) {
/* print the whole subset */
#if HWLOC_BITS_PER_LONG == 64
res = hwloc_snprintf(tmp, size, "%016lx", val);
#else
res = hwloc_snprintf(tmp, size, "%08lx", val);
#endif
} else if (val || i == -1) {
res = hwloc_snprintf(tmp, size, "0x%lx", val);
started = 1;
} else {
res = 0;
}
if (res < 0)
return -1;
ret += res;
if (res >= size)
res = size>0 ? size - 1 : 0;
tmp += res;
size -= res;
}
return ret;
}
int hwloc_bitmap_taskset_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set)
{
int len;
char *buf;
HWLOC__BITMAP_CHECK(set);
len = hwloc_bitmap_taskset_snprintf(NULL, 0, set);
buf = malloc(len+1);
*strp = buf;
return hwloc_bitmap_taskset_snprintf(buf, len+1, set);
}
int hwloc_bitmap_taskset_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string)
{
const char * current = string;
int chars;
int count;
int infinite = 0;
current = string;
if (!strncmp("0xf...f", current, 7)) {
/* infinite bitmap */
infinite = 1;
current += 7;
if (*current == '\0') {
/* special case for infinite/full bitmap */
hwloc_bitmap_fill(set);
return 0;
}
} else {
/* finite bitmap */
if (!strncmp("0x", current, 2))
current += 2;
if (*current == '\0') {
/* special case for empty bitmap */
hwloc_bitmap_zero(set);
return 0;
}
}
/* we know there are other characters now */
chars = strlen(current);
count = (chars * 4 + HWLOC_BITS_PER_LONG - 1) / HWLOC_BITS_PER_LONG;
hwloc_bitmap_reset_by_ulongs(set, count);
set->infinite = 0;
while (*current != '\0') {
int tmpchars;
char ustr[17];
unsigned long val;
char *next;
tmpchars = chars % (HWLOC_BITS_PER_LONG/4);
if (!tmpchars)
tmpchars = (HWLOC_BITS_PER_LONG/4);
memcpy(ustr, current, tmpchars);
ustr[tmpchars] = '\0';
val = strtoul(ustr, &next, 16);
if (*next != '\0')
goto failed;
set->ulongs[count-1] = val;
current += tmpchars;
chars -= tmpchars;
count--;
}
set->infinite = infinite; /* set at the end, to avoid spurious realloc with filled new ulongs */
return 0;
failed:
/* failure to parse */
hwloc_bitmap_zero(set);
return -1;
}
static void hwloc_bitmap__zero(struct hwloc_bitmap_s *set)
{
unsigned i;
for(i=0; i<set->ulongs_count; i++)
set->ulongs[i] = HWLOC_SUBBITMAP_ZERO;
set->infinite = 0;
}
void hwloc_bitmap_zero(struct hwloc_bitmap_s * set)
{
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_reset_by_ulongs(set, 1);
hwloc_bitmap__zero(set);
}
static void hwloc_bitmap__fill(struct hwloc_bitmap_s * set)
{
unsigned i;
for(i=0; i<set->ulongs_count; i++)
set->ulongs[i] = HWLOC_SUBBITMAP_FULL;
set->infinite = 1;
}
void hwloc_bitmap_fill(struct hwloc_bitmap_s * set)
{
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_reset_by_ulongs(set, 1);
hwloc_bitmap__fill(set);
}
void hwloc_bitmap_from_ulong(struct hwloc_bitmap_s *set, unsigned long mask)
{
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_reset_by_ulongs(set, 1);
set->ulongs[0] = mask; /* there's always at least one ulong allocated */
set->infinite = 0;
}
void hwloc_bitmap_from_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask)
{
unsigned j;
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_reset_by_ulongs(set, i+1);
set->ulongs[i] = mask;
for(j=0; j<i; j++)
set->ulongs[j] = HWLOC_SUBBITMAP_ZERO;
set->infinite = 0;
}
unsigned long hwloc_bitmap_to_ulong(const struct hwloc_bitmap_s *set)
{
HWLOC__BITMAP_CHECK(set);
return set->ulongs[0]; /* there's always at least one ulong allocated */
}
unsigned long hwloc_bitmap_to_ith_ulong(const struct hwloc_bitmap_s *set, unsigned i)
{
HWLOC__BITMAP_CHECK(set);
return HWLOC_SUBBITMAP_READULONG(set, i);
}
void hwloc_bitmap_only(struct hwloc_bitmap_s * set, unsigned cpu)
{
unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_reset_by_cpu_index(set, cpu);
hwloc_bitmap__zero(set);
set->ulongs[index_] |= HWLOC_SUBBITMAP_CPU(cpu);
}
void hwloc_bitmap_allbut(struct hwloc_bitmap_s * set, unsigned cpu)
{
unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_reset_by_cpu_index(set, cpu);
hwloc_bitmap__fill(set);
set->ulongs[index_] &= ~HWLOC_SUBBITMAP_CPU(cpu);
}
void hwloc_bitmap_set(struct hwloc_bitmap_s * set, unsigned cpu)
{
unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
HWLOC__BITMAP_CHECK(set);
/* nothing to do if setting inside the infinite part of the bitmap */
if (set->infinite && cpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
return;
hwloc_bitmap_realloc_by_cpu_index(set, cpu);
set->ulongs[index_] |= HWLOC_SUBBITMAP_CPU(cpu);
}
void hwloc_bitmap_set_range(struct hwloc_bitmap_s * set, unsigned begincpu, int _endcpu)
{
unsigned i;
unsigned beginset,endset;
unsigned endcpu = (unsigned) _endcpu;
HWLOC__BITMAP_CHECK(set);
if (_endcpu == -1) {
set->infinite = 1;
/* keep endcpu == -1 since this unsigned is actually larger than anything else */
}
if (set->infinite) {
/* truncate the range according to the infinite part of the bitmap */
if (endcpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
endcpu = set->ulongs_count * HWLOC_BITS_PER_LONG - 1;
if (begincpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
return;
}
if (endcpu < begincpu)
return;
hwloc_bitmap_realloc_by_cpu_index(set, endcpu);
beginset = HWLOC_SUBBITMAP_INDEX(begincpu);
endset = HWLOC_SUBBITMAP_INDEX(endcpu);
for(i=beginset+1; i<endset; i++)
set->ulongs[i] = HWLOC_SUBBITMAP_FULL;
if (beginset == endset) {
set->ulongs[beginset] |= HWLOC_SUBBITMAP_ULBIT_FROMTO(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu), HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
} else {
set->ulongs[beginset] |= HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu));
set->ulongs[endset] |= HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
}
}
void hwloc_bitmap_set_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask)
{
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_realloc_by_ulongs(set, i+1);
set->ulongs[i] = mask;
}
void hwloc_bitmap_clr(struct hwloc_bitmap_s * set, unsigned cpu)
{
unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
HWLOC__BITMAP_CHECK(set);
/* nothing to do if clearing inside the infinitely-unset part of the bitmap */
if (!set->infinite && cpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
return;
hwloc_bitmap_realloc_by_cpu_index(set, cpu);
set->ulongs[index_] &= ~HWLOC_SUBBITMAP_CPU(cpu);
}
void hwloc_bitmap_clr_range(struct hwloc_bitmap_s * set, unsigned begincpu, int _endcpu)
{
unsigned i;
unsigned beginset,endset;
unsigned endcpu = (unsigned) _endcpu;
HWLOC__BITMAP_CHECK(set);
if (_endcpu == -1) {
set->infinite = 0;
/* keep endcpu == -1 since this unsigned is actually larger than anything else */
}
if (!set->infinite) {
/* truncate the range according to the infinitely-unset part of the bitmap */
if (endcpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
endcpu = set->ulongs_count * HWLOC_BITS_PER_LONG - 1;
if (begincpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
return;
}
if (endcpu < begincpu)
return;
hwloc_bitmap_realloc_by_cpu_index(set, endcpu);
beginset = HWLOC_SUBBITMAP_INDEX(begincpu);
endset = HWLOC_SUBBITMAP_INDEX(endcpu);
for(i=beginset+1; i<endset; i++)
set->ulongs[i] = HWLOC_SUBBITMAP_ZERO;
if (beginset == endset) {
set->ulongs[beginset] &= ~HWLOC_SUBBITMAP_ULBIT_FROMTO(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu), HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
} else {
set->ulongs[beginset] &= ~HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu));
set->ulongs[endset] &= ~HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
}
}
int hwloc_bitmap_isset(const struct hwloc_bitmap_s * set, unsigned cpu)
{
unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
HWLOC__BITMAP_CHECK(set);
return (HWLOC_SUBBITMAP_READULONG(set, index_) & HWLOC_SUBBITMAP_CPU(cpu)) != 0;
}
int hwloc_bitmap_iszero(const struct hwloc_bitmap_s *set)
{
unsigned i;
HWLOC__BITMAP_CHECK(set);
if (set->infinite)
return 0;
for(i=0; i<set->ulongs_count; i++)
if (set->ulongs[i] != HWLOC_SUBBITMAP_ZERO)
return 0;
return 1;
}
int hwloc_bitmap_isfull(const struct hwloc_bitmap_s *set)
{
unsigned i;
HWLOC__BITMAP_CHECK(set);
if (!set->infinite)
return 0;
for(i=0; i<set->ulongs_count; i++)
if (set->ulongs[i] != HWLOC_SUBBITMAP_FULL)
return 0;
return 1;
}
int hwloc_bitmap_isequal (const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
{
unsigned i;
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
for(i=0; i<set1->ulongs_count || i<set2->ulongs_count; i++)
if (HWLOC_SUBBITMAP_READULONG(set1, i) != HWLOC_SUBBITMAP_READULONG(set2, i))
return 0;
if (set1->infinite != set2->infinite)
return 0;
return 1;
}
int hwloc_bitmap_intersects (const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
{
unsigned i;
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
for(i=0; i<set1->ulongs_count || i<set2->ulongs_count; i++)
if ((HWLOC_SUBBITMAP_READULONG(set1, i) & HWLOC_SUBBITMAP_READULONG(set2, i)) != HWLOC_SUBBITMAP_ZERO)
return 1;
if (set1->infinite && set2->infinite)
return 0;
return 0;
}
int hwloc_bitmap_isincluded (const struct hwloc_bitmap_s *sub_set, const struct hwloc_bitmap_s *super_set)
{
unsigned i;
HWLOC__BITMAP_CHECK(sub_set);
HWLOC__BITMAP_CHECK(super_set);
for(i=0; i<sub_set->ulongs_count; i++)
if (HWLOC_SUBBITMAP_READULONG(super_set, i) != (HWLOC_SUBBITMAP_READULONG(super_set, i) | HWLOC_SUBBITMAP_READULONG(sub_set, i)))
return 0;
if (sub_set->infinite && !super_set->infinite)
return 0;
return 1;
}
void hwloc_bitmap_or (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
{
const struct hwloc_bitmap_s *largest = set1->ulongs_count > set2->ulongs_count ? set1 : set2;
unsigned i;
HWLOC__BITMAP_CHECK(res);
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
hwloc_bitmap_realloc_by_ulongs(res, largest->ulongs_count); /* cannot reset since the output may also be an input */
for(i=0; i<res->ulongs_count; i++)
res->ulongs[i] = HWLOC_SUBBITMAP_READULONG(set1, i) | HWLOC_SUBBITMAP_READULONG(set2, i);
res->infinite = set1->infinite || set2->infinite;
}
void hwloc_bitmap_and (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
{
const struct hwloc_bitmap_s *largest = set1->ulongs_count > set2->ulongs_count ? set1 : set2;
unsigned i;
HWLOC__BITMAP_CHECK(res);
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
hwloc_bitmap_realloc_by_ulongs(res, largest->ulongs_count); /* cannot reset since the output may also be an input */
for(i=0; i<res->ulongs_count; i++)
res->ulongs[i] = HWLOC_SUBBITMAP_READULONG(set1, i) & HWLOC_SUBBITMAP_READULONG(set2, i);
res->infinite = set1->infinite && set2->infinite;
}
void hwloc_bitmap_andnot (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
{
const struct hwloc_bitmap_s *largest = set1->ulongs_count > set2->ulongs_count ? set1 : set2;
unsigned i;
HWLOC__BITMAP_CHECK(res);
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
hwloc_bitmap_realloc_by_ulongs(res, largest->ulongs_count); /* cannot reset since the output may also be an input */
for(i=0; i<res->ulongs_count; i++)
res->ulongs[i] = HWLOC_SUBBITMAP_READULONG(set1, i) & ~HWLOC_SUBBITMAP_READULONG(set2, i);
res->infinite = set1->infinite && !set2->infinite;
}
void hwloc_bitmap_xor (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
{
const struct hwloc_bitmap_s *largest = set1->ulongs_count > set2->ulongs_count ? set1 : set2;
unsigned i;
HWLOC__BITMAP_CHECK(res);
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
hwloc_bitmap_realloc_by_ulongs(res, largest->ulongs_count); /* cannot reset since the output may also be an input */
for(i=0; i<res->ulongs_count; i++)
res->ulongs[i] = HWLOC_SUBBITMAP_READULONG(set1, i) ^ HWLOC_SUBBITMAP_READULONG(set2, i);
res->infinite = (!set1->infinite) != (!set2->infinite);
}
void hwloc_bitmap_not (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set)
{
unsigned i;
HWLOC__BITMAP_CHECK(res);
HWLOC__BITMAP_CHECK(set);
hwloc_bitmap_realloc_by_ulongs(res, set->ulongs_count); /* cannot reset since the output may also be an input */
for(i=0; i<res->ulongs_count; i++)
res->ulongs[i] = ~HWLOC_SUBBITMAP_READULONG(set, i);
res->infinite = !set->infinite;
}
int hwloc_bitmap_first(const struct hwloc_bitmap_s * set)
{
unsigned i;
HWLOC__BITMAP_CHECK(set);
for(i=0; i<set->ulongs_count; i++) {
/* subsets are unsigned longs, use ffsl */
unsigned long w = set->ulongs[i];
if (w)
return hwloc_ffsl(w) - 1 + HWLOC_BITS_PER_LONG*i;
}
if (set->infinite)
return set->ulongs_count * HWLOC_BITS_PER_LONG;
return -1;
}
int hwloc_bitmap_last(const struct hwloc_bitmap_s * set)
{
int i;
HWLOC__BITMAP_CHECK(set);
if (set->infinite)
return -1;
for(i=set->ulongs_count-1; i>=0; i--) {
/* subsets are unsigned longs, use flsl */
unsigned long w = set->ulongs[i];
if (w)
return hwloc_flsl(w) - 1 + HWLOC_BITS_PER_LONG*i;
}
return -1;
}
int hwloc_bitmap_next(const struct hwloc_bitmap_s * set, int prev_cpu)
{
unsigned i = HWLOC_SUBBITMAP_INDEX(prev_cpu + 1);
HWLOC__BITMAP_CHECK(set);
if (i >= set->ulongs_count) {
if (set->infinite)
return prev_cpu + 1;
else
return -1;
}
for(; i<set->ulongs_count; i++) {
/* subsets are unsigned longs, use ffsl */
unsigned long w = set->ulongs[i];
/* if the prev cpu is in the same word as the possible next one,
we need to mask out previous cpus */
if (prev_cpu >= 0 && HWLOC_SUBBITMAP_INDEX((unsigned) prev_cpu) == i)
w &= ~HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(prev_cpu));
if (w)
return hwloc_ffsl(w) - 1 + HWLOC_BITS_PER_LONG*i;
}
if (set->infinite)
return set->ulongs_count * HWLOC_BITS_PER_LONG;
return -1;
}
void hwloc_bitmap_singlify(struct hwloc_bitmap_s * set)
{
unsigned i;
int found = 0;
HWLOC__BITMAP_CHECK(set);
for(i=0; i<set->ulongs_count; i++) {
if (found) {
set->ulongs[i] = HWLOC_SUBBITMAP_ZERO;
continue;
} else {
/* subsets are unsigned longs, use ffsl */
unsigned long w = set->ulongs[i];
if (w) {
int _ffs = hwloc_ffsl(w);
set->ulongs[i] = HWLOC_SUBBITMAP_CPU(_ffs-1);
found = 1;
}
}
}
if (set->infinite) {
if (found) {
set->infinite = 0;
} else {
/* set the first non allocated bit */
unsigned first = set->ulongs_count * HWLOC_BITS_PER_LONG;
set->infinite = 0; /* do not let realloc fill the newly allocated sets */
hwloc_bitmap_set(set, first);
}
}
}
int hwloc_bitmap_compare_first(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2)
{
unsigned i;
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
for(i=0; i<set1->ulongs_count || i<set2->ulongs_count; i++) {
unsigned long w1 = HWLOC_SUBBITMAP_READULONG(set1, i);
unsigned long w2 = HWLOC_SUBBITMAP_READULONG(set2, i);
if (w1 || w2) {
int _ffs1 = hwloc_ffsl(w1);
int _ffs2 = hwloc_ffsl(w2);
/* if both have a bit set, compare for real */
if (_ffs1 && _ffs2)
return _ffs1-_ffs2;
/* one is empty, and it is considered higher, so reverse-compare them */
return _ffs2-_ffs1;
}
}
if ((!set1->infinite) != (!set2->infinite))
return !!set1->infinite - !!set2->infinite;
return 0;
}
int hwloc_bitmap_compare(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2)
{
const struct hwloc_bitmap_s *largest = set1->ulongs_count > set2->ulongs_count ? set1 : set2;
int i;
HWLOC__BITMAP_CHECK(set1);
HWLOC__BITMAP_CHECK(set2);
if ((!set1->infinite) != (!set2->infinite))
return !!set1->infinite - !!set2->infinite;
for(i=largest->ulongs_count-1; i>=0; i--) {
unsigned long val1 = HWLOC_SUBBITMAP_READULONG(set1, (unsigned) i);
unsigned long val2 = HWLOC_SUBBITMAP_READULONG(set2, (unsigned) i);
if (val1 == val2)
continue;
return val1 < val2 ? -1 : 1;
}
return 0;
}
int hwloc_bitmap_weight(const struct hwloc_bitmap_s * set)
{
int weight = 0;
unsigned i;
HWLOC__BITMAP_CHECK(set);
if (set->infinite)
return -1;
for(i=0; i<set->ulongs_count; i++)
weight += hwloc_weight_long(set->ulongs[i]);
return weight;
}
/********************************************************************
* everything below should be dropped when hwloc/cpuset.h is dropped
*/
/* for HWLOC_DECLSPEC */
#include <hwloc/autogen/config.h>
/* forward declarations (public headers do not export this API anymore) */
HWLOC_DECLSPEC struct hwloc_bitmap_s * hwloc_cpuset_alloc(void);
HWLOC_DECLSPEC void hwloc_cpuset_free(struct hwloc_bitmap_s * set);
HWLOC_DECLSPEC struct hwloc_bitmap_s * hwloc_cpuset_dup(const struct hwloc_bitmap_s * old);
HWLOC_DECLSPEC void hwloc_cpuset_copy(struct hwloc_bitmap_s * dst, const struct hwloc_bitmap_s * src);
HWLOC_DECLSPEC int hwloc_cpuset_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set);
HWLOC_DECLSPEC int hwloc_cpuset_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set);
HWLOC_DECLSPEC int hwloc_cpuset_from_string(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string);
HWLOC_DECLSPEC int hwloc_cpuset_taskset_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set);
HWLOC_DECLSPEC int hwloc_cpuset_taskset_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set);
HWLOC_DECLSPEC int hwloc_cpuset_taskset_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string);
HWLOC_DECLSPEC void hwloc_cpuset_zero(struct hwloc_bitmap_s * set);
HWLOC_DECLSPEC void hwloc_cpuset_fill(struct hwloc_bitmap_s * set);
HWLOC_DECLSPEC void hwloc_cpuset_from_ulong(struct hwloc_bitmap_s *set, unsigned long mask);
HWLOC_DECLSPEC void hwloc_cpuset_from_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask);
HWLOC_DECLSPEC unsigned long hwloc_cpuset_to_ulong(const struct hwloc_bitmap_s *set);
HWLOC_DECLSPEC unsigned long hwloc_cpuset_to_ith_ulong(const struct hwloc_bitmap_s *set, unsigned i);
HWLOC_DECLSPEC void hwloc_cpuset_cpu(struct hwloc_bitmap_s * set, unsigned cpu);
HWLOC_DECLSPEC void hwloc_cpuset_all_but_cpu(struct hwloc_bitmap_s * set, unsigned cpu);
HWLOC_DECLSPEC void hwloc_cpuset_set(struct hwloc_bitmap_s * set, unsigned cpu);
HWLOC_DECLSPEC void hwloc_cpuset_set_range(struct hwloc_bitmap_s * set, unsigned begincpu, unsigned endcpu);
HWLOC_DECLSPEC void hwloc_cpuset_set_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask);
HWLOC_DECLSPEC void hwloc_cpuset_clr(struct hwloc_bitmap_s * set, unsigned cpu);
HWLOC_DECLSPEC void hwloc_cpuset_clr_range(struct hwloc_bitmap_s * set, unsigned begincpu, unsigned endcpu);
HWLOC_DECLSPEC int hwloc_cpuset_isset(const struct hwloc_bitmap_s * set, unsigned cpu);
HWLOC_DECLSPEC int hwloc_cpuset_iszero(const struct hwloc_bitmap_s *set);
HWLOC_DECLSPEC int hwloc_cpuset_isfull(const struct hwloc_bitmap_s *set);
HWLOC_DECLSPEC int hwloc_cpuset_isequal(const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2);
HWLOC_DECLSPEC int hwloc_cpuset_intersects(const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2);
HWLOC_DECLSPEC int hwloc_cpuset_isincluded(const struct hwloc_bitmap_s *sub_set, const struct hwloc_bitmap_s *super_set);
HWLOC_DECLSPEC void hwloc_cpuset_or(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2);
HWLOC_DECLSPEC void hwloc_cpuset_and(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2);
HWLOC_DECLSPEC void hwloc_cpuset_andnot(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2);
HWLOC_DECLSPEC void hwloc_cpuset_xor(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2);
HWLOC_DECLSPEC void hwloc_cpuset_not(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set);
HWLOC_DECLSPEC int hwloc_cpuset_first(const struct hwloc_bitmap_s * set);
HWLOC_DECLSPEC int hwloc_cpuset_last(const struct hwloc_bitmap_s * set);
HWLOC_DECLSPEC int hwloc_cpuset_next(const struct hwloc_bitmap_s * set, unsigned prev_cpu);
HWLOC_DECLSPEC void hwloc_cpuset_singlify(struct hwloc_bitmap_s * set);
HWLOC_DECLSPEC int hwloc_cpuset_compare_first(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2);
HWLOC_DECLSPEC int hwloc_cpuset_compare(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2);
HWLOC_DECLSPEC int hwloc_cpuset_weight(const struct hwloc_bitmap_s * set);
/* actual symbols converting from cpuset ABI into bitmap ABI */
struct hwloc_bitmap_s * hwloc_cpuset_alloc(void) { return hwloc_bitmap_alloc(); }
void hwloc_cpuset_free(struct hwloc_bitmap_s * set) { hwloc_bitmap_free(set); }
struct hwloc_bitmap_s * hwloc_cpuset_dup(const struct hwloc_bitmap_s * old) { return hwloc_bitmap_dup(old); }
void hwloc_cpuset_copy(struct hwloc_bitmap_s * dst, const struct hwloc_bitmap_s * src) { hwloc_bitmap_copy(dst, src); }
int hwloc_cpuset_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set) { return hwloc_bitmap_snprintf(buf, buflen, set); }
int hwloc_cpuset_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set) { return hwloc_bitmap_asprintf(strp, set); }
int hwloc_cpuset_from_string(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string) { return hwloc_bitmap_sscanf(set, string); }
int hwloc_cpuset_taskset_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set) { return hwloc_bitmap_taskset_snprintf(buf, buflen, set); }
int hwloc_cpuset_taskset_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set) { return hwloc_bitmap_taskset_asprintf(strp, set); }
int hwloc_cpuset_taskset_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string) { return hwloc_bitmap_taskset_sscanf(set, string); }
void hwloc_cpuset_zero(struct hwloc_bitmap_s * set) { hwloc_bitmap_zero(set); }
void hwloc_cpuset_fill(struct hwloc_bitmap_s * set) { hwloc_bitmap_fill(set); }
void hwloc_cpuset_from_ulong(struct hwloc_bitmap_s *set, unsigned long mask) { hwloc_bitmap_from_ulong(set, mask); }
void hwloc_cpuset_from_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask) { hwloc_bitmap_from_ith_ulong(set, i, mask); }
unsigned long hwloc_cpuset_to_ulong(const struct hwloc_bitmap_s *set) { return hwloc_bitmap_to_ulong(set); }
unsigned long hwloc_cpuset_to_ith_ulong(const struct hwloc_bitmap_s *set, unsigned i) { return hwloc_bitmap_to_ith_ulong(set, i); }
void hwloc_cpuset_cpu(struct hwloc_bitmap_s * set, unsigned cpu) { hwloc_bitmap_only(set, cpu); }
void hwloc_cpuset_all_but_cpu(struct hwloc_bitmap_s * set, unsigned cpu) { hwloc_bitmap_allbut(set, cpu); }
void hwloc_cpuset_set(struct hwloc_bitmap_s * set, unsigned cpu) { hwloc_bitmap_set(set, cpu); }
void hwloc_cpuset_set_range(struct hwloc_bitmap_s * set, unsigned begincpu, unsigned endcpu) { hwloc_bitmap_set_range(set, begincpu, endcpu); }
void hwloc_cpuset_set_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask) { hwloc_bitmap_set_ith_ulong(set, i, mask); }
void hwloc_cpuset_clr(struct hwloc_bitmap_s * set, unsigned cpu) { hwloc_bitmap_clr(set, cpu); }
void hwloc_cpuset_clr_range(struct hwloc_bitmap_s * set, unsigned begincpu, unsigned endcpu) { hwloc_bitmap_clr_range(set, begincpu, endcpu); }
int hwloc_cpuset_isset(const struct hwloc_bitmap_s * set, unsigned cpu) { return hwloc_bitmap_isset(set, cpu); }
int hwloc_cpuset_iszero(const struct hwloc_bitmap_s *set) { return hwloc_bitmap_iszero(set); }
int hwloc_cpuset_isfull(const struct hwloc_bitmap_s *set) { return hwloc_bitmap_isfull(set); }
int hwloc_cpuset_isequal(const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) { return hwloc_bitmap_isequal(set1, set2); }
int hwloc_cpuset_intersects(const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) { return hwloc_bitmap_intersects(set1, set2); }
int hwloc_cpuset_isincluded(const struct hwloc_bitmap_s *sub_set, const struct hwloc_bitmap_s *super_set) { return hwloc_bitmap_isincluded(sub_set, super_set); }
void hwloc_cpuset_or(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) { hwloc_bitmap_or(res, set1, set2); }
void hwloc_cpuset_and(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) { hwloc_bitmap_and(res, set1, set2); }
void hwloc_cpuset_andnot(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) { hwloc_bitmap_andnot(res, set1, set2); }
void hwloc_cpuset_xor(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) { hwloc_bitmap_xor(res, set1, set2); }
void hwloc_cpuset_not(struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set) { hwloc_bitmap_not(res, set); }
int hwloc_cpuset_first(const struct hwloc_bitmap_s * set) { return hwloc_bitmap_first(set); }
int hwloc_cpuset_last(const struct hwloc_bitmap_s * set) { return hwloc_bitmap_last(set); }
int hwloc_cpuset_next(const struct hwloc_bitmap_s * set, unsigned prev_cpu) { return hwloc_bitmap_next(set, prev_cpu); }
void hwloc_cpuset_singlify(struct hwloc_bitmap_s * set) { hwloc_bitmap_singlify(set); }
int hwloc_cpuset_compare_first(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2) { return hwloc_bitmap_compare_first(set1, set2); }
int hwloc_cpuset_compare(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2) { return hwloc_bitmap_compare(set1, set2); }
int hwloc_cpuset_weight(const struct hwloc_bitmap_s * set) { return hwloc_bitmap_weight(set); }
/*
* end of everything to be dropped when hwloc/cpuset.h is dropped
*****************************************************************/
/*
* Copyright © 2010-2011 INRIA. All rights reserved.
* Copyright © 2011 Université Bordeaux 1
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
#include <private/autogen/config.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#include <float.h>
/* called during topology init */
void hwloc_topology_distances_init(struct hwloc_topology *topology)
{
unsigned i;
for (i=0; i < HWLOC_OBJ_TYPE_MAX; i++) {
/* no distances yet */
topology->os_distances[i].nbobjs = 0;
topology->os_distances[i].objs = NULL;
topology->os_distances[i].indexes = NULL;
topology->os_distances[i].distances = NULL;
}
}
/* called when reloading a topology.
* keep initial parameters (from set_distances and environment),
* but drop what was generated during previous load().
*/
void hwloc_topology_distances_clear(struct hwloc_topology *topology)
{
unsigned i;
for (i=0; i < HWLOC_OBJ_TYPE_MAX; i++) {
/* remove final distance matrices, but keep physically-ordered ones */
free(topology->os_distances[i].objs);
topology->os_distances[i].objs = NULL;
}
}
/* called during topology destroy */
void hwloc_topology_distances_destroy(struct hwloc_topology *topology)
{
unsigned i;
for (i=0; i < HWLOC_OBJ_TYPE_MAX; i++) {
/* remove final distance matrics AND physically-ordered ones */
free(topology->os_distances[i].indexes);
topology->os_distances[i].indexes = NULL;
free(topology->os_distances[i].objs);
topology->os_distances[i].objs = NULL;
free(topology->os_distances[i].distances);
topology->os_distances[i].distances = NULL;
}
}
/* insert a distance matrix in the topology.
* the caller gives us those pointers, we take care of freeing them later and so on.
*/
void hwloc_topology__set_distance_matrix(hwloc_topology_t __hwloc_restrict topology, hwloc_obj_type_t type,
unsigned nbobjs, unsigned *indexes, hwloc_obj_t *objs, float *distances)
{
free(topology->os_distances[type].indexes);
free(topology->os_distances[type].objs);
free(topology->os_distances[type].distances);
topology->os_distances[type].nbobjs = nbobjs;
topology->os_distances[type].indexes = indexes;
topology->os_distances[type].objs = objs;
topology->os_distances[type].distances = distances;
}
/* make sure a user-given distance matrix is sane */
static int hwloc_topology__check_distance_matrix(hwloc_topology_t __hwloc_restrict topology __hwloc_attribute_unused, hwloc_obj_type_t type __hwloc_attribute_unused,
unsigned nbobjs, unsigned *indexes, hwloc_obj_t *objs __hwloc_attribute_unused, float *distances __hwloc_attribute_unused)
{
unsigned i,j;
/* make sure we don't have the same index twice */
for(i=0; i<nbobjs; i++)
for(j=i+1; j<nbobjs; j++)
if (indexes[i] == indexes[j]) {
errno = EINVAL;
return -1;
}
return 0;
}
static hwloc_obj_t hwloc_find_obj_by_type_and_os_index(hwloc_obj_t root, hwloc_obj_type_t type, unsigned os_index)
{
hwloc_obj_t child;
if (root->type == type && root->os_index == os_index)
return root;
child = root->first_child;
while (child) {
hwloc_obj_t found = hwloc_find_obj_by_type_and_os_index(child, type, os_index);
if (found)
return found;
child = child->next_sibling;
}
return NULL;
}
static void hwloc_get_type_distances_from_string(struct hwloc_topology *topology,
hwloc_obj_type_t type, char *string)
{
/* the string format is: "index[0],...,index[N-1]:distance[0],...,distance[N*N-1]"
* or "index[0],...,index[N-1]:X*Y" or "index[0],...,index[N-1]:X*Y*Z"
*/
char *tmp = string, *next;
unsigned *indexes;
float *distances;
unsigned nbobjs = 0, i, j, x, y, z;
/* count indexes */
while (1) {
size_t size = strspn(tmp, "0123456789");
if (tmp[size] != ',') {
/* last element */
tmp += size;
nbobjs++;
break;
}
/* another index */
tmp += size+1;
nbobjs++;
}
if (*tmp != ':') {
fprintf(stderr, "Ignoring %s distances from environment variable, missing colon\n",
hwloc_obj_type_string(type));
return;
}
indexes = calloc(nbobjs, sizeof(unsigned));
distances = calloc(nbobjs*nbobjs, sizeof(float));
tmp = string;
/* parse indexes */
for(i=0; i<nbobjs; i++) {
indexes[i] = strtoul(tmp, &next, 0);
tmp = next+1;
}
/* parse distances */
z=1; /* default if sscanf finds only 2 values below */
if (sscanf(tmp, "%u*%u*%u", &x, &y, &z) >= 2) {
/* generate the matrix to create x groups of y elements */
if (x*y*z != nbobjs) {
fprintf(stderr, "Ignoring %s distances from environment variable, invalid grouping (%u*%u*%u=%u instead of %u)\n",
hwloc_obj_type_string(type), x, y, z, x*y*z, nbobjs);
free(indexes);
free(distances);
return;
}
for(i=0; i<nbobjs; i++)
for(j=0; j<nbobjs; j++)
if (i==j)
distances[i*nbobjs+j] = 1;
else if (i/z == j/z)
distances[i*nbobjs+j] = 2;
else if (i/z/y == j/z/y)
distances[i*nbobjs+j] = 4;
else
distances[i*nbobjs+j] = 8;
} else {
/* parse a comma separated list of distances */
for(i=0; i<nbobjs*nbobjs; i++) {
distances[i] = atof(tmp);
next = strchr(tmp, ',');
if (next) {
tmp = next+1;
} else if (i!=nbobjs*nbobjs-1) {
fprintf(stderr, "Ignoring %s distances from environment variable, not enough values (%u out of %u)\n",
hwloc_obj_type_string(type), i+1, nbobjs*nbobjs);
free(indexes);
free(distances);
return;
}
}
}
if (hwloc_topology__check_distance_matrix(topology, type, nbobjs, indexes, NULL, distances) < 0) {
fprintf(stderr, "Ignoring invalid %s distances from environment variable\n", hwloc_obj_type_string(type));
free(indexes);
free(distances);
return;
}
hwloc_topology__set_distance_matrix(topology, type, nbobjs, indexes, NULL, distances);
}
/* take distances in the environment, store them as is in the topology.
* we'll convert them into object later once the tree is filled
*/
void hwloc_store_distances_from_env(struct hwloc_topology *topology)
{
hwloc_obj_type_t type;
for(type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) {
char *env, envname[64];
snprintf(envname, sizeof(envname), "HWLOC_%s_DISTANCES", hwloc_obj_type_string(type));
env = getenv(envname);
if (env)
hwloc_get_type_distances_from_string(topology, type, env);
}
}
/* take the given distance, store them as is in the topology.
* we'll convert them into object later once the tree is filled.
*/
int hwloc_topology_set_distance_matrix(hwloc_topology_t __hwloc_restrict topology, hwloc_obj_type_t type,
unsigned nbobjs, unsigned *indexes, float *distances)
{
unsigned *_indexes;
float *_distances;
if (hwloc_topology__check_distance_matrix(topology, type, nbobjs, indexes, NULL, distances) < 0)
return -1;
/* copy the input arrays and give them to the topology */
_indexes = malloc(nbobjs*sizeof(unsigned));
memcpy(_indexes, indexes, nbobjs*sizeof(unsigned));
_distances = malloc(nbobjs*nbobjs*sizeof(float));
memcpy(_distances, distances, nbobjs*nbobjs*sizeof(float));
hwloc_topology__set_distance_matrix(topology, type, nbobjs, _indexes, NULL, _distances);
return 0;
}
/* cleanup everything we created from distances so that we may rebuild them
* at the end of restrict()
*/
void hwloc_restrict_distances(struct hwloc_topology *topology, unsigned long flags)
{
hwloc_obj_type_t type;
for(type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) {
/* remove the objs array, we'll rebuild it from the indexes
* depending on remaining objects */
free(topology->os_distances[type].objs);
topology->os_distances[type].objs = NULL;
/* if not adapting distances, drop everything */
if (!(flags & HWLOC_RESTRICT_FLAG_ADAPT_DISTANCES)) {
free(topology->os_distances[type].indexes);
topology->os_distances[type].indexes = NULL;
free(topology->os_distances[type].distances);
topology->os_distances[type].distances = NULL;
topology->os_distances[type].nbobjs = 0;
}
}
}
/* convert distance indexes that were previously stored in the topology
* into actual objects if not done already.
* it's already done when distances come from backends.
* it's not done when distances come from the user.
*/
void hwloc_convert_distances_indexes_into_objects(struct hwloc_topology *topology)
{
hwloc_obj_type_t type;
for(type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) {
unsigned nbobjs = topology->os_distances[type].nbobjs;
unsigned *indexes = topology->os_distances[type].indexes;
float *distances = topology->os_distances[type].distances;
unsigned i, j;
if (!topology->os_distances[type].objs) {
hwloc_obj_t *objs = calloc(nbobjs, sizeof(hwloc_obj_t));
/* traverse the topology and look for the relevant objects */
for(i=0; i<nbobjs; i++) {
hwloc_obj_t obj = hwloc_find_obj_by_type_and_os_index(topology->levels[0][0], type, indexes[i]);
if (!obj) {
/* shift the matrix */
#define OLDPOS(i,j) (distances+(i)*nbobjs+(j))
#define NEWPOS(i,j) (distances+(i)*(nbobjs-1)+(j))
if (i>0) {
/** no need to move beginning of 0th line */
for(j=0; j<i-1; j++)
/** move end of jth line + beginning of (j+1)th line */
memmove(NEWPOS(j,i), OLDPOS(j,i+1), (nbobjs-1)*sizeof(*distances));
/** move end of (i-1)th line */
memmove(NEWPOS(i-1,i), OLDPOS(i-1,i+1), (nbobjs-i-1)*sizeof(*distances));
}
if (i<nbobjs-1) {
/** move beginning of (i+1)th line */
memmove(NEWPOS(i,0), OLDPOS(i+1,0), i*sizeof(*distances));
/** move end of jth line + beginning of (j+1)th line */
for(j=i; j<nbobjs-1; j++)
memmove(NEWPOS(j,i), OLDPOS(j+1,i+1), (nbobjs-1)*sizeof(*distances));
/** move end of (nbobjs-2)th line */
memmove(NEWPOS(nbobjs-2,i), OLDPOS(nbobjs-1,i+1), (nbobjs-i-1)*sizeof(*distances));
}
/* shift the indexes array */
memmove(indexes+i, indexes+i+1, (nbobjs-i-1)*sizeof(*indexes));
/* update counters */
nbobjs--;
i--;
continue;
}
objs[i] = obj;
}
topology->os_distances[type].nbobjs = nbobjs;
if (!nbobjs) {
/* the whole matrix was invalid */
free(objs);
free(topology->os_distances[type].indexes);
topology->os_distances[type].indexes = NULL;
free(topology->os_distances[type].distances);
topology->os_distances[type].distances = NULL;
} else {
/* setup the objs array */
topology->os_distances[type].objs = objs;
}
}
}
}
static void
hwloc_setup_distances_from_os_matrix(struct hwloc_topology *topology,
unsigned nbobjs,
hwloc_obj_t *objs, float *osmatrix)
{
unsigned i, j, li, lj, minl;
float min = FLT_MAX, max = FLT_MIN;
hwloc_obj_t root;
float *matrix;
hwloc_cpuset_t set;
unsigned relative_depth;
int idx;
/* find the root */
set = hwloc_bitmap_alloc();
for(i=0; i<nbobjs; i++)
hwloc_bitmap_or(set, set, objs[i]->cpuset);
root = hwloc_get_obj_covering_cpuset(topology, set);
assert(root);
if (!hwloc_bitmap_isequal(set, root->cpuset)) {
/* partial distance matrix not including all the children of a single object */
/* TODO insert an intermediate object (group?) covering only these children ? */
hwloc_bitmap_free(set);
return;
}
hwloc_bitmap_free(set);
relative_depth = objs[0]->depth - root->depth; /* this assume that we have distances between objects of the same level */
/* get the logical index offset, it's the min of all logical indexes */
minl = UINT_MAX;
for(i=0; i<nbobjs; i++)
if (minl > objs[i]->logical_index)
minl = objs[i]->logical_index;
/* compute/check min/max values */
for(i=0; i<nbobjs; i++)
for(j=0; j<nbobjs; j++) {
float val = osmatrix[i*nbobjs+j];
if (val < min)
min = val;
if (val > max)
max = val;
}
if (!min) {
/* Linux up to 2.6.36 reports ACPI SLIT distances, which should be memory latencies.
* Except of SGI IP27 (SGI Origin 200/2000 with MIPS processors) where the distances
* are the number of hops between routers.
*/
hwloc_debug("%s", "minimal distance is 0, matrix does not seem to contain latencies, ignoring\n");
return;
}
/* store the normalized latency matrix in the root object */
idx = root->distances_count++;
root->distances = realloc(root->distances, root->distances_count * sizeof(struct hwloc_distances_s *));
root->distances[idx] = malloc(sizeof(struct hwloc_distances_s));
root->distances[idx]->relative_depth = relative_depth;
root->distances[idx]->nbobjs = nbobjs;
root->distances[idx]->latency = matrix = malloc(nbobjs*nbobjs*sizeof(float));
root->distances[idx]->latency_base = (float) min;
#define NORMALIZE_LATENCY(d) ((d)/(min))
root->distances[idx]->latency_max = NORMALIZE_LATENCY(max);
for(i=0; i<nbobjs; i++) {
li = objs[i]->logical_index - minl;
matrix[li*nbobjs+li] = NORMALIZE_LATENCY(osmatrix[i*nbobjs+i]);
for(j=i+1; j<nbobjs; j++) {
lj = objs[j]->logical_index - minl;
matrix[li*nbobjs+lj] = NORMALIZE_LATENCY(osmatrix[i*nbobjs+j]);
matrix[lj*nbobjs+li] = NORMALIZE_LATENCY(osmatrix[j*nbobjs+i]);
}
}
}
/* convert internal distances into logically-ordered distances
* that can be exposed in the API
*/
void
hwloc_finalize_logical_distances(struct hwloc_topology *topology)
{
unsigned nbobjs;
hwloc_obj_type_t type;
int depth;
for (type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) {
nbobjs = topology->os_distances[type].nbobjs;
if (!nbobjs)
continue;
depth = hwloc_get_type_depth(topology, type);
if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
continue;
if (topology->os_distances[type].objs) {
assert(topology->os_distances[type].distances);
hwloc_setup_distances_from_os_matrix(topology, nbobjs,
topology->os_distances[type].objs,
topology->os_distances[type].distances);
}
}
}
/* destroy a object distances structure */
void
hwloc_free_logical_distances(struct hwloc_distances_s * dist)
{
free(dist->latency);
free(dist);
}
static void hwloc_report_user_distance_error(const char *msg, int line)
{
static int reported = 0;
if (!reported) {
fprintf(stderr, "****************************************************************************\n");
fprintf(stderr, "* Hwloc has encountered what looks like an error from user-given distances.\n");
fprintf(stderr, "*\n");
fprintf(stderr, "* %s\n", msg);
fprintf(stderr, "* Error occurred in topology.c line %d\n", line);
fprintf(stderr, "*\n");
fprintf(stderr, "* Please make sure that distances given through the interface or environment\n");
fprintf(stderr, "* variables do not contradict any other topology information.\n");
fprintf(stderr, "****************************************************************************\n");
reported = 1;
}
}
/*
* Place objects in groups if they are in a transitive graph of minimal distances.
* Return how many groups were created, or 0 if some incomplete distance graphs were found.
*/
static unsigned
hwloc_setup_group_from_min_distance(unsigned nbobjs,
float *_distances,
unsigned *groupids)
{
float min_distance = FLT_MAX;
unsigned groupid = 1;
unsigned i,j,k;
unsigned skipped = 0;
#define DISTANCE(i, j) _distances[(i) * nbobjs + (j)]
memset(groupids, 0, nbobjs*sizeof(*groupids));
/* find the minimal distance */
for(i=0; i<nbobjs; i++)
for(j=i+1; j<nbobjs; j++)
if (DISTANCE(i, j) < min_distance)
min_distance = DISTANCE(i, j);
hwloc_debug("found minimal distance %f between objects\n", min_distance);
if (min_distance == FLT_MAX)
return 0;
/* build groups of objects connected with this distance */
for(i=0; i<nbobjs; i++) {
unsigned size;
int firstfound;
/* if already grouped, skip */
if (groupids[i])
continue;
/* start a new group */
groupids[i] = groupid;
size = 1;
firstfound = i;
while (firstfound != -1) {
/* we added new objects to the group, the first one was firstfound.
* rescan all connections from these new objects (starting at first found) to any other objects,
* so as to find new objects minimally-connected by transivity.
*/
int newfirstfound = -1;
for(j=firstfound; j<nbobjs; j++)
if (groupids[j] == groupid)
for(k=0; k<nbobjs; k++)
if (!groupids[k] && DISTANCE(j, k) == min_distance) {
groupids[k] = groupid;
size++;
if (newfirstfound == -1)
newfirstfound = k;
if (i == j)
hwloc_debug("object %u is minimally connected to %u\n", k, i);
else
hwloc_debug("object %u is minimally connected to %u through %u\n", k, i, j);
}
firstfound = newfirstfound;
}
if (size == 1) {
/* cancel this useless group, ignore this object and try from the next one */
groupids[i] = 0;
skipped++;
continue;
}
/* valid this group */
groupid++;
hwloc_debug("found transitive graph with %u objects with minimal distance %f\n",
size, min_distance);
}
if (groupid == 2 && !skipped)
/* we created a single group containing all objects, ignore it */
return 0;
/* return the last id, since it's also the number of used group ids */
return groupid-1;
}
/*
* Look at object physical distances to group them,
* after having done some basic sanity checks.
*/
static void
hwloc__setup_groups_from_distances(struct hwloc_topology *topology,
unsigned nbobjs,
struct hwloc_obj **objs,
float *_distances,
int fromuser)
{
unsigned *groupids = NULL;
unsigned nbgroups;
unsigned i,j;
hwloc_debug("trying to group %s objects into Group objects according to physical distances\n",
hwloc_obj_type_string(objs[0]->type));
if (nbobjs <= 2) {
return;
}
groupids = malloc(sizeof(unsigned) * nbobjs);
if (NULL == groupids) {
return;
}
nbgroups = hwloc_setup_group_from_min_distance(nbobjs, _distances, groupids);
if (!nbgroups) {
goto outter_free;
}
/* For convenience, put these declarations inside a block. It's a
crying shame we can't use C99 syntax here, and have to do a bunch
of mallocs. :-( */
{
hwloc_obj_t *groupobjs = NULL;
unsigned *groupsizes = NULL;
float *groupdistances = NULL;
groupobjs = malloc(sizeof(hwloc_obj_t) * nbgroups);
groupsizes = malloc(sizeof(unsigned) * nbgroups);
groupdistances = malloc(sizeof(float) * nbgroups * nbgroups);
if (NULL == groupobjs || NULL == groupsizes || NULL == groupdistances) {
goto inner_free;
}
/* create new Group objects and record their size */
memset(&(groupsizes[0]), 0, sizeof(groupsizes[0]) * nbgroups);
for(i=0; i<nbgroups; i++) {
/* create the Group object */
hwloc_obj_t group_obj;
group_obj = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, -1);
group_obj->cpuset = hwloc_bitmap_alloc();
group_obj->attr->group.depth = topology->next_group_depth;
for (j=0; j<nbobjs; j++)
if (groupids[j] == i+1) {
hwloc_bitmap_or(group_obj->cpuset, group_obj->cpuset, objs[j]->cpuset);
groupsizes[i]++;
}
hwloc_debug_1arg_bitmap("adding Group object with %u objects and cpuset %s\n",
groupsizes[i], group_obj->cpuset);
hwloc__insert_object_by_cpuset(topology, group_obj,
fromuser ? hwloc_report_user_distance_error : hwloc_report_os_error);
groupobjs[i] = group_obj;
}
/* factorize distances */
memset(&(groupdistances[0]), 0, sizeof(groupdistances[0]) * nbgroups * nbgroups);
#undef DISTANCE
#define DISTANCE(i, j) _distances[(i) * nbobjs + (j)]
#define GROUP_DISTANCE(i, j) groupdistances[(i) * nbgroups + (j)]
for(i=0; i<nbobjs; i++)
if (groupids[i])
for(j=0; j<nbobjs; j++)
if (groupids[j])
GROUP_DISTANCE(groupids[i]-1, groupids[j]-1) += DISTANCE(i, j);
for(i=0; i<nbgroups; i++)
for(j=0; j<nbgroups; j++)
GROUP_DISTANCE(i, j) /= groupsizes[i]*groupsizes[j];
#ifdef HWLOC_DEBUG
hwloc_debug("%s", "generated new distance matrix between groups:\n");
hwloc_debug("%s", " index");
for(j=0; j<nbgroups; j++)
hwloc_debug(" % 5d", (int) j); /* print index because os_index is -1 fro Groups */
hwloc_debug("%s", "\n");
for(i=0; i<nbgroups; i++) {
hwloc_debug(" % 5d", (int) i);
for(j=0; j<nbgroups; j++)
hwloc_debug(" %2.3f", GROUP_DISTANCE(i, j));
hwloc_debug("%s", "\n");
}
#endif
topology->next_group_depth++;
hwloc__setup_groups_from_distances(topology, nbgroups, groupobjs, (float*) groupdistances, fromuser);
inner_free:
/* Safely free everything */
if (NULL != groupobjs) {
free(groupobjs);
}
if (NULL != groupsizes) {
free(groupsizes);
}
if (NULL != groupdistances) {
free(groupdistances);
}
}
outter_free:
if (NULL != groupids) {
free(groupids);
}
}
/*
* Look at object physical distances to group them.
*/
static void
hwloc_setup_groups_from_distances(struct hwloc_topology *topology,
unsigned nbobjs,
struct hwloc_obj **objs,
float *_distances,
int fromuser)
{
unsigned i,j;
if (getenv("HWLOC_IGNORE_DISTANCES"))
return;
#ifdef HWLOC_DEBUG
hwloc_debug("%s", "trying to group objects using distance matrix:\n");
hwloc_debug("%s", " index");
for(j=0; j<nbobjs; j++)
hwloc_debug(" % 5d", (int) objs[j]->os_index);
hwloc_debug("%s", "\n");
for(i=0; i<nbobjs; i++) {
hwloc_debug(" % 5d", (int) objs[i]->os_index);
for(j=0; j<nbobjs; j++)
hwloc_debug(" %2.3f", DISTANCE(i, j));
hwloc_debug("%s", "\n");
}
#endif
/* check that the matrix is ok */
for(i=0; i<nbobjs; i++) {
for(j=i+1; j<nbobjs; j++) {
/* should be symmetric */
if (DISTANCE(i, j) != DISTANCE(j, i)) {
hwloc_debug("distance matrix asymmetric ([%u,%u]=%f != [%u,%u]=%f), aborting\n",
i, j, DISTANCE(i, j), j, i, DISTANCE(j, i));
return;
}
/* diagonal is smaller than everything else */
if (DISTANCE(i, j) <= DISTANCE(i, i)) {
hwloc_debug("distance to self not strictly minimal ([%u,%u]=%f <= [%u,%u]=%f), aborting\n",
i, j, DISTANCE(i, j), i, i, DISTANCE(i, i));
return;
}
}
}
hwloc__setup_groups_from_distances(topology, nbobjs, objs, _distances, fromuser);
}
void
hwloc_group_by_distances(struct hwloc_topology *topology)
{
unsigned nbobjs;
hwloc_obj_type_t type;
for (type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) {
nbobjs = topology->os_distances[type].nbobjs;
if (!nbobjs)
continue;
if (topology->os_distances[type].objs) {
/* if we have objs, we must have distances as well,
* thanks to hwloc_convert_distances_indexes_into_objects()
*/
assert(topology->os_distances[type].distances);
hwloc_setup_groups_from_distances(topology, nbobjs,
topology->os_distances[type].objs,
topology->os_distances[type].distances,
topology->os_distances[type].indexes != NULL);
}
}
}
/*
* Copyright © 2009 CNRS
* Copyright © 2009 INRIA. All rights reserved.
* Copyright © 2009 Université Bordeaux 1
* See COPYING in top-level directory.
*/
/* Wrapper to avoid msys' tendency to turn / into \ and : into ; */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char *prog, *arch, *def, *name, *lib;
char s[1024];
if (argc != 6) {
fprintf(stderr,"bad number of arguments");
exit(EXIT_FAILURE);
}
prog = argv[1];
arch = argv[2];
def = argv[3];
name = argv[4];
lib = argv[5];
snprintf(s, sizeof(s), "\"%s\" /machine:%s /def:%s /name:%s /out:%s",
prog, arch, def, name, lib);
if (system(s)) {
fprintf(stderr, "%s failed\n", s);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
<!ELEMENT topology (object)+>
<!ELEMENT root (object)+>
<!ELEMENT object (page_type*,info*,distances*,object*)>
<!ATTLIST object type (System | Machine | Misc | Group | NUMANode | Socket| Cache | Core | PU) #REQUIRED>
<!ATTLIST object os_level CDATA "-1" >
<!ATTLIST object os_index CDATA "-1" >
<!ATTLIST object name CDATA "" >
<!ATTLIST object local_memory CDATA "0" >
<!ATTLIST object cache_size CDATA "0" >
<!ATTLIST object cache_linesize CDATA "0" >
<!ATTLIST object huge_page_size_kB CDATA "0" >
<!ATTLIST object huge_page_free CDATA "0" >
<!ATTLIST object depth CDATA "-1" >
<!ATTLIST object cpuset CDATA "0" >
<!ATTLIST object complete_cpuset CDATA "" >
<!ATTLIST object online_cpuset CDATA "" >
<!ATTLIST object allowed_cpuset CDATA "" >
<!ATTLIST object nodeset CDATA "" >
<!ATTLIST object complete_nodeset CDATA "" >
<!ATTLIST object allowed_nodeset CDATA "" >
<!ELEMENT page_type EMPTY>
<!ATTLIST page_type size CDATA #REQUIRED>
<!ATTLIST page_type count CDATA #REQUIRED>
<!ELEMENT info EMPTY>
<!ATTLIST info name CDATA #REQUIRED>
<!ATTLIST info value CDATA #REQUIRED>
<!ELEMENT distances (latency*)>
<!ATTLIST distances nbobjs CDATA #REQUIRED>
<!ATTLIST distances relative_depth CDATA #REQUIRED>
<!ATTLIST distances latency_base CDATA #REQUIRED>
<!ELEMENT latency EMPTY>
<!ATTLIST latency value CDATA #REQUIRED>
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2010 INRIA. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux 1
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
#include <private/autogen/config.h>
#include <private/misc.h>
#include <stdarg.h>
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
int hwloc_snprintf(char *str, size_t size, const char *format, ...)
{
int ret;
va_list ap;
static char bin;
size_t fakesize;
char *fakestr;
/* Some systems crash on str == NULL */
if (!size) {
str = &bin;
size = 1;
}
va_start(ap, format);
ret = vsnprintf(str, size, format, ap);
va_end(ap);
if (ret >= 0 && (size_t) ret != size-1)
return ret;
/* vsnprintf returned size-1 or -1. That could be a system which reports the
* written data and not the actually required room. Try increasing buffer
* size to get the latter. */
fakesize = size;
fakestr = NULL;
do {
fakesize *= 2;
free(fakestr);
fakestr = malloc(fakesize);
if (NULL == fakestr)
return -1;
va_start(ap, format);
errno = 0;
ret = vsnprintf(fakestr, fakesize, format, ap);
va_end(ap);
} while ((size_t) ret == fakesize-1 || (ret < 0 && (!errno || errno == ERANGE)));
if (ret >= 0 && size) {
if (size > (size_t) ret+1)
size = ret+1;
memcpy(str, fakestr, size-1);
str[size-1] = 0;
}
free(fakestr);
return ret;
}
int hwloc_namecoloncmp(const char *haystack, const char *needle, size_t n)
{
size_t i = 0;
while (*haystack && *haystack != ':') {
int ha = *haystack++;
int low_h = tolower(ha);
int ne = *needle++;
int low_n = tolower(ne);
if (low_h != low_n)
return 1;
i++;
}
return i < n;
}
void hwloc_add_uname_info(struct hwloc_topology *topology __hwloc_attribute_unused)
{
#ifdef HAVE_UNAME
struct utsname utsname;
if (uname(&utsname) < 0)
return;
hwloc_add_object_info(topology->levels[0][0], "OSName", utsname.sysname);
hwloc_add_object_info(topology->levels[0][0], "OSRelease", utsname.release);
hwloc_add_object_info(topology->levels[0][0], "OSVersion", utsname.version);
hwloc_add_object_info(topology->levels[0][0], "HostName", utsname.nodename);
hwloc_add_object_info(topology->levels[0][0], "Architecture", utsname.machine);
#endif /* HAVE_UNAME */
}
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2010 INRIA. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux 1
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
/* TODO: use SIGRECONFIG & dr_reconfig for state change */
#include <private/autogen/config.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#include <sys/rset.h>
#include <sys/processor.h>
#include <sys/thread.h>
#include <sys/mman.h>
#include <sys/systemcfg.h>
static int
hwloc_aix_set_sth_cpubind(hwloc_topology_t topology, rstype_t what, rsid_t who, hwloc_const_bitmap_t hwloc_set, int flags __hwloc_attribute_unused)
{
rsethandle_t rad;
int res;
unsigned cpu;
if (flags & HWLOC_CPUBIND_NOMEMBIND) {
errno = ENOSYS;
return -1;
}
/* The resulting binding is always strict */
if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) {
if (ra_detachrset(what, who, 0))
return -1;
return 0;
}
rad = rs_alloc(RS_EMPTY);
hwloc_bitmap_foreach_begin(cpu, hwloc_set)
rs_op(RS_ADDRESOURCE, rad, NULL, R_PROCS, cpu);
hwloc_bitmap_foreach_end();
res = ra_attachrset(what, who, rad, 0);
rs_free(rad);
return res;
}
static int
hwloc_aix_get_sth_cpubind(hwloc_topology_t topology, rstype_t what, rsid_t who, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused)
{
rsethandle_t rset;
unsigned cpu, maxcpus;
int res = -1;
rset = rs_alloc(RS_EMPTY);
if (ra_getrset(what, who, 0, rset) == -1)
goto out;
hwloc_bitmap_zero(hwloc_set);
maxcpus = rs_getinfo(rset, R_MAXPROCS, 0);
for (cpu = 0; cpu < maxcpus; cpu++)
if (rs_op(RS_TESTRESOURCE, rset, NULL, R_PROCS, cpu) == 1)
hwloc_bitmap_set(hwloc_set, cpu);
hwloc_bitmap_and(hwloc_set, hwloc_set, hwloc_topology_get_complete_cpuset(topology));
res = 0;
out:
rs_free(rset);
return res;
}
static int
hwloc_aix_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
rsid_t who;
who.at_pid = getpid();
return hwloc_aix_set_sth_cpubind(topology, R_PROCESS, who, hwloc_set, flags);
}
static int
hwloc_aix_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags)
{
rsid_t who;
who.at_pid = getpid();
return hwloc_aix_get_sth_cpubind(topology, R_PROCESS, who, hwloc_set, flags);
}
static int
hwloc_aix_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
rsid_t who;
who.at_tid = thread_self();
return hwloc_aix_set_sth_cpubind(topology, R_THREAD, who, hwloc_set, flags);
}
static int
hwloc_aix_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags)
{
rsid_t who;
who.at_tid = thread_self();
return hwloc_aix_get_sth_cpubind(topology, R_THREAD, who, hwloc_set, flags);
}
static int
hwloc_aix_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags)
{
rsid_t who;
who.at_pid = pid;
return hwloc_aix_set_sth_cpubind(topology, R_PROCESS, who, hwloc_set, flags);
}
static int
hwloc_aix_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_set, int flags)
{
rsid_t who;
who.at_pid = pid;
return hwloc_aix_get_sth_cpubind(topology, R_PROCESS, who, hwloc_set, flags);
}
#ifdef HWLOC_HAVE_PTHREAD_GETTHRDS_NP
static int
hwloc_aix_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_const_bitmap_t hwloc_set, int flags)
{
struct __pthrdsinfo info;
int size;
if ((errno = pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size)))
return -1;
{
rsid_t who = { .at_tid = info.__pi_tid };
return hwloc_aix_set_sth_cpubind(topology, R_THREAD, who, hwloc_set, flags);
}
}
static int
hwloc_aix_get_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_bitmap_t hwloc_set, int flags)
{
struct __pthrdsinfo info;
int size;
if (pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size))
return -1;
{
rsid_t who;
who.at_tid = info.__pi_tid;
return hwloc_aix_get_sth_cpubind(topology, R_THREAD, who, hwloc_set, flags);
}
}
#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */
#ifdef P_DEFAULT
static int
hwloc_aix_membind_policy_from_hwloc(uint_t *aix_policy, int policy)
{
switch (policy) {
case HWLOC_MEMBIND_DEFAULT:
case HWLOC_MEMBIND_BIND:
*aix_policy = P_DEFAULT;
break;
case HWLOC_MEMBIND_FIRSTTOUCH:
*aix_policy = P_FIRST_TOUCH;
break;
case HWLOC_MEMBIND_INTERLEAVE:
*aix_policy = P_BALANCED;
break;
default:
errno = ENOSYS;
return -1;
}
return 0;
}
static int
hwloc_aix_prepare_membind(hwloc_topology_t topology, rsethandle_t *rad, hwloc_const_nodeset_t nodeset, int flags __hwloc_attribute_unused)
{
rsethandle_t rset, noderad;
int MCMlevel;
int node;
MCMlevel = rs_getinfo(NULL, R_MCMSDL, 0);
if ((topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM))
rset = rs_alloc(RS_ALL);
else
rset = rs_alloc(RS_PARTITION);
*rad = rs_alloc(RS_EMPTY);
noderad = rs_alloc(RS_EMPTY);
hwloc_bitmap_foreach_begin(node, nodeset)
rs_getrad(rset, noderad, MCMlevel, node, 0);
rs_op(RS_UNION, noderad, *rad, 0, 0);
hwloc_bitmap_foreach_end();
rs_free(rset);
rs_free(noderad);
return 0;
}
static int
hwloc_aix_set_sth_membind(hwloc_topology_t topology, rstype_t what, rsid_t who, hwloc_const_bitmap_t nodeset, hwloc_membind_policy_t policy, int flags)
{
rsethandle_t rad;
int res;
if (flags & HWLOC_MEMBIND_NOCPUBIND) {
errno = ENOSYS;
return -1;
}
switch (policy) {
case HWLOC_MEMBIND_DEFAULT:
case HWLOC_MEMBIND_BIND:
break;
default:
errno = ENOSYS;
return -1;
}
if (hwloc_aix_prepare_membind(topology, &rad, nodeset, flags))
return -1;
res = ra_attachrset(what, who, rad, 0);
rs_free(rad);
return res;
}
static int
hwloc_aix_get_sth_membind(hwloc_topology_t topology, rstype_t what, rsid_t who, hwloc_bitmap_t nodeset, hwloc_membind_policy_t *policy, int flags __hwloc_attribute_unused)
{
hwloc_bitmap_t hwloc_set;
rsethandle_t rset;
unsigned cpu, maxcpus;
int res = -1;
int depth, n, i;
depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
if (depth < 0) {
errno = EXDEV;
return -1;
}
n = hwloc_get_nbobjs_by_depth(topology, depth);
rset = rs_alloc(RS_EMPTY);
if (ra_getrset(what, who, 0, rset) == -1)
goto out;
hwloc_set = hwloc_bitmap_alloc();
maxcpus = rs_getinfo(rset, R_MAXPROCS, 0);
for (cpu = 0; cpu < maxcpus; cpu++)
if (rs_op(RS_TESTRESOURCE, rset, NULL, R_PROCS, cpu) == 1)
hwloc_bitmap_set(hwloc_set, cpu);
hwloc_bitmap_and(hwloc_set, hwloc_set, hwloc_topology_get_complete_cpuset(topology));
hwloc_bitmap_zero(nodeset);
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_set(nodeset, obj->os_index);
}
*policy = HWLOC_MEMBIND_DEFAULT;
res = 0;
out:
rs_free(rset);
return res;
}
static int
hwloc_aix_set_thisproc_membind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags)
{
rsid_t who;
who.at_pid = getpid();
return hwloc_aix_set_sth_membind(topology, R_PROCESS, who, hwloc_set, policy, flags);
}
static int
hwloc_aix_get_thisproc_membind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags)
{
rsid_t who;
who.at_pid = getpid();
return hwloc_aix_get_sth_membind(topology, R_PROCESS, who, hwloc_set, policy, flags);
}
static int
hwloc_aix_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags)
{
rsid_t who;
who.at_tid = thread_self();
return hwloc_aix_set_sth_membind(topology, R_THREAD, who, hwloc_set, policy, flags);
}
static int
hwloc_aix_get_thisthread_membind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags)
{
rsid_t who;
who.at_tid = thread_self();
return hwloc_aix_get_sth_membind(topology, R_THREAD, who, hwloc_set, policy, flags);
}
static int
hwloc_aix_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags)
{
rsid_t who;
who.at_pid = pid;
return hwloc_aix_set_sth_membind(topology, R_PROCESS, who, hwloc_set, policy, flags);
}
static int
hwloc_aix_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags)
{
rsid_t who;
who.at_pid = pid;
return hwloc_aix_get_sth_membind(topology, R_PROCESS, who, hwloc_set, policy, flags);
}
#if 0 /* def HWLOC_HAVE_PTHREAD_GETTHRDS_NP */
static int
hwloc_aix_set_thread_membind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags)
{
struct __pthrdsinfo info;
int size;
if ((errno = pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size)))
return -1;
{
rsid_t who;
who.at_tid = info.__pi_tid;
return hwloc_aix_set_sth_membind(topology, R_THREAD, who, hwloc_set, policy, flags);
}
}
static int
hwloc_aix_get_thread_membind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags)
{
struct __pthrdsinfo info;
int size;
if (pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size))
return -1;
{
rsid_t who;
who.at_tid = info.__pi_tid;
return hwloc_aix_get_sth_membind(topology, R_THREAD, who, hwloc_set, policy, flags);
}
}
#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */
#if 0
/* TODO: seems to be right, but doesn't seem to be working (EINVAL), even after
* aligning the range on 64K... */
static int
hwloc_aix_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)
{
subrange_t subrange;
rsid_t rsid = { .at_subrange = &subrange };
uint_t aix_policy;
int ret;
fprintf(stderr,"yop\n");
if ((flags & (HWLOC_MEMBIND_MIGRATE|HWLOC_MEMBIND_STRICT))
== (HWLOC_MEMBIND_MIGRATE|HWLOC_MEMBIND_STRICT)) {
errno = ENOSYS;
return -1;
}
subrange.su_offset = (uintptr_t) addr;
subrange.su_length = len;
subrange.su_rstype = R_RSET;
if (hwloc_aix_membind_policy_from_hwloc(&aix_policy, policy))
return -1;
if (hwloc_aix_prepare_membind(topology, &subrange.su_rsid.at_rset, nodeset, flags))
return -1;
subrange.su_policy = aix_policy;
ret = ra_attachrset(R_SUBRANGE, rsid, subrange.su_rsid.at_rset, 0);
rs_free(subrange.su_rsid.at_rset);
return ret;
}
#endif
static void *
hwloc_aix_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
void *ret;
rsid_t rsid;
uint_t aix_policy;
if (hwloc_aix_membind_policy_from_hwloc(&aix_policy, policy))
return hwloc_alloc_or_fail(topology, len, flags);
if (hwloc_aix_prepare_membind(topology, &rsid.at_rset, nodeset, flags))
return hwloc_alloc_or_fail(topology, len, flags);
ret = ra_mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, R_RSET, rsid, aix_policy);
rs_free(rsid.at_rset);
return ret;
}
#endif /* P_DEFAULT */
static void
look_rset(int sdl, hwloc_obj_type_t type, struct hwloc_topology *topology, int level)
{
rsethandle_t rset, rad;
int i,maxcpus,j;
int nbnodes;
struct hwloc_obj *obj;
if ((topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM))
rset = rs_alloc(RS_ALL);
else
rset = rs_alloc(RS_PARTITION);
rad = rs_alloc(RS_EMPTY);
nbnodes = rs_numrads(rset, sdl, 0);
if (nbnodes == -1) {
perror("rs_numrads");
return;
}
for (i = 0; i < nbnodes; i++) {
if (rs_getrad(rset, rad, sdl, i, 0)) {
fprintf(stderr,"rs_getrad(%d) failed: %s\n", i, strerror(errno));
continue;
}
if (!rs_getinfo(rad, R_NUMPROCS, 0))
continue;
/* It seems logical processors are numbered from 1 here, while the
* bindprocessor functions numbers them from 0... */
obj = hwloc_alloc_setup_object(type, i - (type == HWLOC_OBJ_PU));
obj->cpuset = hwloc_bitmap_alloc();
obj->os_level = sdl;
maxcpus = rs_getinfo(rad, R_MAXPROCS, 0);
for (j = 0; j < maxcpus; j++) {
if (rs_op(RS_TESTRESOURCE, rad, NULL, R_PROCS, j))
hwloc_bitmap_set(obj->cpuset, j);
}
switch(type) {
case HWLOC_OBJ_NODE:
obj->nodeset = hwloc_bitmap_alloc();
hwloc_bitmap_set(obj->nodeset, i);
obj->memory.local_memory = 0; /* TODO: odd, rs_getinfo(rad, R_MEMSIZE, 0) << 10 returns the total memory ... */
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
/* TODO: obj->memory.page_types[1].count = rs_getinfo(rset, R_LGPGFREE, 0) / hugepagesize */
break;
case HWLOC_OBJ_CACHE:
obj->attr->cache.size = _system_configuration.L2_cache_size;
obj->attr->cache.linesize = 0; /* TODO: ? */
obj->attr->cache.depth = 2;
break;
case HWLOC_OBJ_GROUP:
obj->attr->group.depth = level;
break;
case HWLOC_OBJ_CORE:
{
hwloc_obj_t obj2 = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, i);
obj2->cpuset = hwloc_bitmap_dup(obj->cpuset);
obj2->attr->cache.size = _system_configuration.dcache_size;
obj2->attr->cache.linesize = _system_configuration.dcache_line;
obj2->attr->cache.depth = 1;
hwloc_debug("Adding an L1 cache for core %d\n", i);
hwloc_insert_object_by_cpuset(topology, obj2);
break;
}
default:
break;
}
hwloc_debug_2args_bitmap("%s %d has cpuset %s\n",
hwloc_obj_type_string(type),
i, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj);
}
rs_free(rset);
rs_free(rad);
}
void
hwloc_look_aix(struct hwloc_topology *topology)
{
int i;
/* TODO: R_LGPGDEF/R_LGPGFREE for large pages */
hwloc_debug("Note: SMPSDL is at %d\n", rs_getinfo(NULL, R_SMPSDL, 0));
for (i=0; i<=rs_getinfo(NULL, R_MAXSDL, 0); i++)
{
int known = 0;
#if 0
if (i == rs_getinfo(NULL, R_SMPSDL, 0))
/* Not enabled for now because I'm not sure what it corresponds to. On
* decrypthon it contains all the cpus. Is it a "machine" or a "system"
* level ?
*/
{
hwloc_debug("looking AIX \"SMP\" sdl %d\n", i);
look_rset(i, HWLOC_OBJ_MACHINE, topology, i);
known = 1;
}
#endif
if (i == rs_getinfo(NULL, R_MCMSDL, 0))
{
hwloc_debug("looking AIX node sdl %d\n", i);
look_rset(i, HWLOC_OBJ_NODE, topology, i);
known = 1;
}
# ifdef R_L2CSDL
if (i == rs_getinfo(NULL, R_L2CSDL, 0))
{
hwloc_debug("looking AIX L2 sdl %d\n", i);
look_rset(i, HWLOC_OBJ_CACHE, topology, i);
known = 1;
}
# endif
# ifdef R_PCORESDL
if (i == rs_getinfo(NULL, R_PCORESDL, 0))
{
hwloc_debug("looking AIX core sdl %d\n", i);
look_rset(i, HWLOC_OBJ_CORE, topology, i);
known = 1;
}
# endif
if (i == rs_getinfo(NULL, R_MAXSDL, 0))
{
hwloc_debug("looking AIX max sdl %d\n", i);
look_rset(i, HWLOC_OBJ_PU, topology, i);
known = 1;
topology->support.discovery->pu = 1;
}
/* Don't know how it should be rendered, make a misc object for it. */
if (!known)
{
hwloc_debug("looking AIX unknown sdl %d\n", i);
look_rset(i, HWLOC_OBJ_GROUP, topology, i);
}
}
hwloc_add_object_info(topology->levels[0][0], "Backend", "AIX");
}
void
hwloc_set_aix_hooks(struct hwloc_topology *topology)
{
topology->set_proc_cpubind = hwloc_aix_set_proc_cpubind;
topology->get_proc_cpubind = hwloc_aix_get_proc_cpubind;
#ifdef HWLOC_HAVE_PTHREAD_GETTHRDS_NP
topology->set_thread_cpubind = hwloc_aix_set_thread_cpubind;
topology->get_thread_cpubind = hwloc_aix_get_thread_cpubind;
#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */
topology->set_thisproc_cpubind = hwloc_aix_set_thisproc_cpubind;
topology->get_thisproc_cpubind = hwloc_aix_get_thisproc_cpubind;
topology->set_thisthread_cpubind = hwloc_aix_set_thisthread_cpubind;
topology->get_thisthread_cpubind = hwloc_aix_get_thisthread_cpubind;
/* TODO: get_last_cpu_location: use mycpu() */
#ifdef P_DEFAULT
topology->set_proc_membind = hwloc_aix_set_proc_membind;
topology->get_proc_membind = hwloc_aix_get_proc_membind;
#if 0 /* def HWLOC_HAVE_PTHREAD_GETTHRDS_NP */
/* Does it really make sense to set the memory binding of another thread? */
topology->set_thread_membind = hwloc_aix_set_thread_membind;
topology->get_thread_membind = hwloc_aix_get_thread_membind;
#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */
topology->set_thisproc_membind = hwloc_aix_set_thisproc_membind;
topology->get_thisproc_membind = hwloc_aix_get_thisproc_membind;
topology->set_thisthread_membind = hwloc_aix_set_thisthread_membind;
topology->get_thisthread_membind = hwloc_aix_get_thisthread_membind;
/* topology->set_area_membind = hwloc_aix_set_area_membind; */
/* get_area_membind is not available */
topology->alloc_membind = hwloc_aix_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 /* P_DEFAULT */
}
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2010 INRIA. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux 1
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
/* Detect topology change: registering for power management changes and check
* if for example hw.activecpu changed */
/* Apparently, Darwin people do not _want_ to provide binding functions. */
#include <private/autogen/config.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdlib.h>
#include <inttypes.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
void
hwloc_look_darwin(struct hwloc_topology *topology)
{
int64_t _nprocs;
unsigned nprocs;
int64_t _npackages;
unsigned i, j, cpu;
struct hwloc_obj *obj;
size_t size;
int64_t l1cachesize;
int64_t l2cachesize;
int64_t cachelinesize;
int64_t memsize;
if (hwloc_get_sysctlbyname("hw.ncpu", &_nprocs) || _nprocs <= 0)
return;
nprocs = _nprocs;
topology->support.discovery->pu = 1;
hwloc_debug("%u procs\n", nprocs);
if (!hwloc_get_sysctlbyname("hw.packages", &_npackages) && _npackages > 0) {
unsigned npackages = _npackages;
int64_t _cores_per_package;
int64_t _logical_per_package;
unsigned logical_per_package;
hwloc_debug("%u packages\n", npackages);
if (!hwloc_get_sysctlbyname("machdep.cpu.logical_per_package", &_logical_per_package) && _logical_per_package > 0)
logical_per_package = _logical_per_package;
else
/* Assume the trivia. */
logical_per_package = nprocs / npackages;
hwloc_debug("%u threads per package\n", logical_per_package);
if (nprocs == npackages * logical_per_package)
for (i = 0; i < npackages; i++) {
obj = hwloc_alloc_setup_object(HWLOC_OBJ_SOCKET, i);
obj->cpuset = hwloc_bitmap_alloc();
for (cpu = i*logical_per_package; cpu < (i+1)*logical_per_package; cpu++)
hwloc_bitmap_set(obj->cpuset, cpu);
hwloc_debug_1arg_bitmap("package %u has cpuset %s\n",
i, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj);
}
if (!hwloc_get_sysctlbyname("machdep.cpu.cores_per_package", &_cores_per_package) && _cores_per_package > 0) {
unsigned cores_per_package = _cores_per_package;
hwloc_debug("%u cores per package\n", cores_per_package);
if (!(logical_per_package % cores_per_package))
for (i = 0; i < npackages * cores_per_package; i++) {
obj = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, i);
obj->cpuset = hwloc_bitmap_alloc();
for (cpu = i*(logical_per_package/cores_per_package);
cpu < (i+1)*(logical_per_package/cores_per_package);
cpu++)
hwloc_bitmap_set(obj->cpuset, cpu);
hwloc_debug_1arg_bitmap("core %u has cpuset %s\n",
i, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj);
}
}
}
if (hwloc_get_sysctlbyname("hw.l1dcachesize", &l1cachesize))
l1cachesize = 0;
if (hwloc_get_sysctlbyname("hw.l2cachesize", &l2cachesize))
l2cachesize = 0;
if (hwloc_get_sysctlbyname("hw.cachelinesize", &cachelinesize))
cachelinesize = 0;
if (hwloc_get_sysctlbyname("hw.memsize", &memsize))
memsize = 0;
if (!sysctlbyname("hw.cacheconfig", NULL, &size, NULL, 0)) {
unsigned n = size / sizeof(uint32_t);
uint64_t *cacheconfig = NULL;
uint64_t *cachesize = NULL;
uint32_t *cacheconfig32 = NULL;
cacheconfig = malloc(sizeof(uint64_t) * n);
if (NULL == cacheconfig) {
goto out;
}
cachesize = malloc(sizeof(uint64_t) * n);
if (NULL == cachesize) {
goto out;
}
cacheconfig32 = malloc(sizeof(uint32_t) * n);
if (NULL == cacheconfig32) {
goto out;
}
if ((!sysctlbyname("hw.cacheconfig", cacheconfig, &size, NULL, 0))) {
/* Yeech. Darwin seemingly has changed from 32bit to 64bit integers for
* cacheconfig, with apparently no way for detection. Assume the machine
* won't have more than 4 billion cpus */
if (cacheconfig[0] > 0xFFFFFFFFUL) {
memcpy(cacheconfig32, cacheconfig, size);
for (i = 0 ; i < size / sizeof(uint32_t); i++)
cacheconfig[i] = cacheconfig32[i];
}
memset(cachesize, 0, sizeof(uint64_t) * n);
size = sizeof(uint64_t) * n;
if (sysctlbyname("hw.cachesize", cachesize, &size, NULL, 0)) {
if (n > 0)
cachesize[0] = memsize;
if (n > 1)
cachesize[1] = l1cachesize;
if (n > 2)
cachesize[2] = l2cachesize;
}
hwloc_debug("%s", "caches");
for (i = 0; i < n && cacheconfig[i]; i++)
hwloc_debug(" %"PRIu64"(%"PRIu64"kB)", cacheconfig[i], cachesize[i] / 1024);
cacheconfig[i] = cacheconfig32[i];
/* Now we know how many caches there are */
n = i;
hwloc_debug("\n%u cache levels\n", n - 1);
/* For each cache level (0 is memory) */
for (i = 0; i < n; i++) {
/* cacheconfig tells us how many cpus share it, let's iterate on each cache */
for (j = 0; j < (nprocs / cacheconfig[i]); j++) {
obj = hwloc_alloc_setup_object(i?HWLOC_OBJ_CACHE:HWLOC_OBJ_NODE, j);
if (!i) {
obj->nodeset = hwloc_bitmap_alloc();
hwloc_bitmap_set(obj->nodeset, j);
}
obj->cpuset = hwloc_bitmap_alloc();
for (cpu = j*cacheconfig[i];
cpu < ((j+1)*cacheconfig[i]);
cpu++)
hwloc_bitmap_set(obj->cpuset, cpu);
if (i) {
hwloc_debug_2args_bitmap("L%ucache %u has cpuset %s\n",
i, j, obj->cpuset);
obj->attr->cache.depth = i;
obj->attr->cache.size = cachesize[i];
obj->attr->cache.linesize = cachelinesize;
} else {
hwloc_debug_1arg_bitmap("node %u has cpuset %s\n",
j, obj->cpuset);
obj->memory.local_memory = cachesize[i];
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);
}
}
}
out:
if (NULL != cacheconfig) {
free(cacheconfig);
}
if (NULL != cachesize) {
free(cachesize);
}
if (NULL != cacheconfig32) {
free(cacheconfig32);
}
}
/* add PU objects */
hwloc_setup_pu_level(topology, nprocs);
hwloc_add_object_info(topology->levels[0][0], "Backend", "Darwin");
}
void
hwloc_set_darwin_hooks(struct hwloc_topology *topology __hwloc_attribute_unused)
{
}
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2010 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 <private/autogen/config.h>
#include <sys/types.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/param.h>
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
#ifdef HAVE_SYS_CPUSET_H
#include <sys/cpuset.h>
#endif
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#ifdef HAVE_SYS_CPUSET_H
static void
hwloc_freebsd_bsd2hwloc(hwloc_bitmap_t hwloc_cpuset, const cpuset_t *cpuset)
{
unsigned cpu;
hwloc_bitmap_zero(hwloc_cpuset);
for (cpu = 0; cpu < CPU_SETSIZE; cpu++)
if (CPU_ISSET(cpu, cpuset))
hwloc_bitmap_set(hwloc_cpuset, cpu);
}
static void
hwloc_freebsd_hwloc2bsd(hwloc_const_bitmap_t hwloc_cpuset, cpuset_t *cpuset)
{
unsigned cpu;
CPU_ZERO(cpuset);
for (cpu = 0; cpu < CPU_SETSIZE; cpu++)
if (hwloc_bitmap_isset(hwloc_cpuset, cpu))
CPU_SET(cpu, cpuset);
}
static int
hwloc_freebsd_set_sth_affinity(hwloc_topology_t topology __hwloc_attribute_unused, cpulevel_t level, cpuwhich_t which, id_t id, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
{
cpuset_t cpuset;
hwloc_freebsd_hwloc2bsd(hwloc_cpuset, &cpuset);
if (cpuset_setaffinity(level, which, id, sizeof(cpuset), &cpuset))
return -1;
return 0;
}
static int
hwloc_freebsd_get_sth_affinity(hwloc_topology_t topology __hwloc_attribute_unused, cpulevel_t level, cpuwhich_t which, id_t id, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
{
cpuset_t cpuset;
if (cpuset_getaffinity(level, which, id, sizeof(cpuset), &cpuset))
return -1;
hwloc_freebsd_bsd2hwloc(hwloc_cpuset, &cpuset);
return 0;
}
static int
hwloc_freebsd_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags)
{
return hwloc_freebsd_set_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, hwloc_cpuset, flags);
}
static int
hwloc_freebsd_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags)
{
return hwloc_freebsd_get_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, hwloc_cpuset, flags);
}
static int
hwloc_freebsd_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags)
{
return hwloc_freebsd_set_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, hwloc_cpuset, flags);
}
static int
hwloc_freebsd_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags)
{
return hwloc_freebsd_get_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, hwloc_cpuset, flags);
}
static int
hwloc_freebsd_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_cpuset, int flags)
{
return hwloc_freebsd_set_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, hwloc_cpuset, flags);
}
static int
hwloc_freebsd_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_cpuset, int flags)
{
return hwloc_freebsd_get_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, hwloc_cpuset, flags);
}
#ifdef hwloc_thread_t
#if HAVE_DECL_PTHREAD_SETAFFINITY_NP
#pragma weak pthread_setaffinity_np
static int
hwloc_freebsd_set_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
{
int err;
cpuset_t cpuset;
if (!pthread_setaffinity_np) {
errno = ENOSYS;
return -1;
}
hwloc_freebsd_hwloc2bsd(hwloc_cpuset, &cpuset);
err = pthread_setaffinity_np(tid, sizeof(cpuset), &cpuset);
if (err) {
errno = err;
return -1;
}
return 0;
}
#endif
#if HAVE_DECL_PTHREAD_GETAFFINITY_NP
#pragma weak pthread_getaffinity_np
static int
hwloc_freebsd_get_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
{
int err;
cpuset_t cpuset;
if (!pthread_getaffinity_np) {
errno = ENOSYS;
return -1;
}
err = pthread_getaffinity_np(tid, sizeof(cpuset), &cpuset);
if (err) {
errno = err;
return -1;
}
hwloc_freebsd_bsd2hwloc(hwloc_cpuset, &cpuset);
return 0;
}
#endif
#endif
#endif
void
hwloc_look_freebsd(struct hwloc_topology *topology)
{
unsigned nbprocs = hwloc_fallback_nbprocessors(topology);
#ifdef HAVE__SC_LARGE_PAGESIZE
topology->levels[0][0]->attr->machine.huge_page_size_kB = sysconf(_SC_LARGE_PAGESIZE);
#endif
hwloc_set_freebsd_hooks(topology);
hwloc_look_x86(topology, nbprocs);
hwloc_setup_pu_level(topology, nbprocs);
hwloc_add_object_info(topology->levels[0][0], "Backend", "FreeBSD");
}
void
hwloc_set_freebsd_hooks(struct hwloc_topology *topology)
{
#ifdef HAVE_SYS_CPUSET_H
topology->set_thisproc_cpubind = hwloc_freebsd_set_thisproc_cpubind;
topology->get_thisproc_cpubind = hwloc_freebsd_get_thisproc_cpubind;
topology->set_thisthread_cpubind = hwloc_freebsd_set_thisthread_cpubind;
topology->get_thisthread_cpubind = hwloc_freebsd_get_thisthread_cpubind;
topology->set_proc_cpubind = hwloc_freebsd_set_proc_cpubind;
topology->get_proc_cpubind = hwloc_freebsd_get_proc_cpubind;
#ifdef hwloc_thread_t
#if HAVE_DECL_PTHREAD_SETAFFINITY_NP
topology->set_thread_cpubind = hwloc_freebsd_set_thread_cpubind;
#endif
#if HAVE_DECL_PTHREAD_GETAFFINITY_NP
topology->get_thread_cpubind = hwloc_freebsd_get_thread_cpubind;
#endif
#endif
#endif
/* TODO: get_last_cpu_location: find out ki_lastcpu */
}
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2010 INRIA. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux 1
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
/* TODO: psets? (Only for root)
* since 11i 1.6:
_SC_PSET_SUPPORT
pset_create/destroy/assign/setattr
pset_ctl/getattr
pset_bind()
pthread_pset_bind_np()
*/
#include <private/autogen/config.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#include <sys/mpctl.h>
#include <sys/mman.h>
#include <pthread.h>
static ldom_t
hwloc_hpux_find_ldom(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set)
{
int has_numa = sysconf(_SC_CCNUMA_SUPPORT) == 1;
hwloc_obj_t obj;
if (!has_numa)
return -1;
obj = hwloc_get_first_largest_obj_inside_cpuset(topology, hwloc_set);
if (!hwloc_bitmap_isequal(obj->cpuset, hwloc_set) || obj->type != HWLOC_OBJ_NODE) {
/* Does not correspond to exactly one node */
return -1;
}
return obj->os_index;
}
static spu_t
hwloc_hpux_find_spu(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t hwloc_set)
{
spu_t cpu;
cpu = hwloc_bitmap_first(hwloc_set);
if (cpu != -1 && hwloc_bitmap_weight(hwloc_set) == 1)
return cpu;
return -1;
}
/* Note: get_cpubind not available on HP-UX */
static int
hwloc_hpux_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags)
{
ldom_t ldom;
spu_t cpu;
/* Drop previous binding */
mpctl(MPC_SETLDOM, MPC_LDOMFLOAT, pid);
mpctl(MPC_SETPROCESS, MPC_SPUFLOAT, pid);
if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology)))
return 0;
ldom = hwloc_hpux_find_ldom(topology, hwloc_set);
if (ldom != -1)
return mpctl(MPC_SETLDOM, ldom, pid);
cpu = hwloc_hpux_find_spu(topology, hwloc_set);
if (cpu != -1)
return mpctl(flags & HWLOC_CPUBIND_STRICT ? MPC_SETPROCESS_FORCE : MPC_SETPROCESS, cpu, pid);
errno = EXDEV;
return -1;
}
static int
hwloc_hpux_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
return hwloc_hpux_set_proc_cpubind(topology, MPC_SELFPID, hwloc_set, flags);
}
#ifdef hwloc_thread_t
static int
hwloc_hpux_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_const_bitmap_t hwloc_set, int flags)
{
ldom_t ldom, ldom2;
spu_t cpu, cpu2;
/* Drop previous binding */
pthread_ldom_bind_np(&ldom2, PTHREAD_LDOMFLOAT_NP, pthread);
pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP, &cpu2, PTHREAD_SPUFLOAT_NP, pthread);
if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology)))
return 0;
ldom = hwloc_hpux_find_ldom(topology, hwloc_set);
if (ldom != -1)
return pthread_ldom_bind_np(&ldom2, ldom, pthread);
cpu = hwloc_hpux_find_spu(topology, hwloc_set);
if (cpu != -1)
return pthread_processor_bind_np(flags & HWLOC_CPUBIND_STRICT ? PTHREAD_BIND_FORCED_NP : PTHREAD_BIND_ADVISORY_NP, &cpu2, cpu, pthread);
errno = EXDEV;
return -1;
}
static int
hwloc_hpux_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
return hwloc_hpux_set_thread_cpubind(topology, PTHREAD_SELFTID_NP, hwloc_set, flags);
}
#endif
/* According to HP docs, HP-UX up to 11iv2 don't support migration */
#ifdef MAP_MEM_FIRST_TOUCH
static void*
hwloc_hpux_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
int mmap_flags;
/* Can not give a set of nodes. */
if (!hwloc_bitmap_isequal(nodeset, hwloc_topology_get_complete_nodeset(topology))) {
errno = EXDEV;
return hwloc_alloc_or_fail(topology, len, flags);
}
switch (policy) {
case HWLOC_MEMBIND_DEFAULT:
case HWLOC_MEMBIND_BIND:
mmap_flags = 0;
break;
case HWLOC_MEMBIND_FIRSTTOUCH:
mmap_flags = MAP_MEM_FIRST_TOUCH;
break;
case HWLOC_MEMBIND_INTERLEAVE:
mmap_flags = MAP_MEM_INTERLEAVED;
break;
default:
errno = ENOSYS;
return NULL;
}
return mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | mmap_flags, -1, 0);
}
#endif /* MAP_MEM_FIRST_TOUCH */
void
hwloc_look_hpux(struct hwloc_topology *topology)
{
int has_numa = sysconf(_SC_CCNUMA_SUPPORT) == 1;
hwloc_obj_t *nodes = NULL, obj;
spu_t currentcpu;
ldom_t currentnode;
int i, nbnodes = 0;
#ifdef HAVE__SC_LARGE_PAGESIZE
topology->levels[0][0]->attr->machine.huge_page_size_kB = sysconf(_SC_LARGE_PAGESIZE);
#endif
if (has_numa) {
nbnodes = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ?
MPC_GETNUMLDOMS_SYS : MPC_GETNUMLDOMS, 0, 0);
hwloc_debug("%d nodes\n", nbnodes);
nodes = malloc(nbnodes * sizeof(*nodes));
i = 0;
currentnode = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ?
MPC_GETFIRSTLDOM_SYS : MPC_GETFIRSTLDOM, 0, 0);
while (currentnode != -1 && i < nbnodes) {
hwloc_debug("node %d is %d\n", i, currentnode);
nodes[i] = obj = hwloc_alloc_setup_object(HWLOC_OBJ_NODE, currentnode);
obj->cpuset = hwloc_bitmap_alloc();
obj->nodeset = hwloc_bitmap_alloc();
hwloc_bitmap_set(obj->nodeset, currentnode);
/* TODO: obj->attr->node.memory_kB */
/* TODO: obj->attr->node.huge_page_free */
currentnode = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ?
MPC_GETNEXTLDOM_SYS : MPC_GETNEXTLDOM, currentnode, 0);
i++;
}
}
i = 0;
currentcpu = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ?
MPC_GETFIRSTSPU_SYS : MPC_GETFIRSTSPU, 0,0);
while (currentcpu != -1) {
obj = hwloc_alloc_setup_object(HWLOC_OBJ_PU, currentcpu);
obj->cpuset = hwloc_bitmap_alloc();
hwloc_bitmap_set(obj->cpuset, currentcpu);
hwloc_debug("cpu %d\n", currentcpu);
if (nodes) {
/* Add this cpu to its node */
currentnode = mpctl(MPC_SPUTOLDOM, currentcpu, 0);
if ((ldom_t) nodes[i]->os_index != currentnode)
for (i = 0; i < nbnodes; i++)
if ((ldom_t) nodes[i]->os_index == currentnode)
break;
if (i < nbnodes) {
hwloc_bitmap_set(nodes[i]->cpuset, currentcpu);
hwloc_debug("is in node %d\n", i);
} else {
hwloc_debug("%s", "is in no node?!\n");
}
}
/* Add cpu */
hwloc_insert_object_by_cpuset(topology, obj);
currentcpu = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ?
MPC_GETNEXTSPU_SYS : MPC_GETNEXTSPU, currentcpu, 0);
}
if (nodes) {
/* Add nodes */
for (i = 0 ; i < nbnodes ; i++)
hwloc_insert_object_by_cpuset(topology, nodes[i]);
free(nodes);
}
topology->support.discovery->pu = 1;
hwloc_add_object_info(topology->levels[0][0], "Backend", "HP-UX");
}
void
hwloc_set_hpux_hooks(struct hwloc_topology *topology)
{
topology->set_proc_cpubind = hwloc_hpux_set_proc_cpubind;
topology->set_thisproc_cpubind = hwloc_hpux_set_thisproc_cpubind;
#ifdef hwloc_thread_t
topology->set_thread_cpubind = hwloc_hpux_set_thread_cpubind;
topology->set_thisthread_cpubind = hwloc_hpux_set_thisthread_cpubind;
#endif
#ifdef MAP_MEM_FIRST_TOUCH
topology->alloc_membind = hwloc_hpux_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 /* MAP_MEM_FIRST_TOUCH */
}
/*
* 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 <private/autogen/config.h>
#include <hwloc.h>
#include <hwloc/linux.h>
#include <private/misc.h>
#include <private/private.h>
#include <private/misc.h>
#include <private/debug.h>
#include <limits.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sched.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#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 <numaif.h>
#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 <linux/unistd.h>
# 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 <arpa/inet.h>
#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; cpu<CPU_SETSIZE; cpu++)
if (CPU_ISSET(cpu, &linux_set))
hwloc_bitmap_set(hwloc_set, cpu);
#elif defined(HWLOC_HAVE__SYSCALL3)
unsigned long mask;
#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY
err = sched_getaffinity(tid, (void*) &mask);
#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */
err = sched_getaffinity(tid, sizeof(mask), (void*) &mask);
#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */
if (err < 0)
return -1;
hwloc_bitmap_from_ulong(hwloc_set, mask);
#else /* !_SYSCALL3 */
errno = ENOSYS;
return -1;
#endif /* !_SYSCALL3 */
return 0;
}
/* Get the array of tids of a process from the task directory in /proc */
static int
hwloc_linux_get_proc_tids(DIR *taskdir, unsigned *nr_tidsp, pid_t ** tidsp)
{
struct dirent *dirent;
unsigned nr_tids = 0;
unsigned max_tids = 32;
pid_t *tids;
struct stat sb;
/* take the number of links as a good estimate for the number of tids */
if (fstat(dirfd(taskdir), &sb) == 0)
max_tids = sb.st_nlink;
tids = malloc(max_tids*sizeof(pid_t));
if (!tids) {
errno = ENOMEM;
return -1;
}
rewinddir(taskdir);
while ((dirent = readdir(taskdir)) != NULL) {
if (nr_tids == max_tids) {
pid_t *newtids;
max_tids += 8;
newtids = realloc(tids, max_tids*sizeof(pid_t));
if (!newtids) {
free(tids);
errno = ENOMEM;
return -1;
}
tids = newtids;
}
if (!strcmp(dirent->d_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; i<nr; i++) {
err = cb(topology, tids[i], data, i, flags);
if (err < 0)
goto out_with_tids;
}
/* re-read the list of thread and retry if it changed in the meantime */
err = hwloc_linux_get_proc_tids(taskdir, &newnr, &newtids);
if (err < 0)
goto out_with_tids;
if (newnr != nr || memcmp(newtids, tids, nr*sizeof(pid_t))) {
free(tids);
tids = newtids;
nr = newnr;
goto retry;
}
err = 0;
free(newtids);
out_with_tids:
free(tids);
out_with_dir:
closedir(taskdir);
out:
return err;
}
static int
hwloc_linux_set_pid_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags)
{
return hwloc_linux_foreach_proc_tid(topology, pid,
hwloc_linux_foreach_proc_tid_set_cpubind_cb,
(void*) hwloc_set, flags);
}
static int
hwloc_linux_get_pid_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_bitmap_t hwloc_set, int flags)
{
hwloc_bitmap_t tidset = hwloc_bitmap_alloc();
hwloc_bitmap_t cpusets[2];
int ret;
cpusets[0] = hwloc_set;
cpusets[1] = tidset;
ret = hwloc_linux_foreach_proc_tid(topology, pid,
hwloc_linux_foreach_proc_tid_get_cpubind_cb,
(void*) cpusets, flags);
hwloc_bitmap_free(tidset);
return ret;
}
static int
hwloc_linux_set_proc_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags)
{
if (pid == 0)
pid = topology->pid;
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; cpu<CPU_SETSIZE; cpu++)
if (CPU_ISSET(cpu, &linux_set))
hwloc_bitmap_set(hwloc_set, cpu);
}
#else /* CPU_SET */
/* Use a separate block so that we can define specific variable
types here */
{
unsigned long mask;
#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY
err = pthread_getaffinity_np(tid, (void*) &mask);
#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */
err = pthread_getaffinity_np(tid, sizeof(mask), (void*) &mask);
#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */
if (err) {
errno = err;
return -1;
}
hwloc_bitmap_from_ulong(hwloc_set, mask);
}
#endif /* CPU_SET */
return 0;
}
#endif /* HAVE_DECL_PTHREAD_GETAFFINITY_NP */
static int
hwloc_linux_get_tid_last_cpu_location(hwloc_topology_t topology __hwloc_attribute_unused, pid_t tid, hwloc_bitmap_t set)
{
/* read /proc/pid/stat.
* its second field contains the command name between parentheses,
* and the command itself may contain parentheses,
* so read the whole line and find the last closing parenthesis to find the third field.
*/
char buf[1024] = "";
char name[64];
char *tmp;
FILE *file;
int i;
if (!tid) {
#ifdef SYS_gettid
tid = syscall(SYS_gettid);
#else
errno = ENOSYS;
return -1;
#endif
}
snprintf(name, sizeof(name), "/proc/%lu/stat", (unsigned long) tid);
file = fopen(name, "r");
if (!file) {
errno = ENOSYS;
return -1;
}
tmp = fgets(buf, sizeof(buf), file);
fclose(file);
if (!tmp) {
errno = ENOSYS;
return -1;
}
tmp = strrchr(buf, ')');
if (!tmp) {
errno = ENOSYS;
return -1;
}
/* skip ') ' to find the actual third argument */
tmp += 2;
/* skip 35 fields */
for(i=0; i<36; i++) {
tmp = strchr(tmp, ' ');
if (!tmp) {
errno = ENOSYS;
return -1;
}
/* skip the ' ' itself */
tmp++;
}
/* read the last cpu in the 38th field now */
if (sscanf(tmp, "%d ", &i) != 1) {
errno = ENOSYS;
return -1;
}
hwloc_bitmap_only(set, i);
return 0;
}
static int
hwloc_linux_foreach_proc_tid_get_last_cpu_location_cb(hwloc_topology_t topology, pid_t tid, void *data, int idx, int flags __hwloc_attribute_unused)
{
hwloc_bitmap_t *cpusets = data;
hwloc_bitmap_t cpuset = cpusets[0];
hwloc_bitmap_t tidset = cpusets[1];
if (hwloc_linux_get_tid_last_cpu_location(topology, tid, tidset))
return -1;
/* reset the cpuset on first iteration */
if (!idx)
hwloc_bitmap_zero(cpuset);
hwloc_bitmap_or(cpuset, cpuset, tidset);
return 0;
}
static int
hwloc_linux_get_pid_last_cpu_location(hwloc_topology_t topology, pid_t pid, hwloc_bitmap_t hwloc_set, int flags)
{
hwloc_bitmap_t tidset = hwloc_bitmap_alloc();
hwloc_bitmap_t cpusets[2];
int ret;
cpusets[0] = hwloc_set;
cpusets[1] = tidset;
ret = hwloc_linux_foreach_proc_tid(topology, pid,
hwloc_linux_foreach_proc_tid_get_last_cpu_location_cb,
(void*) cpusets, flags);
hwloc_bitmap_free(tidset);
return ret;
}
static int
hwloc_linux_get_proc_last_cpu_location(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_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; i<max_os_index/HWLOC_BITS_PER_LONG; i++)
linuxmask[i] = hwloc_bitmap_to_ith_ulong(nodeset, i);
if (linux_nodeset)
hwloc_bitmap_free(linux_nodeset);
*max_os_index_p = max_os_index;
*linuxmaskp = linuxmask;
return 0;
}
static void
hwloc_linux_membind_mask_to_nodeset(hwloc_topology_t topology __hwloc_attribute_unused,
hwloc_nodeset_t nodeset,
unsigned max_os_index, const unsigned long *linuxmask)
{
unsigned i;
#ifdef HWLOC_DEBUG
/* max_os_index comes from hwloc_linux_find_kernel_max_numnodes() so it's a multiple of HWLOC_BITS_PER_LONG */
assert(!(max_os_index%HWLOC_BITS_PER_LONG));
#endif
hwloc_bitmap_zero(nodeset);
for(i=0; i<max_os_index/HWLOC_BITS_PER_LONG; i++)
hwloc_bitmap_set_ith_ulong(nodeset, i, linuxmask[i]);
}
#endif /* HWLOC_HAVE_SET_MEMPOLICY || HWLOC_HAVE_MBIND */
#ifdef HWLOC_HAVE_MBIND
static int
hwloc_linux_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)
{
unsigned max_os_index; /* highest os_index + 1 */
unsigned long *linuxmask;
size_t remainder;
int linuxpolicy;
unsigned linuxflags = 0;
int err;
remainder = (uintptr_t) addr & (sysconf(_SC_PAGESIZE)-1);
addr = (char*) addr - remainder;
len += remainder;
err = hwloc_linux_membind_policy_from_hwloc(&linuxpolicy, policy, flags);
if (err < 0)
return err;
if (linuxpolicy == MPOL_DEFAULT)
/* Some Linux kernels don't like being passed a set */
return mbind((void *) addr, len, linuxpolicy, NULL, 0, 0);
err = hwloc_linux_membind_mask_from_nodeset(topology, nodeset, &max_os_index, &linuxmask);
if (err < 0)
goto out;
if (flags & HWLOC_MEMBIND_MIGRATE) {
#ifdef MPOL_MF_MOVE
linuxflags = MPOL_MF_MOVE;
if (flags & HWLOC_MEMBIND_STRICT)
linuxflags |= MPOL_MF_STRICT;
#else
if (flags & HWLOC_MEMBIND_STRICT) {
errno = ENOSYS;
goto out_with_mask;
}
#endif
}
err = mbind((void *) addr, len, linuxpolicy, linuxmask, max_os_index+1, linuxflags);
if (err < 0)
goto out_with_mask;
free(linuxmask);
return 0;
out_with_mask:
free(linuxmask);
out:
return -1;
}
static void *
hwloc_linux_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
void *buffer;
int err;
buffer = hwloc_alloc_mmap(topology, len);
if (buffer == MAP_FAILED)
return NULL;
err = hwloc_linux_set_area_membind(topology, buffer, len, nodeset, policy, flags);
if (err < 0 && policy & HWLOC_MEMBIND_STRICT) {
munmap(buffer, len);
return NULL;
}
return buffer;
}
#endif /* HWLOC_HAVE_MBIND */
#ifdef HWLOC_HAVE_SET_MEMPOLICY
static int
hwloc_linux_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
unsigned max_os_index; /* highest os_index + 1 */
unsigned long *linuxmask;
int linuxpolicy;
int err;
err = hwloc_linux_membind_policy_from_hwloc(&linuxpolicy, policy, flags);
if (err < 0)
return err;
if (linuxpolicy == MPOL_DEFAULT)
/* Some Linux kernels don't like being passed a set */
return set_mempolicy(linuxpolicy, NULL, 0);
err = hwloc_linux_membind_mask_from_nodeset(topology, nodeset, &max_os_index, &linuxmask);
if (err < 0)
goto out;
if (flags & HWLOC_MEMBIND_MIGRATE) {
#ifdef HWLOC_HAVE_MIGRATE_PAGES
unsigned long *fullmask = malloc(max_os_index/HWLOC_BITS_PER_LONG * sizeof(long));
if (fullmask) {
memset(fullmask, 0xf, max_os_index/HWLOC_BITS_PER_LONG * sizeof(long));
err = migrate_pages(0, max_os_index+1, fullmask, linuxmask);
free(fullmask);
} else
err = -1;
if (err < 0 && (flags & HWLOC_MEMBIND_STRICT))
goto out_with_mask;
#else
errno = ENOSYS;
goto out_with_mask;
#endif
}
err = set_mempolicy(linuxpolicy, linuxmask, max_os_index+1);
if (err < 0)
goto out_with_mask;
free(linuxmask);
return 0;
out_with_mask:
free(linuxmask);
out:
return -1;
}
/*
* On some kernels, get_mempolicy requires the output size to be larger
* than the kernel MAX_NUMNODES (defined by CONFIG_NODES_SHIFT).
* Try get_mempolicy on ourself until we find a max_os_index value that
* makes the kernel happy.
*/
static int
hwloc_linux_find_kernel_max_numnodes(hwloc_topology_t topology __hwloc_attribute_unused)
{
static int max_numnodes = -1;
int linuxpolicy;
if (max_numnodes != -1)
/* already computed */
return max_numnodes;
/* start with a single ulong, it's the minimal and it's enough for most machines */
max_numnodes = HWLOC_BITS_PER_LONG;
while (1) {
unsigned long *mask = malloc(max_numnodes / HWLOC_BITS_PER_LONG * sizeof(long));
int err = get_mempolicy(&linuxpolicy, mask, max_numnodes, 0, 0);
free(mask);
if (!err || errno != EINVAL)
/* found it */
return max_numnodes;
max_numnodes *= 2;
}
}
static int
hwloc_linux_get_thisthread_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags __hwloc_attribute_unused)
{
unsigned max_os_index;
unsigned long *linuxmask;
int linuxpolicy;
int err;
max_os_index = hwloc_linux_find_kernel_max_numnodes(topology);
linuxmask = malloc(max_os_index/HWLOC_BITS_PER_LONG * sizeof(long));
if (!linuxmask) {
errno = ENOMEM;
goto out;
}
err = get_mempolicy(&linuxpolicy, linuxmask, max_os_index, 0, 0);
if (err < 0)
goto out_with_mask;
if (linuxpolicy == MPOL_DEFAULT) {
hwloc_bitmap_copy(nodeset, hwloc_topology_get_topology_nodeset(topology));
} else {
hwloc_linux_membind_mask_to_nodeset(topology, nodeset, max_os_index, linuxmask);
}
switch (linuxpolicy) {
case MPOL_DEFAULT:
*policy = HWLOC_MEMBIND_FIRSTTOUCH;
break;
case MPOL_PREFERRED:
case MPOL_BIND:
*policy = HWLOC_MEMBIND_BIND;
break;
case MPOL_INTERLEAVE:
*policy = HWLOC_MEMBIND_INTERLEAVE;
break;
default:
errno = EINVAL;
goto out_with_mask;
}
free(linuxmask);
return 0;
out_with_mask:
free(linuxmask);
out:
return -1;
}
#endif /* HWLOC_HAVE_SET_MEMPOLICY */
int
hwloc_backend_sysfs_init(struct hwloc_topology *topology, const char *fsroot_path __hwloc_attribute_unused)
{
#ifdef HAVE_OPENAT
int root;
assert(topology->backend_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<nr_maps; i++)
hwloc_bitmap_set_ith_ulong(set, i, maps[i]);
#else
for(i=0; i<(nr_maps+1)/2; i++) {
unsigned long mask;
mask = maps[2*i];
if (2*i+1<nr_maps)
mask |= maps[2*i+1] << KERNEL_CPU_MASK_BITS;
hwloc_bitmap_set_ith_ulong(set, i, mask);
}
#endif
free(maps);
return 0;
}
static hwloc_bitmap_t
hwloc_parse_cpumap(const char *mappath, int fsroot_fd)
{
hwloc_bitmap_t set;
FILE * file;
file = hwloc_fopen(mappath, "r", fsroot_fd);
if (!file)
return NULL;
set = hwloc_bitmap_alloc();
hwloc_linux_parse_cpumap_file(file, set);
fclose(file);
return set;
}
static char *
hwloc_strdup_mntpath(const char *escapedpath, size_t length)
{
char *path = malloc(length+1);
const char *src = escapedpath, *tmp = src;
char *dst = path;
while ((tmp = strchr(src, '\\')) != NULL) {
strncpy(dst, src, tmp-src);
dst += tmp-src;
if (!strncmp(tmp+1, "040", 3))
*dst = ' ';
else if (!strncmp(tmp+1, "011", 3))
*dst = ' ';
else if (!strncmp(tmp+1, "012", 3))
*dst = '\n';
else
*dst = '\\';
dst++;
src = tmp+4;
}
strcpy(dst, src);
return path;
}
static void
hwloc_find_linux_cpuset_mntpnt(char **cgroup_mntpnt, char **cpuset_mntpnt, int fsroot_fd)
{
#define PROC_MOUNT_LINE_LEN 512
char line[PROC_MOUNT_LINE_LEN];
FILE *fd;
*cgroup_mntpnt = NULL;
*cpuset_mntpnt = NULL;
/* ideally we should use setmntent, getmntent, hasmntopt and endmntent,
* but they do not support fsroot_fd.
*/
fd = hwloc_fopen("/proc/mounts", "r", fsroot_fd);
if (!fd)
return;
while (fgets(line, sizeof(line), fd)) {
char *path;
char *type;
char *tmp;
/* remove the ending " 0 0\n" that the kernel always adds */
tmp = line + strlen(line) - 5;
if (tmp < line || strcmp(tmp, " 0 0\n"))
fprintf(stderr, "Unexpected end of /proc/mounts line `%s'\n", line);
else
*tmp = '\0';
/* path is after first field and a space */
tmp = strchr(line, ' ');
if (!tmp)
continue;
path = tmp+1;
/* type is after path, which may not contain spaces since the kernel escaped them to \040
* (see the manpage of getmntent) */
tmp = strchr(path, ' ');
if (!tmp)
continue;
type = tmp+1;
/* mark the end of path to ease upcoming strdup */
*tmp = '\0';
if (!strncmp(type, "cpuset ", 7)) {
/* found a cpuset mntpnt */
hwloc_debug("Found cpuset mount point on %s\n", path);
*cpuset_mntpnt = hwloc_strdup_mntpath(path, type-path);
break;
} else if (!strncmp(type, "cgroup ", 7)) {
/* found a cgroup mntpnt */
char *opt, *opts;
int cpuset_opt = 0;
int noprefix_opt = 0;
/* find options */
tmp = strchr(type, ' ');
if (!tmp)
continue;
opts = tmp+1;
/* look at options */
while ((opt = strsep(&opts, ",")) != NULL) {
if (!strcmp(opt, "cpuset"))
cpuset_opt = 1;
else if (!strcmp(opt, "noprefix"))
noprefix_opt = 1;
}
if (!cpuset_opt)
continue;
if (noprefix_opt) {
hwloc_debug("Found cgroup emulating a cpuset mount point on %s\n", path);
*cpuset_mntpnt = hwloc_strdup_mntpath(path, type-path);
} else {
hwloc_debug("Found cgroup/cpuset mount point on %s\n", path);
*cgroup_mntpnt = hwloc_strdup_mntpath(path, type-path);
}
break;
}
}
fclose(fd);
}
/*
* Linux cpusets may be managed directly or through cgroup.
* If cgroup is used, tasks get a /proc/pid/cgroup which may contain a
* single line %d:cpuset:<name>. If cpuset are used they get /proc/pid/cpuset
* containing <name>.
*/
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<name>/cpuset.{cpus,mems} or cpuset<name>/{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", &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; i<numsockets; i++)
if (physid == osphysids[i])
break;
proc_physids[processor]=i;
hwloc_debug("%lu on socket %u (%lx)\n", processor, i, physid);
if (i==numsockets)
osphysids[(numsockets)++] = physid;
getprocnb_end() else
getprocnb_begin(COREID,coreid);
for (i=0; i<numcores; i++)
if (coreid == oscoreids[i] && proc_osphysids[processor] == core_osphysids[i])
break;
proc_coreids[processor]=i;
if (i==numcores)
{
core_osphysids[numcores] = proc_osphysids[processor];
oscoreids[numcores] = coreid;
(numcores)++;
}
getprocnb_end()
if (str[strlen(str)-1]!='\n')
{
/* ignore end of line */
if (fscanf(fd,"%*[^\n]") == EOF)
break;
getc(fd);
}
}
fclose(fd);
free(str);
if (processor == (unsigned long) -1) {
hwloc_bitmap_free(cpuset);
return -1;
}
topology->support.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; i<topology->levels[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
}
/*
* 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 <private/autogen/config.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#include <numa.h>
#include <radset.h>
#include <cpuset.h>
#include <sys/mman.h>
/*
* TODO
*
* nsg_init(), nsg_attach_pid(), RAD_MIGRATE/RAD_WAIT
* assign_pid_to_pset()
*
* pthread_use_only_cpu too?
*/
static int
prepare_radset(hwloc_topology_t topology, radset_t *radset, hwloc_const_bitmap_t hwloc_set)
{
unsigned cpu;
cpuset_t target_cpuset;
cpuset_t cpuset, xor_cpuset;
radid_t radid;
int ret = 0;
int ret_errno = 0;
cpusetcreate(&target_cpuset);
cpuemptyset(target_cpuset);
hwloc_bitmap_foreach_begin(cpu, hwloc_set)
cpuaddset(target_cpuset, cpu);
hwloc_bitmap_foreach_end();
cpusetcreate(&cpuset);
cpusetcreate(&xor_cpuset);
for (radid = 0; radid < topology->backend_params.osf.nbnodes; radid++) {
cpuemptyset(cpuset);
if (rad_get_cpus(radid, cpuset)==-1) {
fprintf(stderr,"rad_get_cpus(%d) failed: %s\n",radid,strerror(errno));
continue;
}
cpuxorset(target_cpuset, cpuset, xor_cpuset);
if (cpucountset(xor_cpuset) == 0) {
/* Found it */
radsetcreate(radset);
rademptyset(*radset);
radaddset(*radset, radid);
ret = 1;
goto out;
}
}
/* radset containing exactly this set of CPUs not found */
ret_errno = EXDEV;
out:
cpusetdestroy(&target_cpuset);
cpusetdestroy(&cpuset);
cpusetdestroy(&xor_cpuset);
errno = ret_errno;
return ret;
}
/* Note: get_cpubind not available on OSF */
static int
hwloc_osf_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t thread, hwloc_const_bitmap_t hwloc_set, int flags)
{
radset_t radset;
if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) {
if ((errno = pthread_rad_detach(thread)))
return -1;
return 0;
}
/* Apparently OSF migrates pages */
if (flags & HWLOC_CPUBIND_NOMEMBIND) {
errno = ENOSYS;
return -1;
}
if (!prepare_radset(topology, &radset, hwloc_set))
return -1;
if (flags & HWLOC_CPUBIND_STRICT) {
if ((errno = pthread_rad_bind(thread, radset, RAD_INSIST | RAD_WAIT)))
return -1;
} else {
if ((errno = pthread_rad_attach(thread, radset, RAD_WAIT)))
return -1;
}
radsetdestroy(&radset);
return 0;
}
static int
hwloc_osf_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags)
{
radset_t radset;
if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) {
if (rad_detach_pid(pid))
return -1;
return 0;
}
/* Apparently OSF migrates pages */
if (flags & HWLOC_CPUBIND_NOMEMBIND) {
errno = ENOSYS;
return -1;
}
if (!prepare_radset(topology, &radset, hwloc_set))
return -1;
if (flags & HWLOC_CPUBIND_STRICT) {
if (rad_bind_pid(pid, radset, RAD_INSIST | RAD_WAIT))
return -1;
} else {
if (rad_attach_pid(pid, radset, RAD_WAIT))
return -1;
}
radsetdestroy(&radset);
return 0;
}
static int
hwloc_osf_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
return hwloc_osf_set_thread_cpubind(topology, pthread_self(), hwloc_set, flags);
}
static int
hwloc_osf_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
return hwloc_osf_set_proc_cpubind(topology, getpid(), hwloc_set, flags);
}
static int
hwloc_osf_prepare_mattr(hwloc_topology_t topology __hwloc_attribute_unused, memalloc_attr_t *mattr, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags __hwloc_attribute_unused)
{
unsigned long osf_policy;
int node;
switch (policy) {
case HWLOC_MEMBIND_FIRSTTOUCH:
osf_policy = MPOL_THREAD;
break;
case HWLOC_MEMBIND_DEFAULT:
case HWLOC_MEMBIND_BIND:
osf_policy = MPOL_DIRECTED;
break;
case HWLOC_MEMBIND_INTERLEAVE:
osf_policy = MPOL_STRIPPED;
break;
case HWLOC_MEMBIND_REPLICATE:
osf_policy = MPOL_REPLICATED;
break;
default:
errno = ENOSYS;
return -1;
}
memset(mattr, 0, sizeof(*mattr));
mattr->mattr_policy = osf_policy;
mattr->mattr_rad = RAD_NONE;
radsetcreate(&mattr->mattr_radset);
rademptyset(mattr->mattr_radset);
hwloc_bitmap_foreach_begin(node, nodeset)
radaddset(mattr->mattr_radset, node);
hwloc_bitmap_foreach_end();
return 0;
}
static int
hwloc_osf_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)
{
memalloc_attr_t mattr;
int behavior = 0;
int ret;
if (flags & HWLOC_MEMBIND_MIGRATE)
behavior |= MADV_CURRENT;
if (flags & HWLOC_MEMBIND_STRICT)
behavior |= MADV_INSIST;
if (hwloc_osf_prepare_mattr(topology, &mattr, nodeset, policy, flags))
return -1;
ret = nmadvise(addr, len, MADV_CURRENT, &mattr);
radsetdestroy(&mattr.mattr_radset);
return ret;
}
static void *
hwloc_osf_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
memalloc_attr_t mattr;
void *ptr;
if (hwloc_osf_prepare_mattr(topology, &mattr, nodeset, policy, flags))
return hwloc_alloc_or_fail(topology, len, flags);
/* TODO: rather use acreate/amalloc ? */
ptr = nmmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1,
0, &mattr);
radsetdestroy(&mattr.mattr_radset);
return ptr;
}
void
hwloc_look_osf(struct hwloc_topology *topology)
{
cpu_cursor_t cursor;
unsigned nbnodes;
radid_t radid, radid2;
radset_t radset, radset2;
cpuid_t cpuid;
cpuset_t cpuset;
struct hwloc_obj *obj;
unsigned distance;
topology->backend_params.osf.nbnodes = nbnodes = rad_get_num();
cpusetcreate(&cpuset);
radsetcreate(&radset);
radsetcreate(&radset2);
{
hwloc_obj_t *nodes = calloc(nbnodes, sizeof(hwloc_obj_t));
unsigned *indexes = calloc(nbnodes, sizeof(unsigned));
float *distances = calloc(nbnodes*nbnodes, sizeof(float));
unsigned nfound;
numa_attr_t attr;
attr.nattr_type = R_RAD;
attr.nattr_descr.rd_radset = radset;
attr.nattr_flags = 0;
for (radid = 0; radid < (radid_t) nbnodes; radid++) {
rademptyset(radset);
radaddset(radset, radid);
cpuemptyset(cpuset);
if (rad_get_cpus(radid, cpuset)==-1) {
fprintf(stderr,"rad_get_cpus(%d) failed: %s\n",radid,strerror(errno));
continue;
}
indexes[radid] = radid;
nodes[radid] = obj = hwloc_alloc_setup_object(HWLOC_OBJ_NODE, radid);
obj->cpuset = hwloc_bitmap_alloc();
obj->memory.local_memory = rad_get_physmem(radid) * getpagesize();
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
cursor = SET_CURSOR_INIT;
while((cpuid = cpu_foreach(cpuset, 0, &cursor)) != CPU_NONE)
hwloc_bitmap_set(obj->cpuset, cpuid);
hwloc_debug_1arg_bitmap("node %d has cpuset %s\n",
radid, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj);
nfound = 0;
for (radid2 = 0; radid2 < (radid_t) nbnodes; radid2++)
distances[radid*nbnodes+radid2] = RAD_DIST_REMOTE;
for (distance = RAD_DIST_LOCAL; distance < RAD_DIST_REMOTE; distance++) {
attr.nattr_distance = distance;
/* get set of NUMA nodes at distance <= DISTANCE */
if (nloc(&attr, radset2)) {
fprintf(stderr,"nloc failed: %s\n", strerror(errno));
continue;
}
cursor = SET_CURSOR_INIT;
while ((radid2 = rad_foreach(radset2, 0, &cursor)) != RAD_NONE) {
if (distances[radid*nbnodes+radid2] == RAD_DIST_REMOTE) {
distances[radid*nbnodes+radid2] = (float) distance;
nfound++;
}
}
if (nfound == nbnodes)
/* Finished finding distances, no need to go up to RAD_DIST_REMOTE */
break;
}
}
hwloc_topology__set_distance_matrix(topology, HWLOC_OBJ_NODE, nbnodes, indexes, nodes, distances);
}
radsetdestroy(&radset2);
radsetdestroy(&radset);
cpusetdestroy(&cpuset);
/* add PU objects */
hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology));
hwloc_add_object_info(topology->levels[0][0], "Backend", "OSF");
}
void
hwloc_set_osf_hooks(struct hwloc_topology *topology)
{
topology->set_thread_cpubind = hwloc_osf_set_thread_cpubind;
topology->set_thisthread_cpubind = hwloc_osf_set_thisthread_cpubind;
topology->set_proc_cpubind = hwloc_osf_set_proc_cpubind;
topology->set_thisproc_cpubind = hwloc_osf_set_thisproc_cpubind;
topology->set_area_membind = hwloc_osf_set_area_membind;
topology->alloc_membind = hwloc_osf_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;
topology->support.membind->replicate_membind = 1;
}
/*
* 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 <private/autogen/config.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/processor.h>
#include <sys/procset.h>
#include <sys/types.h>
#include <sys/mman.h>
#ifdef HAVE_LIBLGRP
# include <sys/lgrp_user.h>
#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 <kstat.h>
#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
}
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2011 INRIA. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux 1
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
#include <private/autogen/config.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/misc.h>
#include <private/debug.h>
#include <limits.h>
#include <assert.h>
#include <strings.h>
/* Read from DESCRIPTION a series of integers describing a symmetrical
topology and update `topology->synthetic_description' accordingly. On
success, return zero. */
int
hwloc_backend_synthetic_init(struct hwloc_topology *topology, const char *description)
{
const char *pos, *next_pos;
unsigned long item, count;
unsigned i;
int cache_depth = 0, group_depth = 0;
int nb_machine_levels = 0, nb_node_levels = 0;
int nb_pu_levels = 0;
assert(topology->backend_type == HWLOC_BACKEND_NONE);
for (pos = description, count = 1; *pos; pos = next_pos) {
#define HWLOC_OBJ_TYPE_UNKNOWN ((hwloc_obj_type_t) -1)
hwloc_obj_type_t type = HWLOC_OBJ_TYPE_UNKNOWN;
while (*pos == ' ')
pos++;
if (!*pos)
break;
if (*pos < '0' || *pos > '9') {
if (!hwloc_namecoloncmp(pos, "machines", 2)) {
type = HWLOC_OBJ_MACHINE;
} else if (!hwloc_namecoloncmp(pos, "nodes", 1))
type = HWLOC_OBJ_NODE;
else if (!hwloc_namecoloncmp(pos, "sockets", 1))
type = HWLOC_OBJ_SOCKET;
else if (!hwloc_namecoloncmp(pos, "cores", 2))
type = HWLOC_OBJ_CORE;
else if (!hwloc_namecoloncmp(pos, "caches", 2))
type = HWLOC_OBJ_CACHE;
else if (!hwloc_namecoloncmp(pos, "pus", 1) || !hwloc_namecoloncmp(pos, "procs", 1) /* backward compatiblity with 0.9 */)
type = HWLOC_OBJ_PU;
else if (!hwloc_namecoloncmp(pos, "misc", 2))
type = HWLOC_OBJ_MISC;
else if (!hwloc_namecoloncmp(pos, "group", 2))
type = HWLOC_OBJ_GROUP;
else
fprintf(stderr, "Unknown object type `%s'\n", pos);
next_pos = strchr(pos, ':');
if (!next_pos) {
fprintf(stderr,"synthetic string doesn't have a `:' after object type at '%s'\n", pos);
errno = EINVAL;
return -1;
}
pos = next_pos + 1;
}
item = strtoul(pos, (char **)&next_pos, 0);
if (next_pos == pos) {
fprintf(stderr,"synthetic string doesn't have a number of objects at '%s'\n", pos);
errno = EINVAL;
return -1;
}
if (count + 1 >= HWLOC_SYNTHETIC_MAX_DEPTH) {
fprintf(stderr,"Too many synthetic levels, max %d\n", HWLOC_SYNTHETIC_MAX_DEPTH);
errno = EINVAL;
return -1;
}
if (item > UINT_MAX) {
fprintf(stderr,"Too big arity, max %u\n", UINT_MAX);
errno = EINVAL;
return -1;
}
topology->backend_params.synthetic.arity[count-1] = (unsigned)item;
topology->backend_params.synthetic.type[count] = type;
count++;
}
if (count <= 0) {
fprintf(stderr,"synthetic string doesn't contain any object\n");
errno = EINVAL;
return -1;
}
for(i=count-1; i>0; i--) {
hwloc_obj_type_t type;
type = topology->backend_params.synthetic.type[i];
if (type == HWLOC_OBJ_TYPE_UNKNOWN) {
if (i == count-1)
type = HWLOC_OBJ_PU;
else {
switch (topology->backend_params.synthetic.type[i+1]) {
case HWLOC_OBJ_PU: type = HWLOC_OBJ_CORE; break;
case HWLOC_OBJ_CORE: type = HWLOC_OBJ_CACHE; break;
case HWLOC_OBJ_CACHE: type = HWLOC_OBJ_SOCKET; break;
case HWLOC_OBJ_SOCKET: type = HWLOC_OBJ_NODE; break;
case HWLOC_OBJ_NODE:
case HWLOC_OBJ_GROUP: type = HWLOC_OBJ_GROUP; break;
case HWLOC_OBJ_MACHINE:
case HWLOC_OBJ_MISC: type = HWLOC_OBJ_MISC; break;
default:
assert(0);
}
}
topology->backend_params.synthetic.type[i] = type;
}
switch (type) {
case HWLOC_OBJ_PU:
if (nb_pu_levels) {
fprintf(stderr,"synthetic string can not have several PU levels\n");
errno = EINVAL;
return -1;
}
nb_pu_levels++;
break;
case HWLOC_OBJ_CACHE:
cache_depth++;
break;
case HWLOC_OBJ_GROUP:
group_depth++;
break;
case HWLOC_OBJ_NODE:
nb_node_levels++;
break;
case HWLOC_OBJ_MACHINE:
nb_machine_levels++;
break;
default:
break;
}
}
if (nb_pu_levels > 1) {
fprintf(stderr,"synthetic string can not have several PU levels\n");
errno = EINVAL;
return -1;
}
if (nb_node_levels > 1) {
fprintf(stderr,"synthetic string can not have several NUMA node levels\n");
errno = EINVAL;
return -1;
}
if (nb_machine_levels > 1) {
fprintf(stderr,"synthetic string can not have several machine levels\n");
errno = EINVAL;
return -1;
}
if (nb_machine_levels)
topology->backend_params.synthetic.type[0] = HWLOC_OBJ_SYSTEM;
else {
topology->backend_params.synthetic.type[0] = HWLOC_OBJ_MACHINE;
nb_machine_levels++;
}
if (cache_depth == 1)
/* if there is a single cache level, make it L2 */
cache_depth = 2;
for (i=0; i<count; i++) {
hwloc_obj_type_t type = topology->backend_params.synthetic.type[i];
if (type == HWLOC_OBJ_GROUP)
topology->backend_params.synthetic.depth[i] = group_depth--;
else if (type == HWLOC_OBJ_CACHE)
topology->backend_params.synthetic.depth[i] = cache_depth--;
}
topology->backend_type = HWLOC_BACKEND_SYNTHETIC;
topology->backend_params.synthetic.arity[count-1] = 0;
topology->is_thissystem = 0;
return 0;
}
void
hwloc_backend_synthetic_exit(struct hwloc_topology *topology)
{
assert(topology->backend_type == HWLOC_BACKEND_SYNTHETIC);
topology->backend_type = HWLOC_BACKEND_NONE;
}
/*
* Recursively build objects whose cpu start at first_cpu
* - level gives where to look in the type, arity and id arrays
* - the id array is used as a variable to get unique IDs for a given level.
* - generated memory should be added to *memory_kB.
* - generated cpus should be added to parent_cpuset.
* - next cpu number to be used should be returned.
*/
static unsigned
hwloc__look_synthetic(struct hwloc_topology *topology,
int level, unsigned first_cpu,
hwloc_bitmap_t parent_cpuset)
{
hwloc_obj_t obj;
unsigned i;
hwloc_obj_type_t type = topology->backend_params.synthetic.type[level];
/* pre-hooks */
switch (type) {
case HWLOC_OBJ_MISC:
break;
case HWLOC_OBJ_GROUP:
break;
case HWLOC_OBJ_SYSTEM:
/* Shouldn't happen. */
abort();
break;
case HWLOC_OBJ_MACHINE:
break;
case HWLOC_OBJ_NODE:
break;
case HWLOC_OBJ_SOCKET:
break;
case HWLOC_OBJ_CACHE:
break;
case HWLOC_OBJ_CORE:
break;
case HWLOC_OBJ_PU:
break;
case HWLOC_OBJ_TYPE_MAX:
/* Should never happen */
assert(0);
break;
}
obj = hwloc_alloc_setup_object(type, topology->backend_params.synthetic.id[level]++);
obj->cpuset = hwloc_bitmap_alloc();
if (!topology->backend_params.synthetic.arity[level]) {
hwloc_bitmap_set(obj->cpuset, first_cpu++);
} else {
for (i = 0; i < topology->backend_params.synthetic.arity[level]; i++)
first_cpu = hwloc__look_synthetic(topology, level + 1, first_cpu, obj->cpuset);
}
if (type == HWLOC_OBJ_NODE) {
obj->nodeset = hwloc_bitmap_alloc();
hwloc_bitmap_set(obj->nodeset, obj->os_index);
}
hwloc_bitmap_or(parent_cpuset, parent_cpuset, obj->cpuset);
/* post-hooks */
switch (type) {
case HWLOC_OBJ_MISC:
break;
case HWLOC_OBJ_GROUP:
obj->attr->group.depth = topology->backend_params.synthetic.depth[level];
break;
case HWLOC_OBJ_SYSTEM:
abort();
break;
case HWLOC_OBJ_MACHINE:
break;
case HWLOC_OBJ_NODE:
/* 1GB in memory nodes, 256k 4k-pages. */
obj->memory.local_memory = 1024*1024*1024;
obj->memory.page_types_len = 1;
obj->memory.page_types = malloc(sizeof(*obj->memory.page_types));
memset(obj->memory.page_types, 0, sizeof(*obj->memory.page_types));
obj->memory.page_types[0].size = 4096;
obj->memory.page_types[0].count = 256*1024;
break;
case HWLOC_OBJ_SOCKET:
break;
case HWLOC_OBJ_CACHE:
obj->attr->cache.depth = topology->backend_params.synthetic.depth[level];
obj->attr->cache.linesize = 64;
if (obj->attr->cache.depth == 1)
/* 32Kb in L1 */
obj->attr->cache.size = 32*1024;
else
/* *4 at each level, starting from 1MB for L2 */
obj->attr->cache.size = 256*1024 << (2*obj->attr->cache.depth);
break;
case HWLOC_OBJ_CORE:
break;
case HWLOC_OBJ_PU:
break;
case HWLOC_OBJ_TYPE_MAX:
/* Should never happen */
assert(0);
break;
}
hwloc_insert_object_by_cpuset(topology, obj);
return first_cpu;
}
void
hwloc_look_synthetic(struct hwloc_topology *topology)
{
hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();
unsigned first_cpu = 0, i;
topology->support.discovery->pu = 1;
/* start with id=0 for each level */
for (i = 0; topology->backend_params.synthetic.arity[i] > 0; i++)
topology->backend_params.synthetic.id[i] = 0;
/* ... including the last one */
topology->backend_params.synthetic.id[i] = 0;
/* update first level type according to the synthetic type array */
topology->levels[0][0]->type = topology->backend_params.synthetic.type[0];
for (i = 0; i < topology->backend_params.synthetic.arity[0]; i++)
first_cpu = hwloc__look_synthetic(topology, 1, first_cpu, cpuset);
hwloc_bitmap_free(cpuset);
hwloc_add_object_info(topology->levels[0][0], "Backend", "Synthetic");
}
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2010 INRIA. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux 1
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
/* To try to get all declarations duplicated below. */
#define _WIN32_WINNT 0x0601
#include <private/autogen/config.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#include <windows.h>
#ifndef HAVE_KAFFINITY
typedef ULONG_PTR KAFFINITY, *PKAFFINITY;
#endif
#ifndef HAVE_PROCESSOR_CACHE_TYPE
typedef enum _PROCESSOR_CACHE_TYPE {
CacheUnified,
CacheInstruction,
CacheData,
CacheTrace
} PROCESSOR_CACHE_TYPE;
#endif
#ifndef CACHE_FULLY_ASSOCIATIVE
#define CACHE_FULLY_ASSOCIATIVE 0xFF
#endif
#ifndef HAVE_CACHE_DESCRIPTOR
typedef struct _CACHE_DESCRIPTOR {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD Size; /* in bytes */
PROCESSOR_CACHE_TYPE Type;
} CACHE_DESCRIPTOR, *PCACHE_DESCRIPTOR;
#endif
#ifndef HAVE_LOGICAL_PROCESSOR_RELATIONSHIP
typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP {
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll = 0xffff
} LOGICAL_PROCESSOR_RELATIONSHIP;
#else /* HAVE_LOGICAL_PROCESSOR_RELATIONSHIP */
# ifndef HAVE_RELATIONPROCESSORPACKAGE
# define RelationProcessorPackage 3
# define RelationGroup 4
# define RelationAll 0xffff
# endif /* HAVE_RELATIONPROCESSORPACKAGE */
#endif /* HAVE_LOGICAL_PROCESSOR_RELATIONSHIP */
#ifndef HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION {
ULONG_PTR ProcessorMask;
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
_ANONYMOUS_UNION
union {
struct {
BYTE flags;
} ProcessorCore;
struct {
DWORD NodeNumber;
} NumaNode;
CACHE_DESCRIPTOR Cache;
ULONGLONG Reserved[2];
} DUMMYUNIONNAME;
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION;
#endif
/* Extended interface, for group support */
#ifndef HAVE_GROUP_AFFINITY
typedef struct _GROUP_AFFINITY {
KAFFINITY Mask;
WORD Group;
WORD Reserved[3];
} GROUP_AFFINITY, *PGROUP_AFFINITY;
#endif
#ifndef HAVE_PROCESSOR_RELATIONSHIP
typedef struct _PROCESSOR_RELATIONSHIP {
BYTE Flags;
BYTE Reserved[21];
WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
#endif
#ifndef HAVE_NUMA_NODE_RELATIONSHIP
typedef struct _NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
BYTE Reserved[20];
GROUP_AFFINITY GroupMask;
} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
#endif
#ifndef HAVE_CACHE_RELATIONSHIP
typedef struct _CACHE_RELATIONSHIP {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[20];
GROUP_AFFINITY GroupMask;
} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
#endif
#ifndef HAVE_PROCESSOR_GROUP_INFO
typedef struct _PROCESSOR_GROUP_INFO {
BYTE MaximumProcessorCount;
BYTE ActiveProcessorCount;
BYTE Reserved[38];
KAFFINITY ActiveProcessorMask;
} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;
#endif
#ifndef HAVE_GROUP_RELATIONSHIP
typedef struct _GROUP_RELATIONSHIP {
WORD MaximumGroupCount;
WORD ActiveGroupCount;
ULONGLONG Reserved[2];
PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY];
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
#endif
#ifndef HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
_ANONYMOUS_UNION
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
/* Odd: no member to tell the cpu mask of the package... */
} DUMMYUNIONNAME;
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
#endif
#ifndef HAVE_PSAPI_WORKING_SET_EX_BLOCK
typedef union _PSAPI_WORKING_SET_EX_BLOCK {
ULONG_PTR Flags;
struct {
unsigned Valid :1;
unsigned ShareCount :3;
unsigned Win32Protection :11;
unsigned Shared :1;
unsigned Node :6;
unsigned Locked :1;
unsigned LargePage :1;
};
} PSAPI_WORKING_SET_EX_BLOCK;
#endif
#ifndef HAVE_PSAPI_WORKING_SET_EX_INFORMATION
typedef struct _PSAPI_WORKING_SET_EX_INFORMATION {
PVOID VirtualAddress;
PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes;
} PSAPI_WORKING_SET_EX_INFORMATION;
#endif
/* TODO: SetThreadIdealProcessor */
static int
hwloc_win_set_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t thread, hwloc_const_bitmap_t hwloc_set, int flags)
{
if (flags & HWLOC_CPUBIND_NOMEMBIND) {
errno = ENOSYS;
return -1;
}
/* TODO: groups SetThreadGroupAffinity */
/* The resulting binding is always strict */
DWORD mask = hwloc_bitmap_to_ulong(hwloc_set);
if (!SetThreadAffinityMask(thread, mask))
return -1;
return 0;
}
/* TODO: SetThreadGroupAffinity to get affinity */
static int
hwloc_win_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
return hwloc_win_set_thread_cpubind(topology, GetCurrentThread(), hwloc_set, flags);
}
static int
hwloc_win_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
int ret;
hwloc_cpuset_t cpuset;
if ((policy != HWLOC_MEMBIND_DEFAULT && policy != HWLOC_MEMBIND_BIND)
|| flags & HWLOC_MEMBIND_NOCPUBIND) {
errno = ENOSYS;
return -1;
}
cpuset = hwloc_bitmap_alloc();
hwloc_cpuset_from_nodeset(topology, cpuset, nodeset);
ret = hwloc_win_set_thisthread_cpubind(topology, cpuset, flags & HWLOC_MEMBIND_STRICT?HWLOC_CPUBIND_STRICT:0);
hwloc_bitmap_free(cpuset);
return ret;
}
static int
hwloc_win_set_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t proc, hwloc_const_bitmap_t hwloc_set, int flags)
{
if (flags & HWLOC_CPUBIND_NOMEMBIND) {
errno = ENOSYS;
return -1;
}
/* TODO: groups, hard: has to manually bind all threads into the other group,
* and the bind the process inside the group */
/* The resulting binding is always strict */
DWORD mask = hwloc_bitmap_to_ulong(hwloc_set);
if (!SetProcessAffinityMask(proc, mask))
return -1;
return 0;
}
static int
hwloc_win_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
int ret;
hwloc_cpuset_t cpuset;
if ((policy != HWLOC_MEMBIND_DEFAULT && policy != HWLOC_MEMBIND_BIND)
|| flags & HWLOC_MEMBIND_NOCPUBIND) {
errno = ENOSYS;
return -1;
}
cpuset = hwloc_bitmap_alloc();
hwloc_cpuset_from_nodeset(topology, cpuset, nodeset);
ret = hwloc_win_set_proc_cpubind(topology, pid, cpuset, flags & HWLOC_MEMBIND_STRICT?HWLOC_CPUBIND_STRICT:0);
hwloc_bitmap_free(cpuset);
return ret;
}
static int
hwloc_win_get_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t proc, hwloc_bitmap_t hwloc_set, int flags)
{
DWORD_PTR proc_mask, sys_mask;
if (flags & HWLOC_CPUBIND_NOMEMBIND) {
errno = ENOSYS;
return -1;
}
/* TODO: groups, GetProcessGroupAffinity, or merge SetThreadGroupAffinity for all threads */
if (!GetProcessAffinityMask(proc, &proc_mask, &sys_mask))
return -1;
hwloc_bitmap_from_ulong(hwloc_set, proc_mask);
return 0;
}
static int
hwloc_win_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags)
{
int ret;
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
ret = hwloc_win_get_proc_cpubind(topology, pid, cpuset, flags & HWLOC_MEMBIND_STRICT?HWLOC_CPUBIND_STRICT:0);
if (!ret) {
*policy = HWLOC_MEMBIND_BIND;
hwloc_cpuset_to_nodeset(topology, cpuset, nodeset);
}
hwloc_bitmap_free(cpuset);
return ret;
}
static int
hwloc_win_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags)
{
return hwloc_win_set_proc_cpubind(topology, GetCurrentProcess(), hwloc_set, flags);
}
static int
hwloc_win_set_thisproc_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags)
{
return hwloc_win_set_proc_membind(topology, GetCurrentProcess(), nodeset, policy, flags);
}
static int
hwloc_win_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags)
{
return hwloc_win_get_proc_cpubind(topology, GetCurrentProcess(), hwloc_cpuset, flags);
}
static int
hwloc_win_get_thisproc_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags)
{
return hwloc_win_get_proc_membind(topology, GetCurrentProcess(), nodeset, policy, flags);
}
static LPVOID WINAPI (*VirtualAllocExNumaProc)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, DWORD nndPreferred);
static BOOL WINAPI (*VirtualFreeExProc)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
static BOOL WINAPI (*QueryWorkingSetExProc)(HANDLE hProcess, PVOID pv, DWORD cb);
static int hwloc_win_get_VirtualAllocExNumaProc(void) {
if (VirtualAllocExNumaProc == NULL) {
FARPROC alloc_fun = NULL, free_fun = NULL;
HMODULE kernel32;
kernel32 = LoadLibrary("kernel32.dll");
if (kernel32) {
alloc_fun = GetProcAddress(kernel32, "VirtualAllocExNuma");
free_fun = GetProcAddress(kernel32, "VirtualFreeEx");
}
if (!alloc_fun || !free_fun) {
VirtualAllocExNumaProc = (FARPROC) -1;
errno = ENOSYS;
return -1;
}
VirtualAllocExNumaProc = alloc_fun;
VirtualFreeExProc = free_fun;
} else if ((FARPROC) VirtualAllocExNumaProc == (FARPROC)-1) {
errno = ENOSYS;
return -1;
}
return 0;
}
static void *
hwloc_win_alloc(hwloc_topology_t topology __hwloc_attribute_unused, size_t len) {
return VirtualAlloc(NULL, len, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
}
static void *
hwloc_win_alloc_membind(hwloc_topology_t topology __hwloc_attribute_unused, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) {
int node;
switch (policy) {
case HWLOC_MEMBIND_DEFAULT:
case HWLOC_MEMBIND_BIND:
break;
default:
errno = ENOSYS;
return hwloc_alloc_or_fail(topology, len, flags);
}
if (flags & HWLOC_MEMBIND_STRICT) {
errno = ENOSYS;
return NULL;
}
if (hwloc_bitmap_weight(nodeset) != 1) {
/* Not a single node, can't do this */
errno = EXDEV;
return hwloc_alloc_or_fail(topology, len, flags);
}
node = hwloc_bitmap_first(nodeset);
return VirtualAllocExNumaProc(GetCurrentProcess(), NULL, len, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE, node);
}
static int
hwloc_win_free_membind(hwloc_topology_t topology __hwloc_attribute_unused, void *addr, size_t len __hwloc_attribute_unused) {
if (!addr)
return 0;
if (!VirtualFreeExProc(GetCurrentProcess(), addr, 0, MEM_RELEASE))
return -1;
return 0;
}
static int hwloc_win_get_QueryWorkingSetExProc(void) {
if (QueryWorkingSetExProc == NULL) {
FARPROC fun = NULL;
HMODULE kernel32, psapi;
kernel32 = LoadLibrary("kernel32.dll");
if (kernel32)
fun = GetProcAddress(kernel32, "K32QueryWorkingSetEx");
if (!fun) {
psapi = LoadLibrary("psapi.dll");
if (psapi)
fun = GetProcAddress(psapi, "QueryWorkingSetEx");
}
if (!fun) {
QueryWorkingSetExProc = (FARPROC) -1;
errno = ENOSYS;
return -1;
}
QueryWorkingSetExProc = fun;
} else if ((FARPROC) QueryWorkingSetExProc == (FARPROC)-1) {
errno = ENOSYS;
return -1;
}
return 0;
}
static int
hwloc_win_get_area_membind(hwloc_topology_t topology __hwloc_attribute_unused, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags)
{
SYSTEM_INFO SystemInfo;
DWORD page_size;
GetSystemInfo(&SystemInfo);
page_size = SystemInfo.dwPageSize;
uintptr_t start = (((uintptr_t) addr) / page_size) * page_size;
unsigned nb = (((uintptr_t) addr + len - start) + page_size - 1) / page_size;
if (!nb)
nb = 1;
{
PSAPI_WORKING_SET_EX_INFORMATION pv[nb];
unsigned i;
for (i = 0; i < nb; i++)
pv[i].VirtualAddress = (void*) (start + i * page_size);
if (!QueryWorkingSetExProc(GetCurrentProcess(), &pv, sizeof(pv)))
return -1;
*policy = HWLOC_MEMBIND_BIND;
if (flags & HWLOC_MEMBIND_STRICT) {
unsigned node = pv[0].VirtualAttributes.Node;
for (i = 1; i < nb; i++) {
if (pv[i].VirtualAttributes.Node != node) {
errno = EXDEV;
return -1;
}
}
hwloc_bitmap_only(nodeset, node);
return 0;
}
hwloc_bitmap_zero(nodeset);
for (i = 0; i < nb; i++)
hwloc_bitmap_set(nodeset, pv[i].VirtualAttributes.Node);
return 0;
}
}
void
hwloc_look_windows(struct hwloc_topology *topology)
{
BOOL WINAPI (*GetLogicalProcessorInformationProc)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnLength);
BOOL WINAPI (*GetLogicalProcessorInformationExProc)(LOGICAL_PROCESSOR_RELATIONSHIP relationship, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, PDWORD ReturnLength);
BOOL WINAPI (*GetNumaAvailableMemoryNodeProc)(UCHAR Node, PULONGLONG AvailableBytes);
BOOL WINAPI (*GetNumaAvailableMemoryNodeExProc)(USHORT Node, PULONGLONG AvailableBytes);
SYSTEM_INFO SystemInfo;
DWORD length;
HMODULE kernel32;
GetSystemInfo(&SystemInfo);
kernel32 = LoadLibrary("kernel32.dll");
if (kernel32) {
GetLogicalProcessorInformationProc = GetProcAddress(kernel32, "GetLogicalProcessorInformation");
GetNumaAvailableMemoryNodeProc = GetProcAddress(kernel32, "GetNumaAvailableMemoryNode");
GetNumaAvailableMemoryNodeExProc = GetProcAddress(kernel32, "GetNumaAvailableMemoryNodeEx");
GetLogicalProcessorInformationExProc = GetProcAddress(kernel32, "GetLogicalProcessorInformationEx");
if (!GetLogicalProcessorInformationExProc && GetLogicalProcessorInformationProc) {
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION procInfo;
unsigned id;
unsigned i;
struct hwloc_obj *obj;
hwloc_obj_type_t type;
length = 0;
procInfo = NULL;
while (1) {
if (GetLogicalProcessorInformationProc(procInfo, &length))
break;
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return;
procInfo = realloc(procInfo, length);
}
for (i = 0; i < length / sizeof(*procInfo); i++) {
/* Ignore non-data caches */
if (procInfo[i].Relationship == RelationCache
&& procInfo[i].Cache.Type != CacheUnified
&& procInfo[i].Cache.Type != CacheData)
continue;
id = -1;
switch (procInfo[i].Relationship) {
case RelationNumaNode:
type = HWLOC_OBJ_NODE;
id = procInfo[i].NumaNode.NodeNumber;
break;
case RelationProcessorPackage:
type = HWLOC_OBJ_SOCKET;
break;
case RelationCache:
type = HWLOC_OBJ_CACHE;
break;
case RelationProcessorCore:
type = HWLOC_OBJ_CORE;
break;
case RelationGroup:
default:
type = HWLOC_OBJ_GROUP;
break;
}
obj = hwloc_alloc_setup_object(type, id);
obj->cpuset = hwloc_bitmap_alloc();
hwloc_debug("%s#%u mask %lx\n", hwloc_obj_type_string(type), id, procInfo[i].ProcessorMask);
hwloc_bitmap_from_ulong(obj->cpuset, procInfo[i].ProcessorMask);
switch (type) {
case HWLOC_OBJ_NODE:
{
ULONGLONG avail;
obj->nodeset = hwloc_bitmap_alloc();
hwloc_bitmap_set(obj->nodeset, id);
if ((GetNumaAvailableMemoryNodeExProc && GetNumaAvailableMemoryNodeExProc(id, &avail))
|| (GetNumaAvailableMemoryNodeProc && GetNumaAvailableMemoryNodeProc(id, &avail)))
obj->memory.local_memory = avail;
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_len = 1;
obj->memory.page_types[0].size = SystemInfo.dwPageSize;
#ifdef HAVE__SC_LARGE_PAGESIZE
obj->memory.page_types_len++;
obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE);
#endif
break;
}
case HWLOC_OBJ_CACHE:
obj->attr->cache.size = procInfo[i].Cache.Size;
obj->attr->cache.linesize = procInfo[i].Cache.LineSize;
obj->attr->cache.depth = procInfo[i].Cache.Level;
break;
case HWLOC_OBJ_GROUP:
obj->attr->group.depth = procInfo[i].Relationship == RelationGroup;
break;
default:
break;
}
hwloc_insert_object_by_cpuset(topology, obj);
}
free(procInfo);
}
if (GetLogicalProcessorInformationExProc) {
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX procInfoTotal, procInfo;
unsigned id;
struct hwloc_obj *obj;
hwloc_obj_type_t type;
length = 0;
procInfoTotal = NULL;
while (1) {
if (GetLogicalProcessorInformationExProc(RelationAll, procInfoTotal, &length))
break;
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return;
procInfoTotal = realloc(procInfoTotal, length);
}
for (procInfo = procInfoTotal;
(void*) procInfo < (void*) ((unsigned long) procInfoTotal + length);
procInfo = (void*) ((unsigned long) procInfo + procInfo->Size)) {
unsigned num, i;
GROUP_AFFINITY *GroupMask;
/* Ignore non-data caches */
if (procInfo->Relationship == RelationCache
&& procInfo->Cache.Type != CacheUnified
&& procInfo->Cache.Type != CacheData)
continue;
id = -1;
switch (procInfo->Relationship) {
case RelationNumaNode:
type = HWLOC_OBJ_NODE;
num = 1;
GroupMask = &procInfo->NumaNode.GroupMask;
id = procInfo->NumaNode.NodeNumber;
break;
case RelationProcessorPackage:
type = HWLOC_OBJ_SOCKET;
num = procInfo->Processor.GroupCount;
GroupMask = procInfo->Processor.GroupMask;
break;
case RelationCache:
type = HWLOC_OBJ_CACHE;
num = 1;
GroupMask = &procInfo->Cache.GroupMask;
break;
case RelationProcessorCore:
type = HWLOC_OBJ_CORE;
num = procInfo->Processor.GroupCount;
GroupMask = procInfo->Processor.GroupMask;
break;
case RelationGroup:
/* So strange an interface... */
for (id = 0; id < procInfo->Group.ActiveGroupCount; id++) {
KAFFINITY mask;
obj = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, id);
obj->cpuset = hwloc_bitmap_alloc();
mask = procInfo->Group.GroupInfo[id].ActiveProcessorMask;
hwloc_debug("group %u %d cpus mask %lx\n", id,
procInfo->Group.GroupInfo[id].ActiveProcessorCount, mask);
hwloc_bitmap_from_ith_ulong(obj->cpuset, id, mask);
hwloc_insert_object_by_cpuset(topology, obj);
}
continue;
default:
/* Don't know how to get the mask. */
hwloc_debug("unknown relation %d\n", procInfo->Relationship);
continue;
}
obj = hwloc_alloc_setup_object(type, id);
obj->cpuset = hwloc_bitmap_alloc();
for (i = 0; i < num; i++) {
hwloc_debug("%s#%u %d: mask %d:%lx\n", hwloc_obj_type_string(type), id, i, GroupMask[i].Group, GroupMask[i].Mask);
hwloc_bitmap_from_ith_ulong(obj->cpuset, GroupMask[i].Group, GroupMask[i].Mask);
}
switch (type) {
case HWLOC_OBJ_NODE:
{
ULONGLONG avail;
obj->nodeset = hwloc_bitmap_alloc();
hwloc_bitmap_set(obj->nodeset, id);
if ((GetNumaAvailableMemoryNodeExProc && GetNumaAvailableMemoryNodeExProc(id, &avail))
|| (GetNumaAvailableMemoryNodeProc && GetNumaAvailableMemoryNodeProc(id, &avail)))
obj->memory.local_memory = avail;
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_len = 1;
obj->memory.page_types[0].size = SystemInfo.dwPageSize;
#ifdef HAVE__SC_LARGE_PAGESIZE
obj->memory.page_types_len++;
obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE);
#endif
break;
}
case HWLOC_OBJ_CACHE:
obj->attr->cache.size = procInfo->Cache.CacheSize;
obj->attr->cache.linesize = procInfo->Cache.LineSize;
obj->attr->cache.depth = procInfo->Cache.Level;
break;
default:
break;
}
hwloc_insert_object_by_cpuset(topology, obj);
}
free(procInfoTotal);
}
}
/* add PU objects */
hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology));
hwloc_add_object_info(topology->levels[0][0], "Backend", "Windows");
}
void
hwloc_set_windows_hooks(struct hwloc_topology *topology)
{
topology->set_proc_cpubind = hwloc_win_set_proc_cpubind;
topology->get_proc_cpubind = hwloc_win_get_proc_cpubind;
topology->set_thread_cpubind = hwloc_win_set_thread_cpubind;
topology->set_thisproc_cpubind = hwloc_win_set_thisproc_cpubind;
topology->get_thisproc_cpubind = hwloc_win_get_thisproc_cpubind;
topology->set_thisthread_cpubind = hwloc_win_set_thisthread_cpubind;
/* TODO: get_last_cpu_location: use GetCurrentProcessorNumber */
topology->set_proc_membind = hwloc_win_set_proc_membind;
topology->get_proc_membind = hwloc_win_get_proc_membind;
topology->set_thisproc_membind = hwloc_win_set_thisproc_membind;
topology->get_thisproc_membind = hwloc_win_get_thisproc_membind;
topology->set_thisthread_membind = hwloc_win_set_thisthread_membind;
if (!hwloc_win_get_VirtualAllocExNumaProc()) {
topology->alloc_membind = hwloc_win_alloc_membind;
topology->alloc = hwloc_win_alloc;
topology->free_membind = hwloc_win_free_membind;
topology->support.membind->bind_membind = 1;
}
if (!hwloc_win_get_QueryWorkingSetExProc())
topology->get_area_membind = hwloc_win_get_area_membind;
}
/*
* Copyright © 2010 INRIA. All rights reserved.
* Copyright © 2010-2011 Université Bordeaux 1
* Copyright © 2010-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*
*
* This backend is only used when the operating system does not export
* the necessary hardware topology information to user-space applications.
* Currently, only the FreeBSD backend relies on this x86 backend.
*
* Other backends such as Linux have their own way to retrieve various
* pieces of hardware topology information from the operating system
* on various architectures, without having to use this x86-specific code.
*/
#include <private/autogen/config.h>
#include <hwloc.h>
#include <private/private.h>
#include <private/debug.h>
#include <private/cpuid.h>
#include <private/misc.h>
struct cacheinfo {
unsigned type;
unsigned level;
unsigned nbthreads_sharing;
unsigned linesize;
unsigned linepart;
unsigned ways;
unsigned sets;
unsigned size;
};
struct procinfo {
unsigned present;
unsigned apicid;
unsigned max_log_proc;
unsigned max_nbcores;
unsigned max_nbthreads;
unsigned socketid;
unsigned logprocid;
unsigned threadid;
unsigned coreid;
unsigned *otherids;
unsigned levels;
unsigned numcaches;
struct cacheinfo *cache;
};
enum cpuid_type {
intel,
amd,
unknown
};
static void fill_amd_cache(struct procinfo *infos, unsigned level, unsigned cpuid)
{
struct cacheinfo *cache;
unsigned cachenum;
unsigned size = 0;
if (level == 1)
size = ((cpuid >> 24)) << 10;
else if (level == 2)
size = ((cpuid >> 16)) << 10;
else if (level == 3)
size = ((cpuid >> 18)) << 19;
if (!size)
return;
cachenum = infos->numcaches++;
infos->cache = realloc(infos->cache, infos->numcaches*sizeof(*infos->cache));
cache = &infos->cache[cachenum];
cache->type = 1;
cache->level = level;
if (level <= 2)
cache->nbthreads_sharing = 1;
else
cache->nbthreads_sharing = infos->max_log_proc;
cache->linesize = cpuid & 0xff;
cache->linepart = 0;
if (level == 1)
cache->ways = (cpuid >> 16) & 0xff;
else {
static const unsigned ways_tab[] = { 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 0 };
unsigned ways = (cpuid >> 12) & 0xf;
cache->ways = ways_tab[ways];
}
cache->size = size;
cache->sets = 0;
hwloc_debug("cache L%u t%u linesize %u ways %u size %uKB\n", cache->level, cache->nbthreads_sharing, cache->linesize, cache->ways, cache->size >> 10);
}
/* Fetch information from the processor itself thanks to cpuid and store it in
* infos for summarize to analyze them globally */
static void look_proc(struct procinfo *infos, unsigned highest_cpuid, unsigned highest_ext_cpuid, enum cpuid_type cpuid_type)
{
unsigned eax, ebx, ecx = 0, edx;
unsigned cachenum;
struct cacheinfo *cache;
infos->present = 1;
eax = 0x01;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
infos->apicid = ebx >> 24;
if (edx & (1 << 28))
infos->max_log_proc = 1 << hwloc_flsl(((ebx >> 16) & 0xff) - 1);
else
infos->max_log_proc = 1;
hwloc_debug("APIC ID 0x%02x max_log_proc %u\n", infos->apicid, infos->max_log_proc);
infos->socketid = infos->apicid / infos->max_log_proc;
infos->logprocid = infos->apicid % infos->max_log_proc;
infos->coreid = (unsigned) -1;
infos->threadid = (unsigned) -1;
hwloc_debug("phys %u thread %u\n", infos->socketid, infos->logprocid);
/* Intel doesn't actually provide 0x80000008 information */
if (cpuid_type != intel && highest_ext_cpuid >= 0x80000008) {
unsigned coreidsize;
eax = 0x80000008;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
coreidsize = (ecx >> 12) & 0xf;
hwloc_debug("core ID size: %u\n", coreidsize);
if (!coreidsize) {
infos->max_nbcores = (ecx & 0xff) + 1;
} else
infos->max_nbcores = 1 << coreidsize;
hwloc_debug("Thus max # of cores: %u\n", infos->max_nbcores);
/* Still no multithreaded AMD */
infos->max_nbthreads = 1 ;
hwloc_debug("and max # of threads: %u\n", infos->max_nbthreads);
infos->threadid = infos->logprocid % infos->max_nbthreads;
infos->coreid = infos->logprocid / infos->max_nbthreads;
hwloc_debug("this is thread %u of core %u\n", infos->threadid, infos->coreid);
}
infos->numcaches = 0;
infos->cache = NULL;
/* Intel doesn't actually provide 0x80000005 information */
if (cpuid_type != intel && highest_ext_cpuid >= 0x80000005) {
eax = 0x80000005;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
fill_amd_cache(infos, 1, ecx);
}
/* Intel doesn't actually provide 0x80000006 information */
if (cpuid_type != intel && highest_ext_cpuid >= 0x80000006) {
eax = 0x80000006;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
fill_amd_cache(infos, 2, ecx);
fill_amd_cache(infos, 3, edx);
}
/* AMD doesn't actually provide 0x04 information */
if (cpuid_type != amd && highest_cpuid >= 0x04) {
cachenum = 0;
for (cachenum = 0; ; cachenum++) {
unsigned type;
eax = 0x04;
ecx = cachenum;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
type = eax & 0x1f;
hwloc_debug("cache %u type %u\n", cachenum, type);
if (type == 0)
break;
if (type == 2)
/* Instruction cache */
continue;
infos->numcaches++;
}
cache = infos->cache = malloc(infos->numcaches * sizeof(*infos->cache));
for (cachenum = 0; ; cachenum++) {
unsigned linesize, linepart, ways, sets;
unsigned type;
eax = 0x04;
ecx = cachenum;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
type = eax & 0x1f;
if (type == 0)
break;
if (type == 2)
/* Instruction cache */
continue;
cache->type = type;
cache->level = (eax >> 5) & 0x7;
cache->nbthreads_sharing = ((eax >> 14) & 0xfff) + 1;
infos->max_nbcores = ((eax >> 26) & 0x3f) + 1;
cache->linesize = linesize = (ebx & 0xfff) + 1;
cache->linepart = linepart = ((ebx >> 12) & 0x3ff) + 1;
cache->ways = ways = ((ebx >> 22) & 0x3ff) + 1;
cache->sets = sets = ecx + 1;
cache->size = linesize * linepart * ways * sets;
hwloc_debug("cache %u type %u L%u t%u c%u linesize %u linepart %u ways %u sets %u, size %uKB\n", cachenum, cache->type, cache->level, cache->nbthreads_sharing, infos->max_nbcores, linesize, linepart, ways, sets, cache->size >> 10);
infos->max_nbthreads = infos->max_log_proc / infos->max_nbcores;
hwloc_debug("thus %u threads\n", infos->max_nbthreads);
infos->threadid = infos->logprocid % infos->max_nbthreads;
infos->coreid = infos->logprocid / infos->max_nbthreads;
hwloc_debug("this is thread %u of core %u\n", infos->threadid, infos->coreid);
cache++;
}
}
if (cpuid_type == intel && highest_cpuid >= 0x0b) {
unsigned level, apic_nextshift, apic_number, apic_type, apic_id = 0, apic_shift = 0, id;
for (level = 0; ; level++) {
ecx = level;
eax = 0x0b;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
if (!eax && !ebx)
break;
}
if (level) {
infos->levels = level;
infos->otherids = malloc(level * sizeof(*infos->otherids));
for (level = 0; ; level++) {
ecx = level;
eax = 0x0b;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
if (!eax && !ebx)
break;
apic_nextshift = eax & 0x1f;
apic_number = ebx & 0xffff;
apic_type = (ecx & 0xff00) >> 8;
apic_id = edx;
id = (apic_id >> apic_shift) & ((1 << (apic_nextshift - apic_shift)) - 1);
hwloc_debug("x2APIC %08x %d: nextshift %d num %2d type %d id %2d\n", apic_id, level, apic_nextshift, apic_number, apic_type, id);
infos->apicid = apic_id;
infos->otherids[level] = UINT_MAX;
switch (apic_type) {
case 1:
infos->threadid = id;
break;
case 2:
infos->coreid = id;
break;
default:
hwloc_debug("x2APIC %d: unknown type %d\n", level, apic_type);
infos->otherids[level] = apic_id >> apic_shift;
break;
}
apic_shift = apic_nextshift;
}
infos->socketid = apic_id >> apic_shift;
hwloc_debug("x2APIC remainder: %d\n", infos->socketid);
} else
infos->otherids = NULL;
} else
infos->otherids = NULL;
}
/* Analyse information stored in infos, and build topology levels accordingly */
static void summarize(hwloc_topology_t topology, struct procinfo *infos, unsigned nbprocs)
{
hwloc_bitmap_t complete_cpuset = hwloc_bitmap_alloc();
unsigned i, j, l, level;
int one = -1;
for (i = 0; i < nbprocs; i++)
if (infos[i].present) {
hwloc_bitmap_set(complete_cpuset, i);
one = i;
}
if (one == -1)
return;
/* Look for sockets */
{
hwloc_bitmap_t sockets_cpuset = hwloc_bitmap_dup(complete_cpuset);
hwloc_bitmap_t socket_cpuset;
hwloc_obj_t sock;
while ((i = hwloc_bitmap_first(sockets_cpuset)) != (unsigned) -1) {
unsigned socketid = infos[i].socketid;
socket_cpuset = hwloc_bitmap_alloc();
for (j = i; j < nbprocs; j++) {
if (infos[j].socketid == socketid) {
hwloc_bitmap_set(socket_cpuset, j);
hwloc_bitmap_clr(sockets_cpuset, j);
}
}
sock = hwloc_alloc_setup_object(HWLOC_OBJ_SOCKET, socketid);
sock->cpuset = socket_cpuset;
hwloc_debug_1arg_bitmap("os socket %u has cpuset %s\n",
socketid, socket_cpuset);
hwloc_insert_object_by_cpuset(topology, sock);
}
hwloc_bitmap_free(sockets_cpuset);
}
/* Look for unknown objects */
if (infos[one].otherids) {
for (level = infos[one].levels-1; level <= infos[one].levels-1; level--) {
if (infos[one].otherids[level] != UINT_MAX) {
hwloc_bitmap_t unknowns_cpuset = hwloc_bitmap_dup(complete_cpuset);
hwloc_bitmap_t unknown_cpuset;
hwloc_obj_t unknown;
while ((i = hwloc_bitmap_first(unknowns_cpuset)) != (unsigned) -1) {
unsigned unknownid = infos[i].otherids[level];
unknown_cpuset = hwloc_bitmap_alloc();
for (j = i; j < nbprocs; j++) {
if (infos[j].otherids[level] == unknownid) {
hwloc_bitmap_set(unknown_cpuset, j);
hwloc_bitmap_clr(unknowns_cpuset, j);
}
}
unknown = hwloc_alloc_setup_object(HWLOC_OBJ_MISC, unknownid);
unknown->cpuset = unknown_cpuset;
unknown->os_level = level;
hwloc_debug_2args_bitmap("os unknown%d %u has cpuset %s\n",
level, unknownid, unknown_cpuset);
hwloc_insert_object_by_cpuset(topology, unknown);
}
hwloc_bitmap_free(unknowns_cpuset);
}
}
}
/* Look for cores */
{
hwloc_bitmap_t cores_cpuset = hwloc_bitmap_dup(complete_cpuset);
hwloc_bitmap_t core_cpuset;
hwloc_obj_t core;
while ((i = hwloc_bitmap_first(cores_cpuset)) != (unsigned) -1) {
unsigned socketid = infos[i].socketid;
unsigned coreid = infos[i].coreid;
if (coreid == (unsigned) -1) {
hwloc_bitmap_clr(cores_cpuset, i);
continue;
}
core_cpuset = hwloc_bitmap_alloc();
for (j = i; j < nbprocs; j++) {
if (infos[j].coreid == (unsigned) -1) {
hwloc_bitmap_clr(cores_cpuset, j);
continue;
}
if (infos[j].socketid == socketid && infos[j].coreid == coreid) {
hwloc_bitmap_set(core_cpuset, j);
hwloc_bitmap_clr(cores_cpuset, j);
}
}
core = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, coreid);
core->cpuset = core_cpuset;
hwloc_debug_1arg_bitmap("os core %u has cpuset %s\n",
coreid, core_cpuset);
hwloc_insert_object_by_cpuset(topology, core);
}
hwloc_bitmap_free(cores_cpuset);
}
/* Look for caches */
/* First find max level */
level = 0;
for (i = 0; i < nbprocs; i++)
for (j = 0; j < infos[i].numcaches; j++)
if (infos[i].cache[j].level > level)
level = infos[i].cache[j].level;
while (level > 0) {
/* Look for caches at level level */
{
hwloc_bitmap_t caches_cpuset = hwloc_bitmap_dup(complete_cpuset);
hwloc_bitmap_t cache_cpuset;
hwloc_obj_t cache;
while ((i = hwloc_bitmap_first(caches_cpuset)) != (unsigned) -1) {
unsigned socketid = infos[i].socketid;
for (l = 0; l < infos[i].numcaches; l++) {
if (infos[i].cache[l].level == level)
break;
}
if (l == infos[i].numcaches) {
/* no cache Llevel in i, odd */
hwloc_bitmap_clr(caches_cpuset, i);
continue;
}
{
unsigned cacheid = infos[i].apicid / infos[i].cache[l].nbthreads_sharing;
cache_cpuset = hwloc_bitmap_alloc();
for (j = i; j < nbprocs; j++) {
unsigned l2;
for (l2 = 0; l2 < infos[j].numcaches; l2++) {
if (infos[j].cache[l2].level == level)
break;
}
if (l2 == infos[j].numcaches) {
/* no cache Llevel in j, odd */
hwloc_bitmap_clr(caches_cpuset, j);
continue;
}
if (infos[j].socketid == socketid && infos[j].apicid / infos[j].cache[l2].nbthreads_sharing == cacheid) {
hwloc_bitmap_set(cache_cpuset, j);
hwloc_bitmap_clr(caches_cpuset, j);
}
}
cache = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, cacheid);
cache->attr->cache.depth = level;
cache->attr->cache.size = infos[i].cache[l].size;
cache->attr->cache.linesize = infos[i].cache[l].linesize;
cache->cpuset = cache_cpuset;
hwloc_debug_2args_bitmap("os L%u cache %u has cpuset %s\n",
level, cacheid, cache_cpuset);
hwloc_insert_object_by_cpuset(topology, cache);
}
}
hwloc_bitmap_free(caches_cpuset);
}
level--;
}
for (i = 0; i < nbprocs; i++) {
free(infos[i].cache);
if (infos[i].otherids)
free(infos[i].otherids);
}
}
#define INTEL_EBX ('G' | ('e'<<8) | ('n'<<16) | ('u'<<24))
#define INTEL_EDX ('i' | ('n'<<8) | ('e'<<16) | ('I'<<24))
#define INTEL_ECX ('n' | ('t'<<8) | ('e'<<16) | ('l'<<24))
#define AMD_EBX ('A' | ('u'<<8) | ('t'<<16) | ('h'<<24))
#define AMD_EDX ('e' | ('n'<<8) | ('t'<<16) | ('i'<<24))
#define AMD_ECX ('c' | ('A'<<8) | ('M'<<16) | ('D'<<24))
void hwloc_look_x86(struct hwloc_topology *topology, unsigned nbprocs)
{
/* This function must always be here, but it's ok if it's empty. */
#if defined(HWLOC_HAVE_CPUID)
unsigned eax, ebx, ecx = 0, edx;
hwloc_bitmap_t orig_cpuset;
unsigned i;
unsigned highest_cpuid;
unsigned highest_ext_cpuid;
struct procinfo *infos = NULL;
enum cpuid_type cpuid_type = unknown;
if (!hwloc_have_cpuid())
return;
infos = malloc(sizeof(struct procinfo) * nbprocs);
if (NULL == infos) {
return;
}
eax = 0x00;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
highest_cpuid = eax;
if (ebx == INTEL_EBX && ecx == INTEL_ECX && edx == INTEL_EDX)
cpuid_type = intel;
if (ebx == AMD_EBX && ecx == AMD_ECX && edx == AMD_EDX)
cpuid_type = amd;
hwloc_debug("highest cpuid %x, cpuid type %u\n", highest_cpuid, cpuid_type);
if (highest_cpuid < 0x01) {
goto free;
}
eax = 0x80000000;
hwloc_cpuid(&eax, &ebx, &ecx, &edx);
highest_ext_cpuid = eax;
hwloc_debug("highest extended cpuid %x\n", highest_ext_cpuid);
orig_cpuset = hwloc_bitmap_alloc();
if (topology->get_thisthread_cpubind && topology->set_thisthread_cpubind) {
if (!topology->get_thisthread_cpubind(topology, orig_cpuset, HWLOC_CPUBIND_STRICT)) {
hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();
for (i = 0; i < nbprocs; i++) {
hwloc_bitmap_only(cpuset, i);
if (topology->set_thisthread_cpubind(topology, cpuset, HWLOC_CPUBIND_STRICT))
continue;
look_proc(&infos[i], highest_cpuid, highest_ext_cpuid, cpuid_type);
}
hwloc_bitmap_free(cpuset);
topology->set_thisthread_cpubind(topology, orig_cpuset, 0);
hwloc_bitmap_free(orig_cpuset);
summarize(topology, infos, nbprocs);
goto free;
}
}
if (topology->get_thisproc_cpubind && topology->set_thisproc_cpubind) {
if (!topology->get_thisproc_cpubind(topology, orig_cpuset, HWLOC_CPUBIND_STRICT)) {
hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();
for (i = 0; i < nbprocs; i++) {
hwloc_bitmap_only(cpuset, i);
if (topology->set_thisproc_cpubind(topology, cpuset, HWLOC_CPUBIND_STRICT))
continue;
look_proc(&infos[i], highest_cpuid, highest_ext_cpuid, cpuid_type);
}
hwloc_bitmap_free(cpuset);
topology->set_thisproc_cpubind(topology, orig_cpuset, 0);
hwloc_bitmap_free(orig_cpuset);
summarize(topology, infos, nbprocs);
goto free;
}
}
#endif
hwloc_add_object_info(topology->levels[0][0], "Backend", "x86");
free:
if (NULL != infos) {
free(infos);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment