/* forkcost.c - fork cost vs touched memory; COW and zero-fill fault costs. C89. usage: forkcost MB [reps] */ #include #include #include #include #include #include #include static double now(void) { struct timeval tv; gettimeofday(&tv, 0); return tv.tv_sec + tv.tv_usec / 1e6; } static int cmp(const void *a, const void *b) { double x = *(const double *)a, y = *(const double *)b; return x < y ? -1 : x > y; } int main(int argc, char **argv) { long mb = argc > 1 ? atol(argv[1]) : 0, reps = argc > 2 ? atol(argv[2]) : 20; long bytes = mb << 20, pg = sysconf(_SC_PAGESIZE), i, npg = bytes / pg; char *buf = 0, *mm; double t0, t1, times[1000], med; pid_t pid; int st; if (reps > 1000) reps = 1000; if (bytes) { buf = malloc(bytes); if (!buf) { perror("malloc"); return 1; } t0 = now(); for (i = 0; i < npg; i++) buf[i * pg] = 1; t1 = now(); printf("zero-fill touch %ld pages %.1f us/page\n", npg, (t1 - t0) * 1e6 / npg); /* second pass: no faults, the loop's own cost */ t0 = now(); for (i = 0; i < npg; i++) buf[i * pg] = 2; t1 = now(); printf("retouch %ld pages %.2f us/page\n", npg, (t1 - t0) * 1e6 / npg); mm = mmap(0, bytes, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); if (mm != MAP_FAILED) { t0 = now(); for (i = 0; i < npg; i++) mm[i * pg] = 1; t1 = now(); printf("mmap-anon touch %ld pages %.1f us/page\n", npg, (t1 - t0) * 1e6 / npg); munmap(mm, bytes); } else perror("mmap"); } for (i = 0; i < reps; i++) { t0 = now(); pid = fork(); if (pid == 0) _exit(0); t1 = now(); waitpid(pid, &st, 0); times[i] = t1 - t0; } qsort(times, reps, sizeof(double), cmp); med = times[reps / 2]; printf("fork %ld MB touched min %.0f us median %.0f us\n", mb, times[0] * 1e6, med * 1e6); if (bytes) { /* child writes every inherited page: COW faults */ int fd[2]; double cow; pipe(fd); pid = fork(); if (pid == 0) { t0 = now(); for (i = 0; i < npg; i++) buf[i * pg] = 3; t1 = now(); cow = (t1 - t0) * 1e6 / npg; write(fd[1], &cow, sizeof cow); _exit(0); } read(fd[0], &cow, sizeof cow); waitpid(pid, &st, 0); printf("child COW write %ld pages %.1f us/page\n", npg, cow); } return 0; }