cosmopolitan/examples/spawn_bench.c
2024-09-11 03:49:29 -07:00

142 lines
4.1 KiB
C

#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include <spawn.h>
#include <stdalign.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#define ITERATIONS 10
alignas(128) int a;
alignas(128) int b;
alignas(128) atomic_int lock;
static struct timespec SubtractTime(struct timespec a, struct timespec b) {
a.tv_sec -= b.tv_sec;
if (a.tv_nsec < b.tv_nsec) {
a.tv_nsec += 1000000000;
a.tv_sec--;
}
a.tv_nsec -= b.tv_nsec;
return a;
}
static time_t ToNanoseconds(struct timespec ts) {
return ts.tv_sec * 1000000000 + ts.tv_nsec;
}
static char *Ithoa(char p[27], unsigned long x) {
char m[26];
unsigned i;
i = 0;
do {
m[i++] = x % 10 + '0';
x = x / 10;
} while (x);
for (;;) {
*p++ = m[--i];
if (!i)
break;
if (!(i % 3))
*p++ = ',';
}
*p = '\0';
return p;
}
#define BENCH(name, x) \
{ \
int i; \
char ibuf[27]; \
struct timespec t1, t2; \
clock_gettime(CLOCK_REALTIME, &t1); \
for (i = 0; i < ITERATIONS; ++i) { \
x; \
} \
clock_gettime(CLOCK_REALTIME, &t2); \
Ithoa(ibuf, ToNanoseconds(SubtractTime(t2, t1)) / ITERATIONS); \
printf("%-50s %16s ns\n", name, ibuf); \
}
void PosixSpawnWait(const char *prog) {
int ws, err, pid;
char *args[] = {(char *)prog, 0};
char *envs[] = {0};
if ((err = posix_spawn(&pid, prog, NULL, NULL, args, envs))) {
perror(prog);
exit(1);
}
if (waitpid(pid, &ws, 0) == -1) {
perror("waitpid");
exit(1);
}
if (!(WIFEXITED(ws) && WEXITSTATUS(ws) == 42)) {
puts("bad exit status");
exit(1);
}
}
void ForkExecWait(const char *prog) {
int ws;
if (!fork()) {
execve(prog, (char *[]){(char *)prog, 0}, (char *[]){0});
_Exit(127);
}
if (wait(&ws) == -1) {
perror("wait");
exit(1);
}
if (!(WIFEXITED(ws) && WEXITSTATUS(ws) == 42)) {
puts("bad exit status");
exit(1);
}
}
char *FillMemory(char *p, long n) {
return memset(p, -1, n);
}
char *(*pFillMemory)(char *, long) = FillMemory;
int main(int argc, char *argv[]) {
long n;
void *p;
const char *prog;
// if you need the tiny64 program for windows:
//
// make -j o//tool/hello/life-pe.ape
// scp o//tool/hello/life-pe.ape windows:tiny64
//
if (argc <= 1) {
prog = "tiny64";
} else {
prog = argv[1];
}
BENCH("fork() + exec(tiny)", ForkExecWait(prog));
BENCH("posix_spawn(tiny)", PosixSpawnWait(prog));
n = 128L * 1024 * 1024;
p = pFillMemory(
mmap(0, n, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0), n);
BENCH("mmap(128mb, MAP_SHARED) + fork() + exec(tiny)", ForkExecWait(prog));
BENCH("mmap(128mb, MAP_SHARED) + posix_spawn(tiny)", PosixSpawnWait(prog));
munmap(p, n);
n = 128L * 1024 * 1024;
p = pFillMemory(malloc(n), n);
BENCH("malloc(128mb) + fork() + exec(tiny)", ForkExecWait(prog));
BENCH("malloc(128mb) + posix_spawn(tiny)", PosixSpawnWait(prog));
free(p);
}