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