+ EQ-5: refactoring to eliminate code duplication, side effect: stereo meters
[calf.git] / src / calf / benchmark.h
blob0da28366a4b9cf6fe38603ab9adfe3ee5b637d97
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 "primitives.h"
28 #include <algorithm>
29 #include <typeinfo>
31 namespace dsp {
32 #if 0
33 }; to keep editor happy
34 #endif
37 class median_stat
39 public:
40 double *data;
41 unsigned int pos, count;
42 bool sorted;
44 median_stat() {
45 data = NULL;
46 pos = 0;
47 count = 0;
48 sorted = false;
50 void start(int items) {
51 if (data)
52 delete []data;
53 data = new double[items];
54 pos = 0;
55 count = items;
56 sorted = false;
58 void add(double value)
60 assert(pos < count);
61 data[pos++] = value;
63 void end()
65 std::sort(&data[0], &data[count]);
66 sorted = true;
68 float get()
70 assert(sorted);
71 return data[count >> 1];
75 // USE_RDTSC is for testing on my own machine, a crappy 1.6GHz Pentium 4 - it gives less headaches than clock() based measurements
76 #define USE_RDTSC 0
77 #define CLOCK_SPEED (1.6 * 1000.0 * 1000.0 * 1000.0)
79 #if USE_RDTSC
80 inline uint64_t rdtsc()
82 unsigned long long int x;
83 __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
84 return x;
86 #endif
88 struct benchmark_globals
90 static bool warned;
93 template<typename Target, class Stat>
94 class simple_benchmark: public benchmark_globals
96 public:
97 Target target;
98 Stat &stat;
100 simple_benchmark(const Target &_target, Stat &_stat)
101 : target(_target)
102 , stat(_stat)
106 void measure(int runs, int repeats)
108 int priority = getpriority(PRIO_PROCESS, getpid());
109 stat.start(runs);
110 if (setpriority(PRIO_PROCESS, getpid(), -20) < 0) {
111 if (!warned) {
112 fprintf(stderr, "Warning: could not set process priority, measurements can be worthless\n");
113 warned = true;
116 for (int i = 0; i < runs; i++) {
117 target.prepare();
118 // XXXKF measuring CPU time with clock() sucks,
119 #if USE_RDTSC
120 uint64_t start = rdtsc();
121 #else
122 clock_t start = ::clock();
123 #endif
124 for (int j = 0; j < repeats; j++) {
125 target.run();
127 #if USE_RDTSC
128 uint64_t end = rdtsc();
129 double elapsed = double(end - start) / (CLOCK_SPEED * repeats * target.scaler());
130 #else
131 clock_t end = ::clock();
132 double elapsed = double(end - start) / (double(CLOCKS_PER_SEC) * repeats * target.scaler());
133 #endif
134 stat.add(elapsed);
135 target.cleanup();
136 // printf("elapsed = %f start = %d end = %d diff = %d\n", elapsed, start, end, end - start);
138 setpriority(PRIO_PROCESS, getpid(), priority);
139 stat.end();
142 float get_stat()
144 return stat.get();
148 template<class T>
149 void do_simple_benchmark(int runs = 5, int repeats = 50000)
151 dsp::median_stat stat;
152 dsp::simple_benchmark<T, dsp::median_stat> benchmark(T(), stat);
154 benchmark.measure(runs, repeats);
156 printf("%-30s: %f/sec, %f/CDsr, value = %f\n", typeid(T).name(), 1.0 / stat.get(), 1.0 / (44100 * stat.get()), benchmark.target.result);
160 #if 0
161 { to keep editor happy
162 #endif
165 #endif