DUNE PDELab (git)

benchmarkhelper.hh
1#ifndef DUNE_PDELAB_COMMON_BENCHMARKHELPER_HH
2#define DUNE_PDELAB_COMMON_BENCHMARKHELPER_HH
3
4#include <ostream>
5#include <iomanip>
6#include <map>
7#include <string>
8#include <vector>
9#include <limits>
10#include <cmath>
11
14
15#include <ctime>
16
17namespace Dune {
18 namespace PDELab {
19
20 struct CppClockWallTimeSource
21 {
22
23 double operator()() const
24 {
25 return static_cast<double>(std::clock()) / static_cast<double>(CLOCKS_PER_SEC);
26 }
27
28 };
29
30#if HAVE_MPI
31#include"mpi.h"
32
33 struct MPIWallTimeSource
34 {
35
36 double operator()() const
37 {
38 return MPI_Wtime();
39 }
40
41 };
42
43 typedef MPIWallTimeSource DefaultTimeSource;
44
45#else
46
47 typedef CppClockWallTimeSource DefaultTimeSource;
48
49#endif
50
51 struct Timing
52 {
53 double start;
54 double end;
55
56 double elapsed() const
57 {
58 return end - start;
59 }
60
61 };
62
63 struct BenchmarkEntry
64 {
65 std::vector<Timing> timings;
66 double min;
67 double max;
68 double avg;
69 double std_dev;
70 };
71
72 template<typename TimeSource = DefaultTimeSource>
73 struct BenchmarkHelper
74 {
75
76 BenchmarkHelper(std::string name, std::size_t max_runs = 1, TimeSource timeSource = TimeSource())
77 : _name(name)
78 , _time(timeSource)
79 , _run(0)
80 , _max_runs(max_runs)
81 , _statistics_stale(true)
82 {
83 _run_times.timings.resize(max_runs);
84 }
85
86
87 void start_run()
88 {
89 if (_run >= _max_runs)
90 {
91 DUNE_THROW(Dune::RangeError,"maximum number of benchmark runs exceeded");
92 }
93 _statistics_stale = true;
94 _run_times.timings[_run].start = _time();
95 }
96
97 void start_run(std::ostream& s)
98 {
99 start_run();
100 ios_base_all_saver ios_saver(s);
101 s << _name << " (" << std::setw(2) << _run << " of " << std::setw(2) << _max_runs << ") " << std::flush;
102 }
103
104
105 void end_run()
106 {
107 _run_times.timings[_run].end = _time();
108 ++_run;
109 }
110
111 void end_run(std::ostream& s)
112 {
113 end_run();
114 ios_base_all_saver ios_saver(s);
115 s << " " << std::setw(10) << std::setprecision(3) << _run_times.timings[_run-1].elapsed() << " sec" << std::endl;
116 }
117
118 void start(std::string task)
119 {
120 std::pair<
121 std::map<std::string,BenchmarkEntry>::iterator,
122 bool
123 > res = _tasks.insert(make_pair(task,BenchmarkEntry()));
124 if (res.second)
125 res.first->second.timings.resize(_max_runs);
126 res.first->second.timings[_run].start = _time();
127 _statistics_stale = true;
128 }
129
130 void start(std::string task, std::ostream& s)
131 {
132 start(task);
133 }
134
135 void end(std::string task)
136 {
137 _tasks[task].timings[_run].end = _time();
138 _statistics_stale = true;
139 }
140
141 void end(std::string task, std::ostream& s)
142 {
143 end(task);
144 s << "." << std::flush;
145 }
146
147 void update_entry(BenchmarkEntry& entry)
148 {
150 entry.max = 0;
151 entry.avg = 0;
152 entry.std_dev = 0;
153
154 for (std::vector<Timing>::iterator it = entry.timings.begin(), end = entry.timings.end();
155 it != end;
156 ++it)
157 {
158 const double elapsed = it->elapsed();
159 entry.min = std::min(entry.min,elapsed);
160 entry.max = std::max(entry.max,elapsed);
161 entry.avg += elapsed;
162 entry.std_dev += elapsed*elapsed;
163 }
164
165 entry.avg /= entry.timings.size();
166 entry.std_dev /= entry.timings.size();
167 entry.std_dev = std::sqrt(entry.std_dev - entry.avg*entry.avg);
168 }
169
170 void update_statistics()
171 {
172 _max_name_len = 5; // strlen("total")
173 for (std::map<std::string,BenchmarkEntry>::iterator it = _tasks.begin(), end = _tasks.end();
174 it != end;
175 ++it)
176 {
177 _max_name_len = std::max(_max_name_len,it->first.size());
178 update_entry(it->second);
179 }
180
181 update_entry(_run_times);
182
183 _statistics_stale = false;
184 }
185
186 void print_entry(std::ostream& s, std::string name, const BenchmarkEntry& entry, bool summary_only = false) const
187 {
188 s << std::setw(_max_name_len + 1) << std::left << name
189 << std::right << std::scientific << std::setw(10) << std::setprecision(2);
190 if (!summary_only)
191 for (std::vector<Timing>::const_iterator it = entry.timings.begin(),
192 end = entry.timings.end();
193 it != end;
194 ++it)
195 {
196 s << std::setw(10) << it->elapsed();
197 }
198 s << std::setw(10) << entry.min
199 << std::setw(10) << entry.max
200 << std::setw(10) << entry.avg
201 << std::setw(10) << entry.std_dev;
202
203 s << std::endl;
204 }
205
206 void print(std::ostream& s, bool summary_only = false)
207 {
208 ios_base_all_saver ios_saver(s);
209
210 if (_statistics_stale)
211 update_statistics();
212
213 s << _name << " (" << std::setw(2) << _run << " of " << std::setw(2) << _max_runs << ") runs" << std::endl;
214
215 s << std::setw(_max_name_len + 1) << "";
216
217 if (!summary_only)
218 for (std::size_t i = 0; i < _max_runs; ++i)
219 s << std::setw(10) << i;
220
221 s << std::setw(10) << "min"
222 << std::setw(10) << "max"
223 << std::setw(10) << "avg"
224 << std::setw(10) << "std_dev" << std::endl;
225
226 for (std::map<std::string,BenchmarkEntry>::const_iterator it = _tasks.begin(), end = _tasks.end();
227 it != end;
228 ++it)
229 print_entry(s,it->first,it->second,summary_only);
230
231 print_entry(s,"total",_run_times,summary_only);
232 }
233
234 private:
235 const std::string _name;
236 TimeSource _time;
237 std::size_t _run;
238 const std::size_t _max_runs;
239 std::map<std::string,BenchmarkEntry> _tasks;
240 bool _statistics_stale;
241 BenchmarkEntry _run_times;
242 std::size_t _max_name_len;
243
244 };
245
246
247
248 } // namespace PDELAB
249} // namespace Dune
250
251#endif // DUNE_PDELAB_COMMON_BENCHMARKHELPER_HH
Default exception class for range errors.
Definition: exceptions.hh:254
A few common exception classes.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:506
Utility class for storing and resetting stream attributes.
Dune namespace.
Definition: alignedallocator.hh:13
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 12, 23:30, 2024)