diff options
| author | yo mama <pepper@scannerjammer.com> | 2015-04-04 01:00:59 -0700 |
|---|---|---|
| committer | yo mama <pepper@scannerjammer.com> | 2015-04-04 01:00:59 -0700 |
| commit | c7c22e3db1c826bcfb2bc66651ec480aae0d4ae0 (patch) | |
| tree | 8546df448afef40d3814d2581f4dacff7cebb87f /node_modules/webworker-threads/benchmark/doubles.c | |
Diffstat (limited to 'node_modules/webworker-threads/benchmark/doubles.c')
| -rw-r--r-- | node_modules/webworker-threads/benchmark/doubles.c | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/node_modules/webworker-threads/benchmark/doubles.c b/node_modules/webworker-threads/benchmark/doubles.c new file mode 100644 index 0000000..3210a51 --- /dev/null +++ b/node_modules/webworker-threads/benchmark/doubles.c @@ -0,0 +1,637 @@ +/* + simple thread/process benchmark + + Copyright (C) Andrew Tridgell <tridge@samba.org> 2003 + + Released under the GNU GPL version 2 or later +*/ + +/* + this program is designed to test the relative performance of threads/processes + for operations typically performed by fileserving applications. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <dirent.h> + +#ifndef NO_THREADS +#include <pthread.h> +#endif + +/* this contains per-task data */ +static struct { + char *dname; + char *fname; +} *id_data; + +/* these pipes are used for synchronised startup of the tasks */ +static struct barrier { + int fd1[2]; + int fd2[2]; +} barriers[2]; + +/* setup a barrier */ +static void barrier_setup(struct barrier *b) +{ + if (pipe(b->fd1) != 0 || pipe(b->fd2) != 0) { + fprintf(stderr,"Barrier setup failed\n"); + exit(1); + } +} + +/* cleanup the barrier pipes */ +static void barrier_cleanup(struct barrier *b) +{ + close(b->fd1[0]); + close(b->fd1[1]); + close(b->fd2[0]); + close(b->fd2[1]); +} + +/* wait for the parent to signal startup */ +static void barrier_wait(struct barrier *b) +{ + char c = 0; + + if (write(b->fd1[1], &c, 1) != 1 || + read(b->fd2[0], &c, 1) != 1) { + fprintf(stderr, "Barrier wait failed\n"); + exit(1); + } +} + +/* synchronise children. Return the amount of time since the last + barrier */ +static double barrier_parent(struct barrier *b, int nprocs) +{ + char *s = calloc(nprocs, 1); + int i, nwritten=0; + char c = 0; + double t; + static struct timeval tp1; + struct timeval tp2; + + for (i=0;i<nprocs;i++) { + while (read(b->fd1[0], &c, 1) != 1) ; + } + + /* putting the timer here prevents problems with the parent getting + rescheduled after the write */ + gettimeofday(&tp2,NULL); + t = (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - + (tp1.tv_sec + (tp1.tv_usec*1.0e-6)); + gettimeofday(&tp1,NULL); + + while (nwritten != nprocs) { + int n = write(b->fd2[1], s, nprocs-nwritten); + if (n <= 0) { + fprintf(stderr, "Barrier parent failed\n"); + exit(1); + } + nwritten += n; + } + free(s); + return t; +} + +#ifndef NO_THREADS +/* + create a thread with initial function fn(private) +*/ +static pthread_t thread_start(void *(*fn)(int), int id) +{ + pthread_t thread_id; + pthread_attr_t thread_attr; + int rc; + typedef void *(*thread_fn_t)(void *); + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, 0); + rc = pthread_create(&thread_id, &thread_attr, (thread_fn_t)fn, (void *)(intptr_t)id); + pthread_attr_destroy(&thread_attr); + + if (rc != 0) { + fprintf(stderr,"Thread create failed for id %d\n", id); + exit(1); + } + + return thread_id; +} + +/* wait for a thread to exit */ +static int thread_join(pthread_t id) +{ + return pthread_join(id, NULL); +} +#endif + + +/* + create a process with initial function fn(private) +*/ +static pid_t proc_start(void *(*fn)(int), int id) +{ + pid_t pid; + + pid = fork(); + if (pid == (pid_t)-1) { + fprintf(stderr,"Fork failed for id %d\n", id); + return pid; + } + if (pid == 0) { + fn(id); + exit(0); + } + return pid; +} + +/* wait for a process to exit */ +static int proc_join(pid_t id) +{ + if (waitpid(id, NULL, 0) != id) { + return -1; + } + return 0; +} + +#ifndef NO_THREADS +/* run a function under a set of threads */ +static double run_threads(int nthreads, void *(*fn)(int )) +{ + int i; + pthread_t *ids = calloc(sizeof(*ids), nthreads); + double t; + + barrier_setup(&barriers[0]); + barrier_setup(&barriers[1]); + + for (i=0;i<nthreads;i++) { + ids[i] = thread_start(fn, i); + } + + barrier_parent(&barriers[0], nthreads); + t = barrier_parent(&barriers[1], nthreads); + + for (i=0;i<nthreads;i++) { + int rc; + rc = thread_join(ids[i]); + if (rc != 0) { + fprintf(stderr, "Thread %d failed : %s\n", i, strerror(errno)); + exit(1); + } + } + + barrier_cleanup(&barriers[0]); + barrier_cleanup(&barriers[1]); + + free(ids); + + return t; +} +#endif + +/* run a function under a set of processes */ +static double run_processes(int nprocs, void *(*fn)(int )) +{ + int i; + pid_t *ids = calloc(sizeof(*ids), nprocs); + double t; + + barrier_setup(&barriers[0]); + barrier_setup(&barriers[1]); + + for (i=0;i<nprocs;i++) { + ids[i] = proc_start(fn, i); + if (ids[i] == (pid_t)-1) { + for (i--;i>=0;i--) { + kill(ids[i], SIGTERM); + } + exit(1); + } + } + + barrier_parent(&barriers[0], nprocs); + t = barrier_parent(&barriers[1], nprocs); + + for (i=0;i<nprocs;i++) { + int rc; + rc = proc_join(ids[i]); + if (rc != 0) { + fprintf(stderr, "Process %d failed : %s\n", i, strerror(errno)); + exit(1); + } + } + + barrier_cleanup(&barriers[0]); + barrier_cleanup(&barriers[1]); + + free(ids); + + return t; +} + + + +/*********************************************************************** + a simple malloc speed test using a wide variety of malloc sizes +************************************************************************/ +static void *test_malloc(int id) +{ +#define NMALLOCS 200 + int i, j; + void *ptrs[NMALLOCS]; + + barrier_wait(&barriers[0]); + + for (j=0;j<500;j++) { + for (i=1;i<NMALLOCS;i++) { + ptrs[i] = malloc(i*128); + if (!ptrs[i]) { + printf("malloc(%d) failed!\n", i); + exit(1); + } + } + for (i=1;i<NMALLOCS;i++) { + free(ptrs[i]); + } + } + + barrier_wait(&barriers[1]); + return NULL; +} + +/*********************************************************************** + a simple setreuid speed test +************************************************************************/ +static void *test_setreuid(int id) +{ + int i; + void *ptrs[NMALLOCS]; + + barrier_wait(&barriers[0]); + if (getuid() != 0) { + if (id == 0) { + printf("Skipping setreuid test for non-root user\n"); + } + barrier_wait(&barriers[1]); + return NULL; + } + + + for (i=0;i<2000;i++) { + if (setreuid(-1, 1) != 0 || + setreuid(-1, 0) != 0) { + printf("setreuid failed: %s\n", strerror(errno)); + barrier_wait(&barriers[1]); + return NULL; + } + } + + barrier_wait(&barriers[1]); + return NULL; +} + + +/*********************************************************************** + simple read/write testing using /dev/null and /dev/zero +************************************************************************/ +static void *test_readwrite(int id) +{ + int i; + int fd_in, fd_out; + /* we use less than 1 page to prevent page table games */ + char buf[32]; + + barrier_wait(&barriers[0]); + + fd_in = open("/dev/zero", O_RDONLY); + fd_out = open("/dev/null", O_WRONLY); + if (fd_in == -1 || fd_out == -1) { + fprintf(stderr,"Failed to open /dev/zero or /dev/null\n"); + exit(1); + } + + for (i=0;i<100000;i++) { + if (read(fd_in, buf, sizeof(buf)) != sizeof(buf) || + write(fd_out, buf, sizeof(buf)) != sizeof(buf)) { + fprintf(stderr,"IO failed at loop %d\n", i); + exit(1); + } + } + + close(fd_in); + close(fd_out); + + barrier_wait(&barriers[1]); + + return NULL; +} + + +/*********************************************************************** +test stat() operations +************************************************************************/ +static void *test_stat(int id) +{ + int i; + + barrier_wait(&barriers[0]); + + for (i=0;i<30000;i++) { + struct stat st; + if (stat(id_data[id].dname, &st) != 0) goto failed; + if (stat(id_data[id].fname, &st) == 0) goto failed; + } + + barrier_wait(&barriers[1]); + + return NULL; + +failed: + fprintf(stderr,"stat failed\n"); + exit(1); +} + +/*********************************************************************** +test fstat() operations +************************************************************************/ +static void *test_fstat(int id) +{ + int i, fd; + + barrier_wait(&barriers[0]); + + fd = open(id_data[id].fname, O_RDWR|O_CREAT, 0600); + if (fd == -1) goto failed; + + for (i=0;i<1000000;i++) { + struct stat st; + if (fstat(fd, &st) != 0) goto failed; + } + + close(fd); + unlink(id_data[id].fname); + + barrier_wait(&barriers[1]); + + return NULL; + +failed: + fprintf(stderr,"fstat failed\n"); + exit(1); +} + +/*********************************************************************** +test directory operations +************************************************************************/ +static void *test_dir(int id) +{ + int i; + + barrier_wait(&barriers[0]); + + for (i=0;i<2000;i++) { + DIR *d = opendir(id_data[id].dname); + if (!d) goto failed; + while (readdir(d)) {} ; + closedir(d); + } + + barrier_wait(&barriers[1]); + return NULL; + +failed: + fprintf(stderr,"dir failed\n"); + exit(1); +} + +/*********************************************************************** +test directory operations +************************************************************************/ +static void *test_dirsingle(int id) +{ + int i; + + barrier_wait(&barriers[0]); + + for (i=0;i<2000;i++) { + DIR *d = opendir("."); + if (!d) goto failed; + while (readdir(d)) {} ; + closedir(d); + } + + barrier_wait(&barriers[1]); + return NULL; + +failed: + fprintf(stderr,"dirsingle failed\n"); + exit(1); +} + + +/*********************************************************************** +test create/unlink operations +************************************************************************/ +static void *test_create(int id) +{ + int i; + + barrier_wait(&barriers[0]); + + for (i=0;i<3000;i++) { + int fd; + fd = open(id_data[id].fname, O_CREAT|O_TRUNC|O_RDWR, 0666); + if (fd == -1) goto failed; + if (open(id_data[id].fname, O_CREAT|O_TRUNC|O_RDWR|O_EXCL, 0666) != -1) goto failed; + close(fd); + if (unlink(id_data[id].fname) != 0) goto failed; + } + + barrier_wait(&barriers[1]); + return NULL; + +failed: + fprintf(stderr,"create failed\n"); + exit(1); +} + + +/*********************************************************************** +test fcntl lock operations +************************************************************************/ +static void *test_lock(int id) +{ + int i; + int fd; + + barrier_wait(&barriers[0]); + + fd = open(id_data[id].fname, O_CREAT|O_RDWR, 0666); + if (fd == -1) goto failed; + unlink(id_data[id].fname); + + for (i=0;i<20000;i++) { + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = (id*100) + (i%100); + lock.l_len = 1; + lock.l_pid = 0; + + if (fcntl(fd,F_SETLK,&lock) != 0) goto failed; + + lock.l_type = F_UNLCK; + + if (fcntl(fd,F_SETLK,&lock) != 0) goto failed; + } + + close(fd); + + barrier_wait(&barriers[1]); + return NULL; + +failed: + fprintf(stderr,"lock failed\n"); + exit(1); +} + +/*********************************************************************** +do nothing! +************************************************************************/ +static void *test_noop(int id) +{ + barrier_wait(&barriers[0]); + barrier_wait(&barriers[1]); + return NULL; +} + + +/* + show the average and range of a set of results +*/ +static void show_result(const char *name, double *t, int nrepeats) +{ + double mint, maxt, total; + int i; + total = mint = maxt = t[0]; + for (i=1;i<nrepeats;i++) { + if (t[i] < mint) mint = t[i]; + if (t[i] > maxt) maxt = t[i]; + total += t[i]; + } + printf("%s %5.2f +/- %.2f seconds\n", name, total/nrepeats, (maxt-mint)/2); +} + + +/* lock a byte range in a open file */ +int main(int argc, char *argv[]) +{ + int nprocs, i; + char *tname = "ALL"; +#define NREPEATS 10 + struct { + const char *name; + void *(*fn)(int ); + } tests[] = { + {"noop", test_noop}, + {"malloc", test_malloc}, + {"setreuid", test_setreuid}, + {"readwrite", test_readwrite}, + {"stat", test_stat}, + {"fstat", test_fstat}, + {"dir", test_dir}, + {"dirsingle", test_dirsingle}, + {"create", test_create}, + {"lock", test_lock}, + {NULL, NULL} + }; + + if (argc <= 1) { + printf("thread_perf NPROCS\n"); + exit(1); + } + + nprocs = atoi(argv[1]); + + if (argc > 2) { + tname = argv[2]; + } + + id_data = calloc(nprocs, sizeof(*id_data)); + if (!id_data) { + exit(1); + } + +#ifndef NO_THREADS + printf("NOTE! for accurate process results please compile with -DNO_THREADS and don't link to -lpthread\n\n"); +#endif + + for (i=0;i<nprocs;i++) { + char s[30]; + sprintf(s, "testd_%d", i); + id_data[i].dname = strdup(s); + + sprintf(s, "%s/test.dat", id_data[i].dname); + id_data[i].fname = strdup(s); + + rmdir(id_data[i].dname); + if (mkdir(id_data[i].dname, 0777) != 0) { + fprintf(stderr, "Failed to create %s\n", id_data[i].dname); + exit(1); + } + + unlink(id_data[i].fname); + } + + for (i=0;tests[i].name;i++) { + double t_threads[NREPEATS]; + double t_processes[NREPEATS]; + int j; + + if (strcasecmp(tname, "ALL") && strcasecmp(tests[i].name, tname)) { + continue; + } + + printf("Running test '%s' with %d tasks\n", tests[i].name, nprocs); + + for (j=0;j<NREPEATS;j++) { +#ifndef NO_THREADS + t_threads[j] = run_threads(nprocs, tests[i].fn); +#endif + t_processes[j] = run_processes(nprocs, tests[i].fn); + } +#ifndef NO_THREADS + show_result("Threads ", t_threads, NREPEATS); +#endif + show_result("Processes", t_processes, NREPEATS); + + printf("\n"); + fflush(stdout); + } + + for (i=0;i<nprocs;i++) { + if (rmdir(id_data[i].dname) != 0) { + fprintf(stderr, "Failed to delete %s\n", id_data[i].dname); + exit(1); + } + } + + for (i=0;i<nprocs;i++) { + free(id_data[i].dname); + free(id_data[i].fname); + } + free(id_data); + + return 0; +}
\ No newline at end of file |
