Merge branch 'master' of https://github.com/calf-studio-gear/calf
[calf.git] / src / calf / benchmark.h
blob91c1a6b024ec0ef31e41c734796bbb10d9f20ed3
1 /* Calf DSP Library
2 * Reusable performance measurement classes.
4 * Copyright (C) 2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #ifndef __CALF_BENCHMARK_H
22 #define __CALF_BENCHMAR_H
24 #include <time.h>
25 #include <sys/time.h>
26 #include <sys/resource.h>
27 #include <unistd.h>
28 #include "primitives.h"
29 #include <algorithm>
30 #include <typeinfo>
32 namespace dsp {
33 #if 0
34 }; to keep editor happy
35 #endif
38 class median_stat
40 public:
41 double *data;
42 unsigned int pos, count;
43 bool sorted;
45 median_stat() {
46 data = NULL;
47 pos = 0;
48 count = 0;
49 sorted = false;
51 void start(int items) {
52 if (data)
53 delete []data;
54 data = new double[items];
55 pos = 0;
56 count = items;
57 sorted = false;
59 void add(double value)
61 assert(pos < count);
62 data[pos++] = value;
64 void end()
66 std::sort(&data[0], &data[count]);
67 sorted = true;
69 float get()
71 assert(sorted);
72 return data[count >> 1];
76 // USE_RDTSC is for testing on my own machine, a crappy 1.6GHz Pentium 4 - it gives less headaches than clock() based measurements
77 #define USE_RDTSC 0
78 #define CLOCK_SPEED (1.6 * 1000.0 * 1000.0 * 1000.0)
80 #if USE_RDTSC
81 inline uint64_t rdtsc()
83 unsigned long long int x;
84 __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
85 return x;
87 #endif
89 struct benchmark_globals
91 static bool warned;
94 template<typename Target, class Stat>
95 class simple_benchmark: public benchmark_globals
97 public:
98 Target target;
99 Stat &stat;
101 simple_benchmark(const Target &_target, Stat &_stat)
102 : target(_target)
103 , stat(_stat)
107 void measure(int runs, int repeats)
109 int priority = getpriority(PRIO_PROCESS, getpid());
110 stat.start(runs);
111 if (setpriority(PRIO_PROCESS, getpid(), -20) < 0) {
112 if (!warned) {
113 fprintf(stderr, "Warning: could not set process priority, measurements can be worthless\n");
114 warned = true;
117 for (int i = 0; i < runs; i++) {
118 target.prepare();
119 // XXXKF measuring CPU time with clock() sucks,
120 #if USE_RDTSC
121 uint64_t start = rdtsc();
122 #else
123 clock_t start = ::clock();
124 #endif
125 for (int j = 0; j < repeats; j++) {
126 target.run();
128 #if USE_RDTSC
129 uint64_t end = rdtsc();
130 double elapsed = double(end - start) / (CLOCK_SPEED * repeats * target.scaler());
131 #else
132 clock_t end = ::clock();
133 double elapsed = double(end - start) / (double(CLOCKS_PER_SEC) * repeats * target.scaler());
134 #endif
135 stat.add(elapsed);
136 target.cleanup();
137 // printf("elapsed = %f start = %d end = %d diff = %d\n", elapsed, start, end, end - start);
139 setpriority(PRIO_PROCESS, getpid(), priority);
140 stat.end();
143 float get_stat()
145 return stat.get();
149 template<class T>
150 void do_simple_benchmark(int runs = 5, int repeats = 50000)
152 dsp::median_stat stat;
153 dsp::simple_benchmark<T, dsp::median_stat> benchmark(T(), stat);
155 benchmark.measure(runs, repeats);
157 printf("%-30s: %f/sec, %f/CDsr, value = %f\n", typeid(T).name(), 1.0 / stat.get(), 1.0 / (44100 * stat.get()), benchmark.target.result);
161 #if 0
162 { to keep editor happy
163 #endif
166 #endif