子退出后如何防止页面错误?

时间:2019-05-28 19:53:30

标签: linux memory fork copy-on-write

创建进程快照的一种好方法是使用fork()创建一个子进程。子进程的内存将是父进程的副本。

操作系统并没有急切地复制所有内存,而是只是将页面标记为写时复制:如果其中一个进程写入了该事件,则将克隆这些页面。这样既节省时间又节省空间。

如果子进程退出,则应禁用写时复制行为。但是,我遇到了整个阵列的页面错误-有什么方法可以优化这些页面错误吗?例如类似于MAP_POPULATE如何避免首次访问映射区域的页面时出现页面错误。


下面有一个简单的基准,可以演示我要询问的行为。我通过perf stat -e minor-faults,major-faults ./a.out检查页面错误。

如果未创建子进程(WITH_CHILD设置为false),则页面错误很少(大约125和常量)。但是,仅通过创建并获得子进程,我就会在所有内容中遇到页面错误(大约131260,与数组大小成比例)。 由于页面是通过单个进程映射的,所以我不会期望发生任何页面错误!为什么呢?

这是Kernel copying CoW pages after child process exit的后续行动。

#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <array>
#include <cassert>
#include <cstring>
#include <iostream>

#define ARRAY_SIZE 536870912  // 512MB
#define WITH_CHILD true

using inttype = uint64_t;

constexpr uint64_t NUM_ELEMS() {
  return ARRAY_SIZE / sizeof(inttype);
}

int main() {
  // allocate array
  void *arraybuf = mmap(nullptr, ARRAY_SIZE, PROT_READ | PROT_WRITE,
                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
  assert(arraybuf != nullptr);
  std::array<inttype, NUM_ELEMS()> *array =
    new (arraybuf) std::array<inttype, NUM_ELEMS()>();

#if WITH_CHILD
  // spawn checkpointing process
  int pid = fork();
  assert(pid != -1);

  // child process -- do nothing, just exit
  if (pid == 0) {
    exit(0);
  }

  // wait for child thread to exit
  assert(waitpid(pid, nullptr, 0) == pid);
#endif

  // write to array -- this shouldnt generate page faults, right? :(
  std::fill(array->begin(), array->end(), 0);

  // cleanup
  munmap(array, ARRAY_SIZE);
}

0 个答案:

没有答案