Add first micro-benchmark
[flac.git] / microbench / util.c
1 /* FLAC - Free Lossless Audio Codec
2  * Copyright (C) 2015  Xiph.Org Foundation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of the Xiph.org Foundation nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #define _GNU_SOURCE
33
34 #include <stdlib.h>
35 #include <time.h>
36 #include <sys/time.h>
37
38 #include "util.h"
39
40 static double
41 timespec_diff (const struct timespec * start, const struct timespec * end)
42 {       struct timespec difftime;
43
44         if (end->tv_nsec - start->tv_nsec < 0)
45         {       difftime.tv_sec = end->tv_sec - start->tv_sec - 1 ;
46                 difftime.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec ;
47                 }
48         else
49         {       difftime.tv_sec = end->tv_sec - start->tv_sec ;
50                 difftime.tv_nsec = end->tv_nsec-start->tv_nsec ;
51                 } ;
52
53         return difftime.tv_sec + 1e-9 * difftime.tv_nsec ;
54 }
55
56 double
57 benchmark_function (void (*testfunc) (void), unsigned count)
58 {       struct timespec start, end;
59         unsigned k ;
60
61         clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &start) ;
62
63         for (k = 0 ; k < count ; k++)
64                 testfunc () ;
65
66         clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &end) ;
67
68         return timespec_diff (&start, &end) / count ;
69 } /* benchmark_function */
70
71 static int
72 double_cmp (const void * a, const void * b)
73 {       const double * pa = (double *) a ;
74         const double * pb = (double *) b ;
75         return pa [0] < pb [0] ;
76 } /* double_cmp */
77
78 void
79 benchmark_stats (bench_stats * stats)
80 {       double sum, times [stats->run_count] ;
81         unsigned k ;
82
83         for (k = 0 ; k < stats->run_count ; k++)
84                 times [k] = benchmark_function (stats->testfunc, stats->loop_count) ;
85
86         qsort (times, stats->run_count, sizeof (times [0]), double_cmp) ;
87
88         sum = 0.0 ;
89         stats->min_time = stats->max_time = times [0] ;
90         for (k = 0 ; k < stats->run_count ; k++)
91         {       stats->min_time = stats->min_time < times [k] ? stats->min_time : times [k] ;
92                 stats->max_time = stats->max_time > times [k] ? stats->max_time : times [k] ;
93                 sum += times [k] ;
94                 }
95         stats->mean_time = sum / stats->run_count ;
96         if (stats->run_count & 1)
97                 stats->median_time = times [(stats->run_count + 1) / 2] ;
98         else
99                 stats->median_time = 0.5 * (times [stats->run_count / 2] + times [(stats->run_count / 2) + 1]) ;
100
101         return ;
102 } /* benchmark_stats */