2013-08-02 17 views
1

我有一个2个问题:将每个线程的内存页在NUMA架构

(我)假设线程X在CPU运行Y.是否可以使用系统调用migrate_pages - 甚至更好move_pages(或他们的libnuma包装) - 将与X相关的页面移动到Y所连接的节点?

这个问题棱,因为这两个系统调用的第一个参数是PID(我需要每个线程的方法对于一些研发我做)

(二)积极回答为(I)的情况下,我怎么能得到一些线程使用的所有页面?我的目标是,移动包含数组M []的页面,例如...为了使用上面的系统调用,如何将数据结构与其内存页面“链接”?

一个额外的信息:我用pthreads使用C.提前致谢 !

+1

一般来说,当内核系统调用被记录为采用“pid”参数时,您应该不相信该手册并进行更多的研究。几乎所有这些系统调用实际上都带有时间戳。不幸的是,许多文档是由不知道差别的人编写的... –

+0

非常感谢..我用TID尝试过,它的工作原理! – guipy

回答

1

您想要使用更高级别的接口libnuma而不是低级系统调用。

libnuma库为Linux内核支持的NUMA(非统一内存访问)策略提供了一个简单的编程接口。在NUMA架构上,某些内存区域的延迟或带宽与其他区域不同。可用策略是页面交织(即,以循环方式从系统上的所有节点或子集分配),优选节点分配(即,优选地在特定节点上分配),本地分配(即,在任务当前正在执行的节点上分配)或仅分配在特定节点上(即,在可用节点的某个子集上分配)。也可以将任务绑定到特定节点。

man pages for the low level numa_* system calls警告你远离使用它们:

链接与-lnuma获得系统调用的定义。 libnuma和所需的<numaif.h>标头可在numactl包中找到。

但是,应用程序不应该直接使用这些系统调用。建议使用numactl包中的numa(3)函数提供的更高级别的接口。该numactl包可在<ftp://oss.sgi.com/www/projects/libnuma/download/>。该软件包也包含在一些Linux发行版中。一些发行版包含独立的numactl-devel软件包中的开发库和头文件。

+0

好吧......我明白这一点。系统调用的优点是,我不需要链接-lnuma。 – guipy

+1

@guipy:无论漂浮你的船。我个人发现,直接调用'sbrk()'可以避免与C库链接。 – jxh

1

下面是我用于将线程固定到单个CPU并将堆栈移动到相应的NUMA节点(略微适用于删除某些在其他地方定义的常量)的代码。请注意,我首先正常创建线程,然后从线程内调用以下SetAffinityAndRelocateStack()。我认为这样做会更好,然后尝试创建自己的堆栈,因为堆栈在达到底部的情况下对增长有特别的支持。

该代码也可以适应从外部对新创建的线程进行操作,但这可能会导致竞争条件(例如,如果线程在其堆栈中执行I/O),所以我不会推荐它。

void* PreFaultStack() 
{ 
    const size_t NUM_PAGES_TO_PRE_FAULT = 50; 
    const size_t size = NUM_PAGES_TO_PRE_FAULT * numa_pagesize(); 
    void *allocaBase = alloca(size); 
    memset(allocaBase, 0, size); 
    return allocaBase; 
} 

void SetAffinityAndRelocateStack(int cpuNum) 
{ 
    assert(-1 != cpuNum); 
    cpu_set_t cpuset; 
    CPU_ZERO(&cpuset); 
    CPU_SET(cpuNum, &cpuset); 
    const int rc = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); 
    assert(0 == rc); 

    pthread_attr_t attr; 
    void *stackAddr = nullptr; 
    size_t stackSize = 0; 
    if ((0 != pthread_getattr_np(pthread_self(), &attr)) || (0 != pthread_attr_getstack(&attr, &stackAddr, &stackSize))) { 
     assert(false); 
    } 

    const unsigned long nodeMask = 1UL << numa_node_of_cpu(cpuNum); 
    const auto bindRc = mbind(stackAddr, stackSize, MPOL_BIND, &nodeMask, sizeof(nodeMask), MPOL_MF_MOVE | MPOL_MF_STRICT); 
    assert(0 == bindRc); 

    PreFaultStack(); 
    // TODO: Also lock the stack with mlock() to guarantee it stays resident in RAM 
    return; 
}