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;
}
--
⑨