$ make test
./test-fork-exec-memset
vfork-exec-memset: using vfork
Performance counter stats for './vfork-exec-memset':
244,243 page-faults:u
244,243 minor-faults:u
0 major-faults:u
0.803667298 seconds time elapsed
0.200547000 seconds user
0.595543000 seconds sys
Performance counter stats for './fork-exec-memset':
488,411 page-faults:u
488,411 minor-faults:u
0 major-faults:u
1.322967201 seconds time elapsed
0.288548000 seconds user
1.004638000 seconds sys
Last active
April 5, 2023 19:22
-
-
Save scottt/bd56a0b5d45cb77c17d69fafbc095985 to your computer and use it in GitHub Desktop.
Memory stores cause minor page faults after fork() but not after vfork() on Linux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Memory stores cause minor page faults after fork() but not after vfork() on Linux | |
// See discussion in https://twitter.com/offlinemark/status/1643348064835612672 | |
#include <stdlib.h> | |
#include <string.h> | |
#include <libgen.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <errno.h> | |
#include <sys/wait.h> | |
enum { gigabyte = 1000000000 }; | |
char *program_name; | |
enum { FORK_EXEC_USE_VFORK = 1 }; | |
int fork_exec(char * const program, int flags) | |
{ | |
int r, wstatus; | |
pid_t pid; | |
if (flags & FORK_EXEC_USE_VFORK) { | |
pid = vfork(); | |
} else { | |
pid = fork(); | |
} | |
char * const argv[] = { NULL }; | |
if (pid == 0) { | |
r = execvp(program, argv); | |
if (r != 0) { | |
fprintf(stderr, "execvp: %s\n", strerror(errno)); | |
} | |
} else { | |
int options = 0; | |
r = waitpid(pid, &wstatus, options); | |
if (r == -1) { | |
fprintf(stderr, "waitpid: %s\n", strerror(errno)); | |
return r; | |
} | |
return wstatus; | |
} | |
return -1; | |
} | |
int main(int argc, char **argv) | |
{ | |
program_name = basename(argv[0]); | |
volatile char *buf = malloc(gigabyte); | |
memset(buf, 0x55, gigabyte); | |
// fprintf(stderr, "program_name: %s\n", program_name); | |
if (strstr(program_name, "vfork-")) { | |
fprintf(stderr, "%s: using vfork\n", program_name); | |
fork_exec("true", FORK_EXEC_USE_VFORK); | |
} else { | |
fork_exec("true", 0); | |
} | |
memset(buf, 0xaa, gigabyte); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CFLAGS := -Wall -Og | |
PROGRAMS := fork-exec-memset vfork-exec-memset | |
.PHONY: all | |
all: $(PROGRAMS) | |
.PHONY: test | |
test: all | |
./test-fork-exec-memset | |
vfork-exec-memset: fork-exec-memset | |
ln -sf $< $@ | |
.PHONY: clean | |
clean: | |
rm -f $(PROGRAMS) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
for i in vfork-exec-memset fork-exec-memset ; do | |
perf stat -e page-faults,minor-faults,major-faults -- ./$i | |
done | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I had to compile with
-Og
instead of-Os
to keep the secondmemset()
call from being optimized out by GCC.