ref: a1c8da91f18c8bd3cdc7ce36c70538969e0c5602
parent: 721724916347c46df7cfa3105ac6fd1f6da652ed
author: Ori <ori@eigenstate.org>
date: Tue Jul 15 12:49:08 EDT 2025
port to linux (with much drudgework done with claude)
--- a/bench.c
+++ b/bench.c
@@ -1,9 +1,13 @@
-#include <u.h>
-#include <tos.h>
-#include <libc.h>
-#include <bench.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include "bench.h"
#define Nsec 1000000000ULL
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define BENCHTIME (Nsec) /* 1s in ns */
typedef struct Hist Hist;
@@ -25,29 +29,21 @@
uvlong
nanosec(void)
{- static uvlong fasthz, xstart;
- uvlong x;
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (uvlong)ts.tv_sec * Nsec + (uvlong)ts.tv_nsec;
+}
- if(fasthz == ~0ULL)
- return nsec() - xstart;
-
- if(fasthz == 0){- if(_tos->cyclefreq){- fasthz = _tos->cyclefreq;
- cycles(&xstart);
- } else {- fasthz = ~0ULL;
- xstart = nsec();
- }
- return 0;
- }
- cycles(&x);
- x -= xstart;
-
- uvlong q = x / fasthz;
- uvlong r = x % fasthz;
-
- return q*Nsec + r*Nsec/fasthz;
+static void
+cycles(uvlong *x)
+{+#if defined(__x86_64__) || defined(__i386__)
+ unsigned int lo, hi;
+ __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi));+ *x = ((uvlong)hi << 32) | lo;
+#else
+ *x = 0; // No cycle counter support on this architecture
+#endif
}
static int
@@ -74,7 +70,7 @@
vlong ns;
int i;
- if(h == nil)
+ if(h == NULL)
return;
ns = b->ns;
for(i = 0; i < nelem(h->bkt) - 1 && ns > 1; i++)
@@ -179,13 +175,13 @@
b->overheadns = 0;
b->overheadcy = 0;
/* warm caches */
- benchrunn(b, 0, nil);
+ benchrunn(b, 0, NULL);
/* measure overhead */
for(i = 0; i < 20; i++){b->ns = 0;
b->bcycles = 0;
- benchrunn(b, 0, nil);
+ benchrunn(b, 0, NULL);
if(i == 0 || b->ns < b->overheadns)
b->overheadns = b->ns;
if(i == 0 || b->bcycles < b->overheadcy)
@@ -192,18 +188,15 @@
b->overheadcy = b->bcycles;
}
- /* do the run */
- h->min = -1;
- h->max = -1;
/* estimate */
benchrunn(b, 1, h);
n = roundup(BENCHTIME, b->ns);
- print("%10d N ", n);- if(h != nil)
+ printf("%10d N ", n);+ if(h != NULL){for(i = 0; i < n; i++)
benchrunn(b, 1, h);
- else
- benchrunn(b, n, nil);
+ }else
+ benchrunn(b, n, NULL);
}
double
@@ -217,8 +210,8 @@
{"μs", 1000}, {"ms", 1000*1000}, {"s", 1000*1000*1000},- {"m", 60*1000*1000*1000},- {"h", 3600*1000*1000*1000},+ {"m", 60LL*1000*1000*1000},+ {"h", 3600LL*1000*1000*1000},};
int i;
@@ -241,23 +234,23 @@
uvlong cyperop;
if(res->N <= 0) {- print("skipped\n");+ printf("skipped\n");return;
}
nsperop = scaletime(res->ns, (vlong)res->N, &unit);
- snprint(tmop, sizeof(tmop), "%12.2f %s/op", nsperop, unit);
+ snprintf(tmop, sizeof(tmop), "%12.2f %s/op", nsperop, unit);
cyperop = res->bcycles / (uvlong)res->N;
if(cyperop < 10)
- snprint(cyop, sizeof(cyop), "%13.2f cy/op", (double)res->bcycles / (double)res->N);
+ snprintf(cyop, sizeof(cyop), "%13.2f cy/op", (double)res->bcycles / (double)res->N);
else if(cyperop < 100)
- snprint(cyop, sizeof(cyop), "%12.1f cy/op", (double)res->bcycles / (double)res->N);
+ snprintf(cyop, sizeof(cyop), "%12.1f cy/op", (double)res->bcycles / (double)res->N);
else
- snprint(cyop, sizeof(cyop), "%10ulld cy/op", cyperop);
+ snprintf(cyop, sizeof(cyop), "%10lu cy/op", cyperop);
- print("%s\t%s\n", tmop, cyop);- if(h != nil){+ printf("%s\t%s\n", tmop, cyop);+ if(h != NULL){ for(i = h->min; i < h->max; i++){if(h->bktmax < 30)
lim = h->bkt[i];
@@ -268,7 +261,7 @@
for(j = 0; j < lim; j++)
bar[j] = '*';
bar[j] = 0;
- print("\t%12lld | %8d %s\n", 1LL<<i, h->bkt[i], bar);+ printf("\t%12lld | %8d %s\n", 1LL<<i, h->bkt[i], bar);}
}
}
@@ -276,8 +269,8 @@
static void
usage(void)
{- fprint(2, "usage: %s [-s]\n", argv0);
- exits("usage");+ fprintf(stderr, "usage: benchmark [-h]\n");
+ exit(1);
}
void
@@ -285,18 +278,23 @@
{char *e;
- if((e = getenv("NPROC")) == nil)- NPROC = 1;
+ if((e = getenv("NPROC")) == NULL)+ NPROC = sysconf(_SC_NPROCESSORS_ONLN);
else
NPROC = atoi(e);
- free(e);
- ARGBEGIN{- case 'h':
- showhist++;
- break;
- default:
- usage();
- }ARGEND;
+ if(e != NULL)
+ free(e);
+
+ int c;
+ while((c = getopt(argc, argv, "h")) != -1) {+ switch(c) {+ case 'h':
+ showhist++;
+ break;
+ default:
+ usage();
+ }
+ }
}
// bench a single function
@@ -314,10 +312,13 @@
if(strncmp(name, "bench", 5) == 0)
name += 5;
- print("%24s\t", name);- benchrun(&b, showhist ? &h : nil);
- benchres(&b, showhist ? &h : nil);
+ printf("%24s\t", name);+ h.min = -1;
+ h.max = -1;
+ benchrun(&b, showhist ? &h : NULL);
+ benchres(&b, showhist ? &h : NULL);
}
+
// bench an array of functions
void
--- a/bench.h
+++ b/bench.h
@@ -1,3 +1,9 @@
+#include <stdint.h>
+#include <unistd.h>
+
+typedef int64_t vlong;
+typedef uint64_t uvlong;
+
typedef struct BItem BItem;
typedef struct B B;
@@ -32,7 +38,7 @@
GiB = 1024*MiB,
};
-#define BM(func) bench("func", func)+#define BM(func) bench(#func, func)
// public api
void benchinit(int, char**);
--- a/fcall.c
+++ b/fcall.c
@@ -1,5 +1,5 @@
-#include <u.h>
-#include <libc.h>
+#include <stdio.h>
+#include <stdlib.h>
#include "bench.h"
@@ -54,16 +54,16 @@
f16(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
}
-void
+int
main(int argc, char **argv)
{benchinit(argc, argv);
- print("== function call overhead ==\n");+ printf("== function call overhead ==\n");BM(fcall0);
BM(fcall1);
BM(fcall4);
BM(fcall16);
- exits(nil);
+ return 0;
}
--- a/fsio.c
+++ b/fsio.c
@@ -1,8 +1,18 @@
-#include <u.h>
-#include <libc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <pthread.h>
#include "bench.h"
+#define IOUNIT 32768
+
char *benchdir;
char randbuf[128*IOUNIT];
@@ -16,21 +26,29 @@
int i, j, n, nrd;
int rfd, wfd;
- if((rfd = open("/dev/random", OREAD)) == -1)- sysfatal("open: %r");- readn(rfd, randbuf, sizeof(randbuf));
+ if((rfd = open("/dev/urandom", O_RDONLY)) == -1) {+ fprintf(stderr, "open: %s\n", strerror(errno));
+ exit(1);
+ }
+ read(rfd, randbuf, sizeof(randbuf));
for(i = 0; i < Nfiles; i++){- snprint(path, sizeof(path), "%s/rfile.%d", benchdir, i);
- if((wfd = create(path, OWRITE, 0666)) == -1)
- sysfatal("create %s: %r", path);+ snprintf(path, sizeof(path), "%s/rfile.%d", benchdir, i);
+ if((wfd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {+ fprintf(stderr, "create %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
for(j = 0; j < Filesz; j += n){nrd = Filesz - j;
if(nrd > sizeof(buf))
nrd = sizeof(buf);
- if((n = readn(rfd, buf, nrd)) != nrd)
- sysfatal("short read");- if(write(wfd, buf, n) != n)
- sysfatal("short write");+ if((n = read(rfd, buf, nrd)) != nrd) {+ fprintf(stderr, "short read\n");
+ exit(1);
+ }
+ if(write(wfd, buf, n) != n) {+ fprintf(stderr, "short write\n");
+ exit(1);
+ }
}
close(wfd);
}
@@ -40,18 +58,21 @@
void
cleanup(void)
{- char buf[512];
- int i, n, fd;
- Dir *d;
+ char path[512];
+ DIR *dir;
+ struct dirent *entry;
- if((fd = open(benchdir, OREAD)) == -1)
- sysfatal("open %s: %r", benchdir);- n = dirreadall(fd, &d);
- for(i = 0; i < n; i++){- snprint(buf, sizeof(buf), "%s/%s", benchdir, d[i].name);
- remove(buf);
+ if((dir = opendir(benchdir)) == NULL) {+ fprintf(stderr, "opendir %s: %s\n", benchdir, strerror(errno));
+ return;
}
- close(fd);
+ while((entry = readdir(dir)) != NULL) {+ if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ continue;
+ snprintf(path, sizeof(path), "%s/%s", benchdir, entry->d_name);
+ unlink(path);
+ }
+ closedir(dir);
}
void
@@ -60,37 +81,63 @@
int fd, j, k, n;
char path[512];
- snprint(path, sizeof(path), "%s/write.%d.%d", benchdir, i, getpid());
- if((fd = create(path, OWRITE, 0666)) == -1)
- sysfatal("create: %r");+ snprintf(path, sizeof(path), "%s/write.%d.%d", benchdir, i, getpid());
+ if((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {+ fprintf(stderr, "create: %s\n", strerror(errno));
+ exit(1);
+ }
for(j = 0; j < nops; j++)
for(k = 0; k < fsz; k += n)
- if((n = write(fd, randbuf, wsz)) != wsz)
- sysfatal("write: %r");+ if((n = write(fd, randbuf, wsz)) != wsz) {+ fprintf(stderr, "write: %s\n", strerror(errno));
+ exit(1);
+ }
close(fd);
- remove(path);
+ unlink(path);
}
+struct worker_data {+ int nops;
+ int i;
+ int fsz;
+ int sz;
+};
+
+static void *
+write_worker(void *arg)
+{+ struct worker_data *wd = arg;
+ dowrite(wd->nops, wd->i, wd->fsz, wd->sz);
+ return NULL;
+}
+
void
writefile(B *b, int npar, int fsz)
{+ pthread_t *threads;
+ struct worker_data *data;
int i, wsz;
wsz = fsz < IOUNIT ? fsz : IOUNIT;
+ threads = malloc(npar * sizeof(pthread_t));
+ data = malloc(npar * sizeof(struct worker_data));
+
for(i = 0; i < npar; i++){- switch(rfork(RFPROC|RFMEM)){- case -1:
- sysfatal("fork: %r");- case 0:
- dowrite(b->N/npar, i, fsz, wsz);
- exits(nil);
- default:
- /* nothing */
- break;
+ data[i].nops = b->N/npar;
+ data[i].i = i;
+ data[i].fsz = fsz;
+ data[i].sz = wsz;
+
+ if(pthread_create(&threads[i], NULL, write_worker, &data[i]) != 0) {+ fprintf(stderr, "pthread_create failed\n");
+ exit(1);
}
}
for(i = 0; i < npar; i++)
- free(wait());
+ pthread_join(threads[i], NULL);
+
+ free(threads);
+ free(data);
}
void
@@ -99,63 +146,99 @@
char path[512], buf[IOUNIT];
int fd, j, k, n;
- snprint(path, sizeof(path), "%s/rfile.%d", benchdir, i);
- if((fd = open(path, OREAD)) == -1)
- sysfatal("open: %r");+ snprintf(path, sizeof(path), "%s/rfile.%d", benchdir, i);
+ if((fd = open(path, O_RDONLY)) == -1) {+ fprintf(stderr, "open: %s\n", strerror(errno));
+ exit(1);
+ }
for(j = 0; j < nops; j++){- seek(fd, 0, 0);
+ lseek(fd, 0, SEEK_SET);
for(k = 0; k < fsz; k += n)
- if((n = readn(fd, buf, rsz)) != rsz)
- sysfatal("read %s [%d < %d]: %r", path, n, rsz);+ if((n = read(fd, buf, rsz)) != rsz) {+ fprintf(stderr, "read %s [%d < %d]: %s\n", path, n, rsz, strerror(errno));
+ exit(1);
+ }
}
close(fd);
}
+static void *
+read_worker(void *arg)
+{+ struct worker_data *rd = arg;
+ doread(rd->nops, rd->i, rd->fsz, rd->sz);
+ return NULL;
+}
+
void
readfile(B *b, int npar, int fsz)
{+ pthread_t *threads;
+ struct worker_data *data;
int i, rsz;
rsz = fsz < IOUNIT ? fsz : IOUNIT;
+ threads = malloc(npar * sizeof(pthread_t));
+ data = malloc(npar * sizeof(struct worker_data));
+
for(i = 0; i < npar; i++){- switch(rfork(RFPROC|RFMEM)){- case -1:
- sysfatal("fork: %r");- case 0:
- doread(b->N/npar, i, fsz, rsz);
- exits(nil);
- default:
- /* nothing */
- break;
+ data[i].nops = b->N/npar;
+ data[i].i = i % Nfiles; // Cycle through available files
+ data[i].fsz = fsz;
+ data[i].sz = rsz;
+
+ if(pthread_create(&threads[i], NULL, read_worker, &data[i]) != 0) {+ fprintf(stderr, "pthread_create failed\n");
+ exit(1);
}
}
for(i = 0; i < npar; i++)
- free(wait());
+ pthread_join(threads[i], NULL);
+
+ free(threads);
+ free(data);
}
void
mixedfile(B *b, int nrd, int nwr, int fsz)
{- int i, sz;
+ pthread_t *threads;
+ struct worker_data *data;
+ int i, sz, total;
sz = fsz < IOUNIT ? fsz : IOUNIT;
- for(i = 0; i < nrd+nwr; i++){- switch(rfork(RFPROC|RFMEM)){- case -1:
- sysfatal("fork: %r");- case 0:
- if(i < nrd)
- doread(b->N/nrd, i, fsz, sz);
- else
- dowrite(b->N/nwr, i, fsz, sz);
- exits(nil);
- default:
- /* nothing */
- break;
+ total = nrd + nwr;
+ threads = malloc(total * sizeof(pthread_t));
+ data = malloc(total * sizeof(struct worker_data));
+
+ for(i = 0; i < total; i++){+ data[i].fsz = fsz;
+ data[i].sz = sz;
+
+ if(i < nrd) {+ data[i].nops = b->N/nrd;
+ data[i].i = i % Nfiles;
+
+ if(pthread_create(&threads[i], NULL, read_worker, &data[i]) != 0) {+ fprintf(stderr, "pthread_create failed\n");
+ exit(1);
+ }
+ } else {+ data[i].nops = b->N/nwr;
+ data[i].i = i - nrd;
+
+ if(pthread_create(&threads[i], NULL, write_worker, &data[i]) != 0) {+ fprintf(stderr, "pthread_create failed\n");
+ exit(1);
+ }
}
}
- for(i = 0; i < nrd+nwr; i++)
- free(wait());
+
+ for(i = 0; i < total; i++)
+ pthread_join(threads[i], NULL);
+
+ free(threads);
+ free(data);
}
void writefile_p1_16b(B *b){ writefile(b, 1, 16); }@@ -192,54 +275,54 @@
void mixedfile_p4(B *b){ mixedfile(b, 2, 2, 16); } void mixedfile_p8(B *b){ mixedfile(b, 4, 4, 16); }-void
+int
main(int argc, char **argv)
{benchinit(argc, argv);
benchdir = getenv("benchdir");- if(benchdir == nil){- fprint(2, "no benchdir: skipping\n");
- exits(nil);
+ if(benchdir == NULL){+ fprintf(stderr, "no benchdir: skipping\n");
+ return 0;
}
setup();
- print("== file writes (16b) ==\n");+ printf("== file writes (16b) ==\n");BM(writefile_p1_16b);
BM(writefile_p2_16b);
BM(writefile_p4_16b);
BM(writefile_p8_16b);
- print("== file writes (16k) ==\n");+ printf("== file writes (16k) ==\n");BM(writefile_p1_16k);
BM(writefile_p2_16k);
BM(writefile_p4_16k);
BM(writefile_p8_16k);
- print("== file writes (16m) ==\n");+ printf("== file writes (16m) ==\n");BM(writefile_p1_16m);
BM(writefile_p2_16m);
BM(writefile_p4_16m);
BM(writefile_p8_16m);
- print("== file reads (16b) ==\n");+ printf("== file reads (16b) ==\n");BM(readfile_p1_16b);
BM(readfile_p2_16b);
BM(readfile_p4_16b);
BM(readfile_p8_16b);
- print("== file reads (16k) ==\n");+ printf("== file reads (16k) ==\n");BM(readfile_p1_16k);
BM(readfile_p2_16k);
BM(readfile_p4_16k);
BM(readfile_p8_16k);
- print("== file reads (16m) ==\n");+ printf("== file reads (16m) ==\n");BM(readfile_p1_16m);
BM(readfile_p2_16m);
BM(readfile_p4_16m);
BM(readfile_p8_16m);
- print("== mixed ops ==\n");+ printf("== mixed ops ==\n");BM(mixedfile_p2);
BM(mixedfile_p4);
BM(mixedfile_p8);
@@ -246,6 +329,6 @@
cleanup();
- exits(nil);
+ return 0;
}
--- a/libc.c
+++ b/libc.c
@@ -1,8 +1,16 @@
-#include <u.h>
-#include <libc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include "bench.h"
+// Prevent inlining of libc functions
+extern void *memcpy(void *dest, const void *src, size_t n) __attribute__((noinline));
+extern void *memmove(void *dest, const void *src, size_t n) __attribute__((noinline));
+extern int memcmp(const void *s1, const void *s2, size_t n) __attribute__((noinline));
+extern void *memset(void *s, int c, size_t n) __attribute__((noinline));
+
char *dst;
char *src;
@@ -106,18 +114,22 @@
{benchinit(argc, argv);
- if((src = malloc(1*GiB + KiB)) == nil)
- sysfatal("malloc: %r");- if((dst = malloc(1*GiB + KiB)) == nil)
- sysfatal("malloc: %r");+ if((src = malloc(1*GiB + KiB)) == NULL) {+ fprintf(stderr, "malloc failed\n");
+ exit(1);
+ }
+ if((dst = malloc(1*GiB + KiB)) == NULL) {+ fprintf(stderr, "malloc failed\n");
+ exit(1);
+ }
- print("== small nops (0 b) ==\n");+ printf("== small nops (0 b) ==\n");BM(benchmemcpy_0b);
BM(benchmemmovedisjoint_16b);
BM(benchmemmoveoverlap_16b);
BM(benchmemcmp_16k);
- print("== small memory ops (16b) ==\n");+ printf("== small memory ops (16b) ==\n");BM(benchmemcpy_16b);
BM(benchmemmoveoverlap_16b);
BM(benchmemmovedisjoint_16b);
@@ -126,7 +138,7 @@
BM(benchmemcmpdiffmid_16b);
BM(benchmemcmpdifftail_16b);
- print("== midsize memory ops (16k) ==\n");+ printf("== midsize memory ops (16k) ==\n");BM(benchmemcpy_16k);
BM(benchmemmoveoverlap_16k);
BM(benchmemmovedisjoint_16k);
@@ -135,7 +147,7 @@
BM(benchmemcmpdiffmid_16k);
BM(benchmemcmpdifftail_16k);
- print("== large memory ops (16m) ==\n");+ printf("== large memory ops (16m) ==\n");BM(benchmemcpy_16m);
BM(benchmemmoveoverlap_16m);
BM(benchmemmovedisjoint_16m);
@@ -144,7 +156,7 @@
BM(benchmemcmpdiffmid_16m);
BM(benchmemcmpdifftail_16m);
- print("== huge memory ops (1g) ==\n");+ printf("== huge memory ops (1g) ==\n");BM(benchmemcpy_1g);
BM(benchmemmoveoverlap_16g);
BM(benchmemmovedisjoint_16g);
@@ -153,6 +165,6 @@
BM(benchmemcmpdiffmid_1g);
BM(benchmemcmpdifftail_1g);
- exits(nil);
+ exit(0);
}
--- a/lock.c
+++ b/lock.c
@@ -1,21 +1,14 @@
-#include <u.h>
-#include <libc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h>
#include "bench.h"
#define NLockIters 1
-typedef struct SLock SLock;
-struct SLock {- long state;
- long sem;
-};
-
-int casl(long *, long, long);
-
-Lock l;
-QLock q;
-SLock s;
+pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
static int count;
void
@@ -32,157 +25,98 @@
count++;
}
-void
-slock(SLock *s)
-{- int i;
- for(i = 0; i < 1000; i++){- if(casl(&s->state, 0, 1))
- return;
- sleep(0);
- }
- if(ainc(&s->state) == 1)
- return;
- while(semacquire(&s->sem, 1) == -1)
- /* retry */;
-}
-
void
-sunlock(SLock *s)
-{- if(adec(&s->state) == 0)
- return;
- semrelease(&s->sem, 1);
-}
-
-void
dolock(void (*work)(void), int n)
{int i;
for(i = 0; i < n; i++){- lock(&l);
+ pthread_mutex_lock(&l);
work();
- unlock(&l);
+ pthread_mutex_unlock(&l);
}
}
-void
-doqlock(void (*work)(void), int n)
-{- int i;
+struct thread_data {+ void (*fn)(void(*)(void), int);
+ void (*work)(void);
+ int ninc;
+ sem_t *start_sem;
+};
- for(i = 0; i < n; i++){- qlock(&q);
- work();
- qunlock(&q);
- }
-}
-
-void
-doslock(void (*work)(void), int n)
+static void *
+thread_worker(void *arg)
{- int i;
-
- for(i = 0; i < n; i++){- slock(&s);
- work();
- sunlock(&s);
- }
+ struct thread_data *td = arg;
+ sem_wait(td->start_sem);
+ td->fn(td->work, td->ninc);
+ return NULL;
}
void
lockbench(void (*fn)(void(*)(void), int), int nthr, void (*work)(void), int ninc)
{- static long thrwait;
- int i, p;
+ pthread_t *threads;
+ struct thread_data td;
+ sem_t start_sem;
+ int i;
- thrwait = 0;
+ threads = malloc(nthr * sizeof(pthread_t));
+ sem_init(&start_sem, 0, 0);
+
+ td.fn = fn;
+ td.work = work;
+ td.ninc = ninc;
+ td.start_sem = &start_sem;
+
for(i = 0; i < nthr; i++){- if((p = rfork(RFPROC|RFMEM)) == -1)
- sysfatal("rfork: %r");- if(p == 0){- semacquire(&thrwait, 1);
- (*fn)(work, ninc);
- exits(nil);
+ if(pthread_create(&threads[i], NULL, thread_worker, &td) != 0) {+ fprintf(stderr, "pthread_create failed\n");
+ exit(1);
}
}
- semrelease(&thrwait, nthr);
+
for(i = 0; i < nthr; i++)
- free(wait());
+ sem_post(&start_sem);
+
+ for(i = 0; i < nthr; i++)
+ pthread_join(threads[i], NULL);
+
+ sem_destroy(&start_sem);
+ free(threads);
}
void benchlock1(B *b) { lockbench(dolock, 1, nop, b->N); }-void benchqlock1(B *b) { lockbench(doqlock, 1, nop, b->N); }-void benchslock1(B *b) { lockbench(doslock, 1, nop, b->N); } void benchlock4(B *b) { lockbench(dolock, 4, nop, b->N); }-void benchqlock4(B *b) { lockbench(doqlock, 4, nop, b->N); }-void benchslock4(B *b) { lockbench(doslock, 4, nop, b->N); } void benchlock16(B *b) { lockbench(dolock, 16, nop, b->N); }-void benchqlock16(B *b) { lockbench(doqlock, 16, nop, b->N); }-void benchslock16(B *b) { lockbench(doslock, 16, nop, b->N); } void benchlock64(B *b) { lockbench(dolock, 64, nop, b->N); }-void benchqlock64(B *b) { lockbench(doqlock, 64, nop, b->N); }-void benchslock64(B *b) { lockbench(doslock, 64, nop, b->N); } void benchlock512(B *b) { lockbench(dolock, 512, nop, b->N); }-void benchqlock512(B *b) { lockbench(doqlock, 512, nop, b->N); }-void benchslock512(B *b) { lockbench(doslock, 512, nop, b->N); } void benchlock1_w(B *b) { lockbench(dolock, 1, work, b->N); }-void benchqlock1_w(B *b) { lockbench(doqlock, 1, work, b->N); }-void benchslock1_w(B *b) { lockbench(doslock, 1, work, b->N); } void benchlock4_w(B *b) { lockbench(dolock, 4, work, b->N); }-void benchqlock4_w(B *b) { lockbench(doqlock, 4, work, b->N); }-void benchslock4_w(B *b) { lockbench(doslock, 4, work, b->N); } void benchlock16_w(B *b) { lockbench(dolock, 16, work, b->N); }-void benchqlock16_w(B *b) { lockbench(doqlock, 16, work, b->N); }-void benchslock16_w(B *b) { lockbench(doslock, 16, work, b->N); } void benchlock64_w(B *b) { lockbench(dolock, 64, work, b->N); }-void benchqlock64_w(B *b) { lockbench(doqlock, 64, work, b->N); }-void benchslock64_w(B *b) { lockbench(doslock, 64, work, b->N); } void benchlock512_w(B *b) { lockbench(dolock, 512, work, b->N); }-void benchqlock512_w(B *b) { lockbench(doqlock, 512, work, b->N); }-void benchslock512_w(B *b) { lockbench(doslock, 512, work, b->N); }-void
+int
main(int argc, char **argv)
{benchinit(argc, argv);
- print("== locking (fast work) ==\n");+ printf("== locking (fast work) ==\n");BM(benchlock1);
- BM(benchqlock1);
- BM(benchslock1);
BM(benchlock4);
- BM(benchqlock4);
- BM(benchslock4);
BM(benchlock16);
- BM(benchqlock16);
- BM(benchslock16);
BM(benchlock64);
- BM(benchqlock64);
- BM(benchslock64);
BM(benchlock512);
- BM(benchqlock512);
- BM(benchslock512);
- print("== locking (slow work) ==\n");+ printf("== locking (slow work) ==\n");BM(benchlock1_w);
- BM(benchqlock1_w);
- BM(benchslock1_w);
BM(benchlock4_w);
- BM(benchqlock4_w);
- BM(benchslock4_w);
BM(benchlock16_w);
- BM(benchqlock16_w);
- BM(benchslock16_w);
BM(benchlock64_w);
- BM(benchqlock64_w);
- BM(benchslock64_w);
BM(benchlock512_w);
- BM(benchqlock512_w);
- BM(benchslock512_w);
- exits(nil);
+ return 0;
}
--- a/nop.c
+++ b/nop.c
@@ -1,8 +1,8 @@
-#include <u.h>
-#include <libc.h>
+#include <stdio.h>
+#include <stdlib.h>
-void
+int
main(void)
{- exits(nil);
+ return 0;
}
--- a/rdwr.c
+++ b/rdwr.c
@@ -1,16 +1,30 @@
-#include <u.h>
-#include <libc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/syscall.h>
+#include <string.h>
+#include <errno.h>
#include "bench.h"
+#define IOUNIT 32768
+
+struct pipe_data {+ int fd;
+ int n;
+ int count;
+ char *buf;
+};
+
void
benchsysr1(B *b)
{int i;
- extern int sysr1(void);
for(i = 0; i < b->N; i++)
- sysr1();
+ syscall(SYS_getpid);
}
void
@@ -19,8 +33,10 @@
int i, fd;
char buf[128*IOUNIT];
- if((fd = open(path, OREAD)) == -1)
- sysfatal("open %s: %r", path);+ if((fd = open(path, O_RDONLY)) == -1) {+ fprintf(stderr, "open %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
for(i = 0; i < b->N; i++)
pread(fd, buf, n, 0);
close(fd);
@@ -32,46 +48,67 @@
int i, fd;
char buf[128*IOUNIT];
- if((fd = open(path, OWRITE)) == -1)
- sysfatal("open %s: %r", path);+ if((fd = open(path, O_WRONLY)) == -1) {+ fprintf(stderr, "open %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
for(i = 0; i < b->N; i++)
pwrite(fd, buf, n, 0);
close(fd);
}
+static void *
+pipe_writer(void *arg)
+{+ struct pipe_data *pd = arg;
+ int i;
+
+ for(i = 0; i < pd->count; i++)
+ if(write(pd->fd, pd->buf, pd->n) == -1) {+ fprintf(stderr, "write: %s\n", strerror(errno));
+ exit(1);
+ }
+ return NULL;
+}
+
void
benchpipe(B *b, int n)
{char buf[128*IOUNIT];
int i, pfd[2];
+ pthread_t writer_thread;
+ struct pipe_data pd;
- if(pipe(pfd) == -1)
- sysfatal("pipe: %r");+ if(pipe(pfd) == -1) {+ fprintf(stderr, "pipe: %s\n", strerror(errno));
+ exit(1);
+ }
- switch(rfork(RFPROC)){- case -1:
- sysfatal("fork: %r");- case 0:
- for(i = 0; i < b->N; i++)
- if(write(pfd[0], buf, n) == -1)
- sysfatal("write: %r");- exits(nil);
- break;
- default:
- for(i = 0; i < b->N; i++)
- if(read(pfd[1], buf, n) == -1)
- sysfatal("read: %r");- free(wait());
- close(pfd[0]);
- close(pfd[1]);
- break;
+ pd.fd = pfd[1];
+ pd.n = n;
+ pd.count = b->N;
+ pd.buf = buf;
+
+ if(pthread_create(&writer_thread, NULL, pipe_writer, &pd) != 0) {+ fprintf(stderr, "pthread_create failed\n");
+ exit(1);
}
+
+ for(i = 0; i < b->N; i++)
+ if(read(pfd[0], buf, n) == -1) {+ fprintf(stderr, "read: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ pthread_join(writer_thread, NULL);
+ close(pfd[0]);
+ close(pfd[1]);
}
void benchreadzero(B *b) { benchread(b, "/dev/zero", 4); } void benchwritenull(B *b) { benchwrite(b, "/dev/null", 4); }-void benchreadmordor(B *b) { benchread(b, "/dev/mordor", 4); }-void benchwritemordor(B *b) { benchwrite(b, "/dev/mordor", 4); }+void benchreaddir(B *b) { benchread(b, "/tmp", 4); } // Reading directory fails with EISDIR+void benchwritefull(B *b) { benchwrite(b, "/dev/full", 4); } void benchpipe1(B *b) { benchpipe(b, 1); } void benchpipe16(B *b) { benchpipe(b, 16); } void benchpipe256(B *b) { benchpipe(b, 256); }@@ -79,19 +116,19 @@
void benchpipe4097(B *b) { benchpipe(b, 4097); } void benchpipe32768(B *b) { benchpipe(b, 32768); }-void
+int
main(int argc, char **argv)
{benchinit(argc, argv);
- print("== nop io ==\n");+ printf("== nop io ==\n");BM(benchsysr1);
BM(benchreadzero);
BM(benchwritenull);
- BM(benchreadmordor);
- BM(benchwritemordor);
+ BM(benchreaddir);
+ BM(benchwritefull);
- print("== pipe io ==\n");+ printf("== pipe io ==\n");BM(benchpipe1);
BM(benchpipe16);
BM(benchpipe256);
@@ -98,6 +135,6 @@
BM(benchpipe4096);
BM(benchpipe4097);
BM(benchpipe32768);
- exits(nil);
+ return 0;
}
--- a/spawn.c
+++ b/spawn.c
@@ -1,5 +1,12 @@
-#include <u.h>
-#include <libc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <spawn.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
#include "bench.h"
@@ -18,22 +25,37 @@
}
#endif
+typedef struct Args Args;
+
+struct Args
+{+ void (*fn)(int);
+ int n;
+};
+
+static void *
+worker(void *arg)
+{+ Args *a = arg;
+ a->fn(a->n);
+ return NULL;
+}
+
void
doit(void (*fn)(int), int n)
{- int r, i;
+ pthread_t t[256];
+ Args a[256];
+ int i;
+ assert(NPROC <= 256);
for(i = 0; i < NPROC; i++){- r = fork();
- if(r == -1)
- sysfatal("rfork: %r");- if(r == 0){- fn(n/NPROC);
- exits(nil);
- }
+ a[i].fn = fn;
+ a[i].n = n/NPROC;
+ pthread_create(&t[i], NULL, worker, &a[i]);
}
for(i = 0; i < NPROC; i++)
- waitpid();
+ pthread_join(t[i], NULL);
}
void
@@ -41,22 +63,38 @@
{int i;
+ fflush(stdout); // clear the buffer.
for(i = 0; i < N; i++){- if(!fork())
- exits(nil);
- waitpid();
+ switch(fork()){+ case -1:
+ fprintf(stderr, "fork failed\n");
+ exit(1);
+ case 0:
+ exit(0);
+ default:
+ wait(NULL);
+ }
}
}
+static void *
+empty_thread(void *arg)
+{+ return NULL;
+}
+
void
-benchrforkm(int N)
+benchpthread(int N)
{int i;
+ pthread_t thread;
for(i = 0; i < N; i++){- if(!rfork(RFPROC|RFMEM))
- exits(nil);
- waitpid();
+ if(pthread_create(&thread, NULL, empty_thread, NULL) != 0) {+ fprintf(stderr, "pthread_create failed\n");
+ exit(1);
+ }
+ pthread_join(thread, NULL);
}
}
@@ -70,11 +108,11 @@
case -1:
abort();
case 0:
- execl("./6.nop", "6.nop", nil);- print("exec: %r");+ execl("./nop", "nop", NULL);+ fprintf(stderr, "exec: %s\n", strerror(errno));
abort();
default:
- waitpid();
+ wait(NULL);
}
}
}
@@ -83,18 +121,15 @@
benchexecm(int N)
{int i;
+ pid_t pid;
+ char *argv[] = {"nop", NULL}; for(i = 0; i < N; i++){- switch(rfork(RFPROC|RFMEM)){- case -1:
+ if(posix_spawn(&pid, "./nop", NULL, NULL, argv, NULL) != 0) {+ fprintf(stderr, "posix_spawn failed\n");
abort();
- case 0:
- execl("./6.nop", "6.nop", nil);- print("exec: %r");- abort();
- default:
- waitpid();
}
+ waitpid(pid, NULL, 0);
}
}
@@ -113,13 +148,13 @@
void
benchrforkm1(B *b)
{- benchrforkm(b->N);
+ benchpthread(b->N);
}
void
benchrforkmN(B *b)
{- doit(benchrforkm, b->N);
+ doit(benchpthread, b->N);
}
void
@@ -146,22 +181,22 @@
doit(benchexecm, b->N);
}
-void
+int
main(int argc, char **argv)
{benchinit(argc, argv);
- print("== fork/exec (single spawner) ==\n");+ printf("== fork/exec (single spawner) ==\n");BM(benchfork1);
BM(benchrforkm1);
BM(benchexec1);
BM(benchexecm1);
- print("== fork/exec (%d spawners) ==\n", NPROC);+ printf("== fork/exec (%d spawners) ==\n", NPROC);BM(benchforkN);
BM(benchrforkmN);
BM(benchexecN);
BM(benchexecmN);
- exits(nil);
+ return 0;
}
--
⑨