/* Measure Linux (or whatever) fork/exit/wait overhead (see also * syscallovh.c). fork/exit/wait for this program takes about 670 μs * on my laptop, or about 130 μs if compiled with dietlibc. This * number starts to rise once we have more than 100K of data; at 1M * it’s at 300–500 μs, at 10M it’s 600–700 μs, at 100M it’s 3 ms (or 1 * ms after rebooting), at 1G it kills my laptop. On a Linode server * on theoretically a 2.3 GHz E5-2697 Xeon, it takes 130 μs compiled * with glibc, and also starts to slow down past 100K. */ #define _BSD_SOURCE #include #include #include #include #include #include #include #include char *devzero = "/dev/zero"; int main(int argc, char **argv) { int n = atoi(argv[1]); size_t s = atoi(argv[2]); char *c = malloc(s); if (!c) { perror("malloc"); return 1; } int fd = open(devzero, O_RDONLY); if (fd < 0) { perror(devzero); return 1; } int m = read(fd, c, s); m = m; /* placate compiler */ struct rusage pre_usage, post_usage; getrusage(RUSAGE_CHILDREN, &pre_usage); for (int i = 0; i < n; i++) { int err = fork(); if (err == 0) { exit(0); } else if (err < 0) { perror("fork"); return 1; } else { int status; wait(&status); } } getrusage(RUSAGE_CHILDREN, &post_usage); struct timeval diff; timersub(&post_usage.ru_utime, &pre_usage.ru_utime, &diff); printf("%ld.%06ld s user, ", (long)diff.tv_sec, (long)diff.tv_usec); timersub(&post_usage.ru_stime, &pre_usage.ru_stime, &diff); printf("%ld.%06ld s system\n", (long)diff.tv_sec, (long)diff.tv_usec); #define longfield(fieldname) printf( \ #fieldname ": %ld - %ld = %ld (÷%d = %f)\n", \ post_usage.fieldname, pre_usage.fieldname, \ post_usage.fieldname - pre_usage.fieldname, \ n, \ (post_usage.fieldname - pre_usage.fieldname) / (double)n) longfield(ru_minflt); longfield(ru_majflt); longfield(ru_nswap); longfield(ru_inblock); longfield(ru_oublock); longfield(ru_msgsnd); longfield(ru_msgrcv); longfield(ru_nsignals); longfield(ru_nvcsw); longfield(ru_nivcsw); return 0; }