benchmark.c

Basic benchmarking library in C
git clone git://git.finwo.net/lib/benchmark.c
Log | Files | Refs | README | LICENSE

benchmark.c (2929B)


      1 #include <stdint.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 
      6 #if defined(_WIN32) || defined(_WIN64)
      7 #include "win32ports/time.h"
      8 #else
      9 #include <sys/time.h>
     10 #endif
     11 
     12 #include "benchmark.h"
     13 
     14 struct bmark_queue_t {
     15   void *next;
     16   char *name;
     17   void (*fn)();
     18 };
     19 struct bmark_ptile_t {
     20   char n;
     21 };
     22 
     23 struct bmark_queue_t *bmark_queue   = NULL;
     24 
     25 struct bmark_unit_entry {
     26   char *name;
     27   int   next;
     28 };
     29 
     30 struct bmark_unit_entry units[] = {
     31   { "us", 1000 },
     32   { "ms", 1000 },
     33   { "s" ,   60 },
     34   { "m" ,    0 },
     35 };
     36 
     37 const char *header_description = "Description";
     38 
     39 void bmark_enqueue(char *name, void (*fn)()) {
     40   struct bmark_queue_t *q = calloc(1, sizeof(struct bmark_queue_t));
     41   q->name = name;
     42   q->fn   = fn;
     43   q->next = bmark_queue;
     44   bmark_queue = q;
     45 }
     46 
     47 // Example time numbers:  12.23 s
     48 //                       900.00 ms
     49 //                       123.45 us
     50 int bmark_run(int run_count, char percentiles[]) {
     51   int header_desclen = strlen(header_description);
     52   int i, l, r, unit;
     53   struct timeval tv_start;
     54   struct timeval tv_end;
     55 
     56   uint64_t *runs    = calloc(run_count, sizeof(uint64_t));
     57   uint64_t  run_tmp = 0;
     58   double    run_f   = 0;
     59 
     60   // Get max description length
     61   struct bmark_queue_t *q_entry = bmark_queue;
     62   while(q_entry) {
     63     l = strlen(q_entry->name);
     64     if (l > header_desclen) header_desclen = l;
     65     q_entry = q_entry->next;
     66   }
     67 
     68   printf("\n");
     69 
     70   // Column names
     71   printf("| %-*s |", header_desclen, header_description);
     72   for(i = 0 ; percentiles[i] ; i++) printf(" %*d %% |", 7, percentiles[i]);
     73   printf("\n");
     74 
     75   // Separator
     76   printf("|:");
     77   for(i = 0 ; i < header_desclen ; i++) printf("-");
     78   printf(" |");
     79   for(i = 0 ; percentiles[i] ; i++) printf(" ---------:|");
     80   printf("\n");
     81 
     82   // Go over the whole queue
     83   q_entry = bmark_queue;
     84   while(q_entry) {
     85     printf("| %-*s |", header_desclen, q_entry->name);
     86     fflush(stdout);
     87 
     88     // Do the actual runs
     89     for(r = 0; r < run_count ; r++) {
     90       gettimeofday(&tv_start, NULL);
     91       q_entry->fn();
     92       gettimeofday(&tv_end, NULL);
     93       runs[r] = (tv_end.tv_sec*(uint64_t)1000000+tv_end.tv_usec) - (tv_start.tv_sec*(uint64_t)1000000+tv_start.tv_usec);
     94     }
     95 
     96     // Sort the runs
     97     // Basic bubble sort is fine here, we're not going for a speed record
     98     for(r = 0; r < (run_count-1) ; r++) {
     99       if (r < 0) continue;
    100       if (runs[r] > runs[r+1]) {
    101         run_tmp = runs[r];
    102         runs[r] = runs[r+1];
    103         runs[r+1] = run_tmp;
    104         r -= 2;
    105       }
    106     }
    107 
    108     // Print percentiles
    109     for(i = 0 ; percentiles[i] ; i++) {
    110       r     = percentiles[i] * (run_count-1) / 100;
    111       run_f = (double)runs[r];
    112       unit  = 0;
    113       while((run_f > units[unit].next) && units[unit].next) {
    114         run_f = run_f / units[unit].next;
    115         unit++;
    116       }
    117       printf(" %*.2lf %2s |", 6, run_f, units[unit].name);
    118     }
    119 
    120     printf("\n");
    121 
    122     q_entry = q_entry->next;
    123   }
    124 
    125   printf("\n");
    126   return 0;
    127 }