【问题标题】:mbind returns EINVALmbind 返回 EINVAL
【发布时间】:2013-01-10 18:51:58
【问题描述】:

我正在使用为以下问题提供的代码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 调用之前将节点掩码分别更改为 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

【问题讨论】:

  • 对我来说看起来像是一个适当的内核崩溃。不知道为什么——你运行的是什么内核?我不确定这是一个容易解决的问题。您的系统通常很稳定并且运行良好,是吗?
  • @MatsPetersson 这是 Ubuntu 12.10。 Linux 3.5.0-19-generic #30,x86_64。谢谢。
  • 看起来 3.5 (lxr.linux.no/#linux+v3.5/mm/slub.c#L2305) 和 3.7.4 (lxr.linux.no/#linux+v3.7.4/mm/slub.c#L2317) 中的相关代码发生了一些变化,但变化不大。当然,任何错误也可能在调用 kmem_cache_alloc 之前的几百行代码中。我真的不知道这会出什么问题。
  • @MatsPetersson 好的,感谢您的帮助!

标签: c linux numa


【解决方案1】:

查看Linux内核源码,可以得到EINVAL:

  • 传入无效的模式值。超出“不一致”范围(同时使用静态和相对节点)
  • 无效的最大节点(> 一页中的位数 -> 在 x86 上为 32K)。
  • 节点掩码的各种其他问题。
  • 没有MPOL_MF_STRICT | MPOL_MF_MOVE | MPOL_MF_MOVE_ALL 之一
  • start 不是页面对齐的。
  • start+len 当页面对齐 = 开始时。 [也就是说,你的 len 至少不是一个字节]
  • start+len start - 即负长度。
  • policy = MPOL_DEFAULTnodes 不为空或 NULL
  • 引用来源的评论“如果节点掩码为空(本地分配),则 MPOL_PREFERRED 不能与 MPOL_F_STATIC_NODES 或 MPOL_F_RELATIVE_NODES 一起使用。所有其他模式都需要指向非空节点掩码的有效指针。

我的猜测是 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。我认为您的系统中实际上有多个节点。

我还将最后一次mbind 调用的“剩余”从A[] 移动到piece+remnant 大小。

【讨论】:

  • 我运行它的大小为 6156000,我得到piece=2051584,aligned_size=2051584,remnant=1248。谢谢。
  • 所以,让我们计算一下:6156000 是 769500 双倍。每组应有 256500 个双打。但这不是偶数页。 256500 是。那是2048000。这意味着使用“aligned_size”时第二个开始不会对齐。您能否将计算结果粘贴到您的问题中以得到对齐大小和剩余部分。
  • "split_three=num_items/3;aligned_size=(split_three/objs_per_page)*objs_per_page;remnant=num_items-(aligned_size*3);piece=aligned_size;"谢谢。
  • 请将其作为您的问题的一部分发布!并包括“objs_per_page”计算。
  • 谢谢。我确实编译并运行了上面的代码。对于第二次和第三次 mbind 调用,我将 nodemask 更改为 2 和 4。有时它运行良好,但有时它会出现分段错误。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-01
  • 2014-05-23
  • 2018-09-10
  • 1970-01-01
相关资源
最近更新 更多