shithub: sysbench

Download patch

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