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 12 #include <dune/common/exceptions.hh> 13 #include <dune/common/ios_state.hh> 14 15 #include <ctime> 16 17 namespace Dune { 18 namespace PDELab { 19 20 struct CppClockWallTimeSource 21 { 22 operator ()Dune::PDELab::CppClockWallTimeSource23 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 operator ()Dune::PDELab::MPIWallTimeSource36 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 elapsedDune::PDELab::Timing56 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 BenchmarkHelperDune::PDELab::BenchmarkHelper76 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 start_runDune::PDELab::BenchmarkHelper87 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 start_runDune::PDELab::BenchmarkHelper97 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 end_runDune::PDELab::BenchmarkHelper105 void end_run() 106 { 107 _run_times.timings[_run].end = _time(); 108 ++_run; 109 } 110 end_runDune::PDELab::BenchmarkHelper111 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 startDune::PDELab::BenchmarkHelper118 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 startDune::PDELab::BenchmarkHelper130 void start(std::string task, std::ostream& s) 131 { 132 start(task); 133 } 134 endDune::PDELab::BenchmarkHelper135 void end(std::string task) 136 { 137 _tasks[task].timings[_run].end = _time(); 138 _statistics_stale = true; 139 } 140 endDune::PDELab::BenchmarkHelper141 void end(std::string task, std::ostream& s) 142 { 143 end(task); 144 s << "." << std::flush; 145 } 146 update_entryDune::PDELab::BenchmarkHelper147 void update_entry(BenchmarkEntry& entry) 148 { 149 entry.min = std::numeric_limits<double>::max(); 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 update_statisticsDune::PDELab::BenchmarkHelper170 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 print_entryDune::PDELab::BenchmarkHelper186 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 printDune::PDELab::BenchmarkHelper206 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 252