Le 11/11/2010 02:31, Samuel Thibault a écrit :
>> get_mempolicy: Invalid argument
>> hwloc_get_membind failed (errno 22 Invalid argument)
>>
>
> Could you try to increase the value of max_os_index?
>
> I can see in the kernel source code the following in sys_get_mempolicy:
>
> if (nmask != NULL && maxnode < MAX_NUMNODES)
> return -EINVAL;
>
> and MAX_NUMNODES depends on .config ...
>
And indeed MAX_NUMNODES is (1<<CONFIG_NODES_SHIFT) and
CONFIG_NODES_SHIFT=9 on rhel6 kernels. We pass a single ulong to the
kernel, so it's not large enough to store 1<<9 bits. We couldn't
reproduce on Debian and RHEL5 since NODE_SHIFT=6 there.
We had to loop until we found the kernel NR_CPUS for sched_getaffinity,
we can do the same to find the kernel MAX_NUMNODES for get_mempolicy.
The attached patch may help. Only slightly tested obviously since I
don't have any kernel causing the problem.
Brice
diff --git a/src/topology-linux.c b/src/topology-linux.c
index 2b936f6..b34c3f6 100644
--- a/src/topology-linux.c
+++ b/src/topology-linux.c
@@ -1032,28 +1032,47 @@ hwloc_linux_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_nodese
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)
+{
+ 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)
+ /* found it */
+ return max_numnodes;
+ max_numnodes *= 2;
+ }
+}
+
static int
/* TODO: documentation says process, but do_get_mempolicy source
* code says pol = current->mempolicy;... */
hwloc_linux_get_thisthread_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags __hwloc_attribute_unused)
{
hwloc_const_bitmap_t complete_nodeset;
- unsigned max_os_index; /* highest os_index + 1 */
+ unsigned max_os_index;
unsigned long *linuxmask;
int linuxpolicy;
int err;
- /* compute max_os_index */
- complete_nodeset = hwloc_topology_get_complete_nodeset(topology);
- if (complete_nodeset) {
- max_os_index = hwloc_bitmap_last(complete_nodeset);
- if (max_os_index == (unsigned) -1)
- max_os_index = 0;
- } else {
- max_os_index = 0;
- }
- /* round up to the nearest multiple of BITS_PER_LONG */
- max_os_index = (max_os_index + HWLOC_BITS_PER_LONG) & ~(HWLOC_BITS_PER_LONG - 1);
+ max_os_index = hwloc_linux_find_kernel_max_numnodes(topology);
linuxmask = malloc(max_os_index/HWLOC_BITS_PER_LONG * sizeof(long));
if (!linuxmask) {