1 // A simple benchmark tool around getrusage
2
3 #include <assert.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/resource.h>
8
9 #include "cmph_benchmark.h"
10
11 typedef struct {
12 const char* name;
13 void (*func)(int);
14 int iters;
15 struct rusage begin;
16 struct rusage end;
17 } benchmark_t;
18
19 static benchmark_t* global_benchmarks = NULL;
20
21 /* Subtract the `struct timeval' values X and Y,
22 storing the result in RESULT.
23 Return 1 if the difference is negative, otherwise 0. */
24
timeval_subtract(struct timeval * result,struct timeval * x,struct timeval * y)25 int timeval_subtract (
26 struct timeval *result, struct timeval *x, struct timeval* y) {
27 /* Perform the carry for the later subtraction by updating y. */
28 if (x->tv_usec < y->tv_usec) {
29 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
30 y->tv_usec -= 1000000 * nsec;
31 y->tv_sec += nsec;
32 }
33 if (x->tv_usec - y->tv_usec > 1000000) {
34 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
35 y->tv_usec += 1000000 * nsec;
36 y->tv_sec -= nsec;
37 }
38
39 /* Compute the time remaining to wait.
40 tv_usec is certainly positive. */
41 result->tv_sec = x->tv_sec - y->tv_sec;
42 result->tv_usec = x->tv_usec - y->tv_usec;
43
44 /* Return 1 if result is negative. */
45 return x->tv_sec < y->tv_sec;
46 }
47
find_benchmark(const char * name)48 benchmark_t* find_benchmark(const char* name) {
49 benchmark_t* benchmark = global_benchmarks;
50 while (benchmark && benchmark->name != NULL) {
51 if (strcmp(benchmark->name, name) == 0) break;
52 ++benchmark;
53 }
54 if (!benchmark || !benchmark->name) return NULL;
55 return benchmark;
56 }
57
global_benchmarks_length()58 int global_benchmarks_length() {
59 benchmark_t* benchmark = global_benchmarks;
60 int length = 0;
61 if (benchmark == NULL) return 0;
62 while (benchmark->name != NULL) ++length, ++benchmark;
63 return length;
64 }
65
bm_register(const char * name,void (* func)(int),int iters)66 void bm_register(const char* name, void (*func)(int), int iters) {
67 benchmark_t benchmark;
68 int length = global_benchmarks_length();
69 benchmark.name = name;
70 benchmark.func = func;
71 benchmark.iters = iters;
72 assert(!find_benchmark(name));
73 global_benchmarks = (benchmark_t *)realloc(
74 global_benchmarks, (length + 2)*sizeof(benchmark_t));
75 global_benchmarks[length] = benchmark;
76 memset(&benchmark, 0, sizeof(benchmark_t)); // pivot
77 global_benchmarks[length + 1] = benchmark;
78 }
79
bm_start(const char * name)80 void bm_start(const char* name) {
81 benchmark_t* benchmark;
82 struct rusage rs;
83
84 benchmark = find_benchmark(name);
85 assert(benchmark);
86 int ret = getrusage(RUSAGE_SELF, &rs);
87 if (ret != 0) {
88 perror("rusage failed");
89 exit(-1);
90 }
91 benchmark->begin = rs;
92 (*benchmark->func)(benchmark->iters);
93 }
94
bm_end(const char * name)95 void bm_end(const char* name) {
96 benchmark_t* benchmark;
97 struct rusage rs;
98
99 int ret = getrusage(RUSAGE_SELF, &rs);
100 if (ret != 0) {
101 perror("rusage failed");
102 exit(-1);
103 }
104
105 benchmark = find_benchmark(name);
106 benchmark->end = rs;
107
108 struct timeval utime;
109 timeval_subtract(&utime, &benchmark->end.ru_utime, &benchmark->begin.ru_utime);
110 struct timeval stime;
111 timeval_subtract(&stime, &benchmark->end.ru_stime, &benchmark->begin.ru_stime);
112
113 printf("Benchmark: %s\n", benchmark->name);
114 printf("User time used : %ld.%06ld\n",
115 utime.tv_sec, (long int)utime.tv_usec);
116 printf("System time used: %ld.%06ld\n",
117 stime.tv_sec, (long int)stime.tv_usec);
118 printf("\n");
119 }
120
run_benchmarks(int argc,char ** argv)121 void run_benchmarks(int argc, char** argv) {
122 benchmark_t* benchmark = global_benchmarks;
123 while (benchmark && benchmark->name != NULL) {
124 bm_start(benchmark->name);
125 bm_end(benchmark->name);
126 ++benchmark;
127 }
128 }
129
130