mbind返回EINVAL

5
我正在使用以下问题提供的代码numa+mbind+segfault,每个调用mbind都返回EINVAL。如何确定出错原因?我问这个问题是因为EINVAL可能由许多原因引起。
page_size = sysconf(_SC_PAGESIZE);
objs_per_page = page_size/sizeof(A[0]);
assert(page_size%sizeof(A[0])==0);
split_three=num_items/3;
aligned_size=(split_three/objs_per_page)*objs_per_page;
remnant=num_items-(aligned_size*3);
piece = aligned_size;

nodemask=1;
mbind(&A[0],piece*sizeof(double),MPOL_BIND,&nodemask,64,MPOL_MF_MOVE);

nodemask=2;
mbind(&A[aligned_size],piece*sizeof(double),MPOL_BIND,&nodemask,64,MPOL_MF_MOVE);

nodemask=4;
bind(&A[aligned_size*2+remnant],piece*sizeof(double),MPOL_BIND,
     &nodemask,64,MPOL_MF_MOVE);

在运行下面的程序(通过在每个mbind调用之前将nodemask更改为1、2和4,如Mats Petersson的答案所示)之后,有时会出现分段错误,有时会正常运行。当它出现分段错误时,dmesg如下:
Stack:
Call Trace:
mpol_new+0x5d/0xb0
sys_mbind+0x125/0x4f0
finish_task_switch+0x4a/0xf0
? __schedule+0x3cf/0x7c0
system_call_fastpath+0x16/0x1b
Code: ...
kmem_cache_alloc+0x58/0x130

看起来像是一个合适的内核崩溃。不确定为什么 - 你正在运行什么确切的内核?恐怕这不是一个容易修复的问题。你的系统通常稳定并且运行良好,对吗? - Mats Petersson
@MatsPetersson 这是Ubuntu 12.10。Linux 3.5.0-19-generic #30,x86_64。谢谢。 - tiki
看起来3.5(http://lxr.linux.no/#linux+v3.5/mm/slub.c#L2305)和3.7.4(http://lxr.linux.no/#linux+v3.7.4/mm/slub.c#L2317)中相关的代码已经有所改变,但并不显著。当然,在调用kmem_cache_alloc之前的几百行代码中可能存在任何错误。我真的看不出这里会出什么问题。 - Mats Petersson
1个回答

4
查看Linux内核源代码,您可能会因以下原因收到EINVAL:
  • 传递无效的模式值。超出了“不一致”范围(同时使用静态和相对节点)
  • 无效的maxnode(>页面中的位数->x86上的32K)。
  • nodemask存在各种其他问题。
  • 没有MPOL_MF_STRICT | MPOL_MF_MOVE | MPOL_MF_MOVE_ALL之一
  • start未与页对齐。
  • start+len当对齐的页面= start时。【也就是说,您的len至少不含一个字节】
  • start+len<start-也就是负长度。
  • policy=MPOL_DEFAULT并且nodes不为空或NULL
  • 引用源代码的注释:“如果nodemask为空(本地分配),则不能将MPOL_PREFERRED与MPOL_F_STATIC_NODES或MPOL_F_RELATIVE_NODES一起使用。所有其他模式都需要指向非空nodemask的有效指针。”
我猜问题在于start未与页对齐。
这段代码对我有效:
#include <numaif.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define ASSERT(x) do { if (!(x)) do_assert(#x,(long)(x), __FILE__, __LINE__); } while(0)

static void do_assert(const char *expr, long expr_int, const char *file, int line)
{
    fprintf(stderr, "ASSERT failed %s (%d) at %s:%d\n", 
        expr, expr_int, file, line);
    perror("Error if present:");
    exit(1);
}


int main()
{ 
    size_t num_items = 6156000;
    double *A = valloc(num_items * sizeof(double));
    ASSERT(A != NULL);
    int res;
    unsigned long nodemask;


    size_t page_size = sysconf(_SC_PAGESIZE);
    size_t objs_per_page = page_size/sizeof(A[0]);
    ASSERT(page_size%sizeof(A[0])==0);
    size_t split_three=num_items/3;
    size_t aligned_size=(split_three/objs_per_page)*objs_per_page;
    size_t remnant=num_items-(aligned_size*3);
    size_t piece = aligned_size;

    printf("A[0]=%p\n", &A[0]);
    printf("A[%d]=%p\n", piece, &A[aligned_size]);
    printf("A[%d]=%p\n", 2*piece, &A[2*piece]);


    nodemask=1;
    res = mbind(&A[0],piece*sizeof(double),MPOL_BIND,&nodemask,64,MPOL_MF_MOVE);
    ASSERT(res ==0);
    nodemask=1;
    res = mbind(&A[aligned_size],piece*sizeof(double),MPOL_BIND,&nodemask,64,MPOL_MF_MOVE);
    ASSERT(res ==0);

    nodemask=1;
    res = mbind(&A[aligned_size*2],(piece+remnant)*sizeof(double),MPOL_BIND,
     &nodemask,64,MPOL_MF_MOVE);
    ASSERT(res == 0);
}

请注意,我在所有分配中使用“nodemask = 1”,因为我机器上只有一个四核处理器,所以没有其他节点可以绑定 - 这也会导致“EINVAL”。我猜你的系统中实际上有多个节点。
我还将“剩余部分”从“A []”移动到最后一个“mbind”调用的“piece + remnant”大小。

我运行它的SIZE为6156000,得到piece=2051584,aligned_size=2051584和remnant=1248。谢谢。 - tiki
所以,让我们来计算一下:6156000等于769500个双精度数。每组应该有256500个双精度数。但这不是一个偶数页。256500是。那就是2048000。这意味着使用“aligned_size”时第二个起始点将不对齐。你能把计算得到的“aligned_size”和余数粘贴到你的问题中吗? - Mats Petersson
在它完成这些调用之前,还是在稍后的某个时间点?显然,如果没有看到你的其他代码,我无法确定它的具体情况。通常,seg-fault 意味着你在数组中使用了不正确的索引。 - Mats Petersson
我没有其他的代码,我只是按照你上面提供的代码运行它。在打印所有带有A的printf语句之后,它显示了segfault错误。有时候它可以正常运行而没有任何segfault错误。 - tiki
你可能想要添加一些额外的打印输出来找出mbind节点中哪一个失败了。 - Mats Petersson
显示剩余12条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接