如何解决为什么带有 MAP_POPULATE 的匿名大页 mmap 需要这么多时间?
我想评估page fault的开销,所以我设置了实验:mmap匿名64GB内存,然后随机走2MB大页面。对于页面遍历,我 random_shuffle
遍历顺序,并写入每个页面的第一个字节。为了研究页面错误的成本,我在使用和不使用 MAP_POPULATE
的情况下执行 mmap。
但是,我发现带有 MAP_POPULATE
的 mmap 花费了不合理的长时间。结果如下
using 2MB huge page
with populate:
mmap takes 27 s
page walk takes 9.5 ms
without populate:
mmap takes 31 us
page walk takes 146 ms
带 MAP_POPULATE
的 mmap 的成本是 27 秒,比不带 MAP_POPULATE
的 mmap 加上翻页时间长几个数量级。我知道 MAP_POPULATE
会为映射预先设置页表,但 27s 太长而不合理。
更新:
我关闭了大页面并使用 4KB 常规页面代替。结果现在是合理的:
using 4KB pages
with populate:
mmap: 27s
walk: 4.8s
total: ~32s
without populate:
mmap: 13 us
walk: 32s
total: ~32s
那么,为什么使用大页面会导致异常结果?
代码:
代码很短,所以我在下面列出。
#include <stdio.h>
#include <iostream>
#include <sys/mman.h>
#include <algorithm>
#include <random>
#include <chrono>
// MAP_HUGE_2MB is not defined in my system. define it.
#ifndef MAP_HUGE_2MB
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#endif
int main()
{
bool populate = true;
int flag = MAP_ANONYMOUS | MAP_SHARED | MAP_HUGE_2MB;
flag |= populate ? MAP_POPULATE : 0;
size_t size = 64ull * 1024 * 1024 * 1024;
size_t page_size = 2 * 1024 * 1024;
auto Now = std::chrono::steady_clock::Now();
void *m = mmap(NULL,size,PROT_READ | PROT_WRITE,flag,-1,0);
if (m == MAP_Failed)
{
fprintf(stderr,"Failed to mmap: errno: %d\n",errno);
return 0;
}
auto then = std::chrono::steady_clock::Now();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(then - Now)
.count();
std::cout << "mmap time(ns): " << ns << ",populate: " << populate << std::endl;
// randomized page walk
size_t times = size / page_size;
std::vector<int> walk_order;
// generate the randomized walk order
walk_order.reserve(times);
for (size_t t = 0; t < times; ++t)
{
walk_order.push_back(t);
}
std::random_shuffle(walk_order.begin(),walk_order.end());
Now = std::chrono::steady_clock::Now();
// walk the page
for (auto t: walk_order)
{
char *target = (char *) m + t * page_size;
*target = 'a';
}
then = std::chrono::steady_clock::Now();
ns = std::chrono::duration_cast<std::chrono::nanoseconds>(then - Now)
.count();
fprintf(stderr,"walk ns: %ld\n",ns);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。