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) {

Reply via email to