Как предотвратить ошибки страницы после выхода ребенка? - PullRequest
0 голосов
/ 28 мая 2019

Хорошим способом создания моментального снимка процесса является использование fork() для создания дочернего процесса.Память дочернего процесса будет копией родительского процесса.

Вместо того, чтобы активно копировать всю память, ОС просто помечает страницы как копирование при записи : страницыбудет клонирован, если событие одного из процессов записывает в него.Это экономит время и пространство, и это здорово.

В случае выхода из дочернего процесса поведение copy-on-write должно быть отключено.Тем не менее, я получаю ошибки страницы для всего массива - есть ли способ оптимизировать эти ошибки страницы?например, аналогично тому, как MAP_POPULATE позволяет избежать сбоев страниц при начальном доступе к страницам отображаемой области.


Ниже приведен простой тест, демонстрирующий поведение, которое я выполняю.спрашивать о.Я проверяю ошибки страниц через perf stat -e minor-faults,major-faults ./a.out.

Если дочерний процесс не создан (WITH_CHILD установлен на false), у меня очень мало ошибок страниц (около 125 и постоянных).Однако, просто создавая и пожирая дочерний процесс, я получаю ошибки страниц во всем (около 131260, пропорционально размеру массива). Поскольку страницы отображаются одним процессом, я не ожидал бы, что возникнут сбои страниц!Почему они?

Это продолжение Копирование ядра CoW-страниц после завершения дочернего процесса .

#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);
}
...