user16363840
user16363840

Reputation:

C++ How Many Page-Faults are Created with COW?

I have seen this question online, and am not sure if my answer is correct or not:

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

#define N 100*1024*1024
int a[N];

int main() {
    if (fork() > 0) {
        wait(nullptr);
    } else {
        for (unsigned int i = 0; i < N; ++i) {
            a[i] = 1;
        }
    }
    return 0;
}

The question was:

Considering COW technique is enabled in x86-64 OS (With a page size of 4KB = 4096B) how many page faults the child process creates during its whole runtime. (Not looking for very exact answer)

  1. 1024*1
  2. 1024*10
  3. 1024*100
  4. 1024*1024
  5. 1024*1024*10
  6. 1024*1024*100

I think the correct one is 6 since we will try to copy N elements each time the child process tries to write to a write-protected location in memory. Am I right?

I tried to run strace with my program, and it seems none are correct, as the output didn't contain any thousands of lines representing each page fault:

strace ./a.out
execve("./a.out", ["./a.out"], 0x7ffd84f9ace0 /* 50 vars */) = 0
brk(NULL)                               = 0x55c515202000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=96020, ...}) = 0
mmap(NULL, 96020, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f93cbf68000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030928, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93cbf66000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f93cb966000
mprotect(0x7f93cbb4d000, 2097152, PROT_NONE) = 0
mmap(0x7f93cbd4d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f93cbd4d000
mmap(0x7f93cbd53000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f93cbd53000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f93cbf674c0) = 0
mprotect(0x7f93cbd4d000, 16384, PROT_READ) = 0
mprotect(0x55c4fb12b000, 4096, PROT_READ) = 0
mprotect(0x7f93cbf80000, 4096, PROT_READ) = 0
munmap(0x7f93cbf68000, 96020)           = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f93cbf67790) = 3341
wait4(-1, NULL, 0, NULL)                = 3341
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3341, si_uid=1000, si_status=0, si_utime=19, si_stime=35} ---
exit_group(0)                           = ?
+++ exited with 0 +++

Upvotes: 2

Views: 278

Answers (1)

datenwolf
datenwolf

Reputation: 162327

Page faults don't show up in strace; they are not even something that happens "explicitly".

A page fault happens every time a piece of memory is accessed for which the assigned physical page is either not created yet, or mapped into the address space.

In practice the number of page faults for your program is sizeof(int)*N/pagesize. Explanation:

The array a is created in the global .data segment, but default initialized. .data is mapped MAP_ANONYMOUS once, at process start, and by virtue of population-initialization it's zeroing will happen on the first page fault. Since the parent process never accesses the array a, no single page fault for the address space occupied by a will happen in the parent process.

The only process that will cause page faults on a is the child process. However a page fault happens only for the first access of a previously non-resident page. Since a is traversed sequentially the pagefaults on a will only happen on those accessed where 0 == ((uintptr_t)&a[i]) % pagesize (assuming uintptr_t cast pointers correspond exactly to addresses, which on most platforms, they do).

Of course in a system with high memory pressure the system might thrash, thus swapping out the page, before the iterator reached the next page, thus creating additional page faults.

Upvotes: 1

Related Questions