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
根据这个内核,
move\u pages()
将调用do\u pages\u move()
来移动页面,但我看不出它是如何间接调用的
因此,我的问题是:
移动页面()
移动页面吗?如果是,在传递页面地址数组时,页面边界是4KB还是2MB?5年前似乎有一个支持移动hugepages的计划move\u pages()
无法移动hugepages,如何移动hugepagesmove_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;i std::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”来查询任何内存的状态。数组应该列出要检查的内存区域的每个小页面
如果您知道任何可靠的方法来检查内存是否映射到大页面,您可以查询大页面中的任何小页面。我认为,如果您可以将物理地址从内核导出到用户空间(例如使用一些),则可能有概率方法:对于大页面虚拟和物理