Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用move_pages()移动hugepages?_C++_Linux_Numa_Huge Pages - Fatal编程技术网

C++ 使用move_pages()移动hugepages?

C++ 使用move_pages()移动hugepages?,c++,linux,numa,huge-pages,C++,Linux,Numa,Huge Pages,这个问题是为了: 内核3.10.0-1062.4.3.el7.x86_64 通过引导参数分配的非透明hugepages,可能映射到文件,也可能不映射到文件(例如,已装入的hugepages) x86_64 根据这个内核,move\u pages()将调用do\u pages\u move()来移动页面,但我看不出它是如何间接调用的 因此,我的问题是: 可以移动页面()移动页面吗?如果是,在传递页面地址数组时,页面边界是4KB还是2MB?5年前似乎有一个支持移动hugepages的计划 如果mov

这个问题是为了:

  • 内核3.10.0-1062.4.3.el7.x86_64
  • 通过引导参数分配的非透明hugepages,可能映射到文件,也可能不映射到文件(例如,已装入的hugepages)
  • x86_64

  • 根据这个内核,
    move\u pages()
    将调用
    do\u pages\u move()
    来移动页面,但我看不出它是如何间接调用的

    因此,我的问题是:

  • 可以
    移动页面()
    移动页面吗?如果是,在传递页面地址数组时,页面边界是4KB还是2MB?5年前似乎有一个支持移动hugepages的计划
  • 如果
    move\u pages()
    无法移动hugepages,如何移动hugepages
  • 移动hugepages后,我可以像查询这样的常规页面一样查询hugepages的NUMA ID吗
  • 根据下面的代码,我似乎是通过
    move_pages()
    以页面大小=2MB的方式移动hugepages,但这是正确的方式吗

    #include <cstdint>
    #include <iostream>
    #include <numaif.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <unistd.h>
    #include <string.h>
    #include <limits>
    
    int main(int argc, char** argv) {
            const int32_t dst_node = strtoul(argv[1], nullptr, 10);
            const constexpr uint64_t size = 4lu * 1024 * 1024;
            const constexpr uint64_t pageSize = 2lu * 1024 * 1024;
            const constexpr uint32_t nPages = size / pageSize;
            int32_t status[nPages];
            std::fill_n(status, nPages, std::numeric_limits<int32_t>::min());;
            void* pages[nPages];
            int32_t dst_nodes[nPages];
            void* ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB, -1, 0);
    
            if (ptr == MAP_FAILED) {
                    throw "failed to map hugepages";
            }
            memset(ptr, 0x41, nPages*pageSize);
            for (uint32_t i = 0; i < nPages; i++) {
                    pages[i] = &((char*)ptr)[i*pageSize];
                    dst_nodes[i] = dst_node;
            }
    
            std::cout << "Before moving" << std::endl;
    
            if (0 != move_pages(0, nPages, pages, nullptr, status, 0)) {
                std::cout << "failed to inquiry pages because " << strerror(errno) << std::endl;
            }
            else {
                    for (uint32_t i = 0; i < nPages; i++) {
                            std::cout << "page # " << i << " locates at numa node " << status[i] << std::endl;
                    }
            }
    
            // real move
            if (0 != move_pages(0, nPages, pages, dst_nodes, status, MPOL_MF_MOVE_ALL)) {
                    std::cout << "failed to move pages because " << strerror(errno) << std::endl;
                    exit(-1);
            }
    
            const constexpr uint64_t smallPageSize = 4lu * 1024;
            const constexpr uint32_t nSmallPages = size / smallPageSize;
            void* smallPages[nSmallPages];
            int32_t smallStatus[nSmallPages] = {std::numeric_limits<int32_t>::min()};
            for (uint32_t i = 0; i < nSmallPages; i++) {
                    smallPages[i] = &((char*)ptr)[i*smallPageSize];
            }
    
    
            std::cout << "after moving" << std::endl;
            if (0 != move_pages(0, nSmallPages, smallPages, nullptr, smallStatus, 0)) {
                std::cout << "failed to inquiry pages because " << strerror(errno) << std::endl;
            }
            else {
                    for (uint32_t i = 0; i < nSmallPages; i++) {
                            std::cout << "page # " << i << " locates at numa node " << smallStatus[i] << std::endl;
                    }
            }
    
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    int main(int argc,字符**argv){
    const int32_t dst_node=strtoul(argv[1],nullptr,10);
    const constexpr uint64_t size=4lu*1024*1024;
    const constexpr uint64_t pageSize=2lu*1024*1024;
    const constexpr uint32\u t nPages=大小/页面大小;
    国际地位[nPages];
    std::fill_n(状态、nPages、std::numeric_limits::min());;
    作废*页[n页];
    int32_t dst_节点[nPages];
    void*ptr=mmap(空,大小,保护读取|保护写入,映射匿名|映射私有|映射HUGETLB,-1,0);
    如果(ptr==MAP_失败){
    抛出“映射hugepages失败”;
    }
    内存集(ptr,0x41,nPages*pageSize);
    对于(uint32_t i=0;istd::cout对于原始版本的3.10 linux内核(不是redhat补丁,因为我没有rhel内核的LXR),将强制将巨大的页面(2MB;THP和hugetlbfs样式)拆分为小页面(4KB)。move_页面使用过短的块(如果计算正确,大约0.5MB),函数图如下所示:

    移动页面
    。->
    迁移页面
    ->
    取消映射并移动
    ->

    static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                struct page *page, int force, enum migrate_mode mode)
    {
        struct page *newpage = get_new_page(page, private, &result);
        ....
        if (unlikely(PageTransHuge(page)))
            if (unlikely(split_huge_page(page)))
                goto out;
    
    PageTranshugg
    为两种hugepages(thp和LibHugetLB)返回true:

    PAGETRANSHARGE()对于透明巨型和hugetlbfs页面都返回true,但对于普通页面不返回true

    split\u-ground\u-page
    调用
    split\u-ground\u-page\u至\u列表

    将hugepage拆分为普通页面。这不会更改首页的位置

    Split还将发出类型为
    THP_Split
    的vm_事件计数器增量。计数器在
    /proc/vmstat
    ()中导出。您可以在测试前后检查此计数器
    cat/proc/vmstat | grep THP_Split

    在3.10版本中,有一些用于hugepage迁移的代码,如
    unmap\u和\u move\u ground\u page
    函数,它不是从
    move\u page
    调用的。在3.10版本中,只有从
    soft\u offline\u ground\u page
    \u soft\u offline\u page
    )(添加):

    通过迁移或失效使页面软脱机, 不杀任何东西。这是为了 页面尚未损坏(因此仍然可以访问), 但是已经纠正了一些错误,最好采取 出去

    答复:

    是否可以移动页面()移动hugepages?如果可以,在传递页面地址数组时,页面边界应该是4KB还是2MB?5年前似乎有一个支持移动hugepages的补丁

    标准3.10内核具有move_页面,该页面将接受4KB页面指针的数组“pages”,它将中断(拆分)巨大的页面变成512个小页面,然后它会迁移小页面。它们被thp合并回来的可能性非常低,因为move_页面会对物理内存页面进行单独的请求,并且它们几乎总是不连续的

    不要给“2MB”指针,它仍然会分割所提到的每一个大页面,并且只迁移这个内存的第一个4KB小页面

    2013修补程序未添加到原始3.10内核中

    • v2“扩展hugepage迁移”(3.9)
    • v3(3.11)
    • v4(例如,单击相关以访问单个修补程序)
    该补丁似乎在2013年9月被接受:

    如果move_pages()无法移动hugepages,如何移动hugepages

    move_pages
    将把hugepages中的数据作为小页面移动。您可以:在正确的numa节点以手动模式分配大页面并复制您的数据(如果您想保留虚拟地址,请复制两次);或者使用补丁将内核更新到某个版本,并使用补丁作者的方法和测试。他的测试副本有: (是必需的)

    现在我不知道如何启动测试以及如何检查它是否正常工作。对于
    /test\u move\u pages-v-m private-h 2048
    使用最新内核运行,它不会增加THP\u SPLIT counter

    他的测试与我们的测试非常相似:mmap,memset到错误页面,用指向小页面的指针填充页面数组,
    numa\u move\u pages

    移动hugepages后,我可以像查询常规页面一样查询hugepages的NUMA ID吗

    您可以通过在查询模式下(使用空节点)向
    move\u pages
    syscall提供正确的数组“pages”来查询任何内存的状态。数组应该列出要检查的内存区域的每个小页面

    如果您知道任何可靠的方法来检查内存是否映射到大页面,您可以查询大页面中的任何小页面。我认为,如果您可以将物理地址从内核导出到用户空间(例如使用一些),则可能有概率方法:对于大页面虚拟和物理