QMCPACK
test_timer.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Mark Dewing, markdewing@gmail.com, Argonne National Laboratory
8 //
9 // File created by: Mark Dewing, markdewing@gmail.com, Argonne National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 #include "catch.hpp"
14 
15 #include <string>
16 #include <vector>
17 #include "Utilities/TimerManager.h"
18 
19 using namespace std::chrono_literals;
20 
21 namespace qmcplusplus
22 {
24 
25 template<class CLOCK>
26 void set_total_time(TimerType<CLOCK>* timer, double total_time_input)
27 {
28  timer->total_time = total_time_input;
29 }
30 
31 template<class CLOCK>
32 void set_num_calls(TimerType<CLOCK>* timer, long num_calls_input)
33 {
34  timer->num_calls = num_calls_input;
35 }
36 
37 // Convert duration input type to nanosecond duration
38 template<typename T>
39 FakeChronoClock::duration convert_to_ns(T in)
40 {
41  return std::chrono::duration_cast<std::chrono::nanoseconds>(in);
42 }
43 
44 // Convert duration input type to seconds as double precision type
45 template<typename T>
46 double convert_to_s(T in)
47 {
48  return std::chrono::duration_cast<std::chrono::duration<double>>(in).count();
49 }
50 
51 TEST_CASE("test_timer_stack", "[utilities]")
52 {
53  // Use a local version rather than the global timer_manager, otherwise
54  // changes will persist from test to test.
56  FakeTimer* t1 = tm.createTimer("timer1", timer_level_coarse);
57 #if defined(ENABLE_TIMERS)
58 #ifdef USE_STACK_TIMERS
59  t1->start();
60  REQUIRE(tm.current_timer() == t1);
61  t1->stop();
62  REQUIRE(tm.current_timer() == NULL);
63 #endif
64 #endif
65 }
66 
67 TEST_CASE("test_timer_scoped", "[utilities]")
68 {
70  FakeTimer* t1 = tm.createTimer("timer1", timer_level_coarse);
71  {
72  ScopedFakeTimer st(*t1);
73  }
74 #if defined(ENABLE_TIMERS)
75  CHECK(t1->get_total() == Approx(1.0));
76  REQUIRE(t1->get_num_calls() == 1);
77 #endif
78 
79 
80  const std::string prefix_str("Prefix::");
81  FakeTimer& t2(*(tm.createTimer(prefix_str + "timer2", timer_level_coarse)));
82  {
83  ScopedFakeTimer st(t2);
84  }
85 #if defined(ENABLE_TIMERS)
86  CHECK(t1->get_total() == Approx(1.0));
87  REQUIRE(t1->get_num_calls() == 1);
88 #endif
89 }
90 
91 TEST_CASE("test_timer_flat_profile", "[utilities]")
92 {
94  FakeTimer* t1 = tm.createTimer("timer1");
95  set_total_time(t1, 1.1);
96  set_num_calls(t1, 2);
97 
99  tm.collate_flat_profile(NULL, p);
100 
101  REQUIRE(p.nameList.size() == 1);
102  REQUIRE(p.nameList.at("timer1") == 0);
103  REQUIRE(p.timeList.size() == 1);
104  CHECK(p.timeList[0] == Approx(1.1));
105  REQUIRE(p.callList.size() == 1);
106  REQUIRE(p.callList[0] == 2);
107 }
108 
109 TEST_CASE("test_timer_flat_profile_same_name", "[utilities]")
110 {
111  FakeTimerManager tm;
113  FakeTimer* t1 = tm.createTimer("timer1");
114  FakeTimer* t2 = tm.createTimer("timer2");
115  FakeTimer* t3 = tm.createTimer("timer1");
116 
117  FakeChronoClock::fake_chrono_clock_increment = convert_to_ns(1.1s);
118  t1->start();
119  t1->stop();
120  FakeChronoClock::fake_chrono_clock_increment = convert_to_ns(1.2s);
121  for (int i = 0; i < 3; i++)
122  {
123  t2->start();
124  t2->stop();
125 
126  t3->start();
127  t3->stop();
128  }
129  t3->start();
130  t3->stop();
131 
133 
134  tm.collate_flat_profile(NULL, p);
135 
136 #ifdef ENABLE_TIMERS
137  REQUIRE(p.nameList.size() == 2);
138  int idx1 = p.nameList.at("timer1");
139  int idx2 = p.nameList.at("timer2");
140  REQUIRE(p.timeList.size() == 2);
141  CHECK(p.timeList[idx1] == Approx(5.9));
142  CHECK(p.timeList[idx2] == Approx(3.6));
143 
144  REQUIRE(p.callList.size() == 2);
145  REQUIRE(p.callList[idx1] == 5);
146  REQUIRE(p.callList[idx2] == 3);
147 #endif
148 }
149 
150 TEST_CASE("test_timer_nested_profile", "[utilities]")
151 {
152  FakeTimerManager tm;
154  FakeTimer* t1 = tm.createTimer("timer1");
155  FakeTimer* t2 = tm.createTimer("timer2");
156 
157  FakeChronoClock::fake_chrono_clock_increment = convert_to_ns(1.1s);
158  t1->start();
159  t2->start();
160  t2->stop();
161  t1->stop();
162 
164  tm.collate_flat_profile(NULL, p);
165 
166 #ifdef ENABLE_TIMERS
167  REQUIRE(p.nameList.size() == 2);
168  int idx1 = p.nameList.at("timer1");
169  int idx2 = p.nameList.at("timer2");
170  REQUIRE(p.timeList.size() == 2);
171  CHECK(p.timeList[idx1] == Approx(3 * convert_to_s(FakeChronoClock::fake_chrono_clock_increment)));
172  CHECK(p.timeList[idx2] == Approx(convert_to_s(FakeChronoClock::fake_chrono_clock_increment)));
173 #endif
174 
176  tm.collate_stack_profile(NULL, p2);
177 
178 #ifdef ENABLE_TIMERS
179  REQUIRE(p2.nameList.size() == 2);
180  idx1 = p2.nameList.at("timer1");
181  idx2 = p2.nameList.at("timer1/timer2");
182  REQUIRE(p2.timeList.size() == 2);
183  REQUIRE(p2.timeExclList.size() == 2);
184  CHECK(p2.timeList[idx1] == Approx(convert_to_s(3 * FakeChronoClock::fake_chrono_clock_increment)));
185  CHECK(p2.timeList[idx2] == Approx(convert_to_s(FakeChronoClock::fake_chrono_clock_increment)));
186 
187  // Time in t1 minus time inside t2
188  CHECK(p2.timeExclList[idx1] == Approx(2 * convert_to_s(FakeChronoClock::fake_chrono_clock_increment)));
189  CHECK(p2.timeExclList[idx2] == Approx(convert_to_s(FakeChronoClock::fake_chrono_clock_increment)));
190 #endif
191 }
192 
193 TEST_CASE("test_timer_nested_profile_two_children", "[utilities]")
194 {
195  FakeTimerManager tm;
197  FakeTimer* t1 = tm.createTimer("timer1");
198  FakeTimer* t2 = tm.createTimer("timer2");
199  FakeTimer* t3 = tm.createTimer("timer3");
200 
201  FakeChronoClock::fake_chrono_clock_increment = convert_to_ns(1.1s);
202  t1->start();
203  t2->start();
204  t2->stop();
205  t3->start();
206  t3->stop();
207  t1->stop();
208 
210  tm.collate_stack_profile(NULL, p2);
211 
212 #ifdef ENABLE_TIMERS
213  REQUIRE(p2.names.size() == 3);
214  REQUIRE(p2.names[0] == "timer1");
215  REQUIRE(p2.names[1] == "timer1/timer2");
216  REQUIRE(p2.names[2] == "timer1/timer3");
217 #endif
218 
219 
221  doc.newDoc("resources");
222  tm.output_timing(NULL, doc, doc.getRoot());
223  doc.dump("tmp.xml");
224  // To really test this, should read the file in and inspect the contents.
225  // For now, it makes for quick iterations on writing the file.
226 }
227 
228 TEST_CASE("test_timer_nested_profile_alt_routes", "[utilities]")
229 {
230  FakeTimerManager tm;
232  FakeTimer* t1 = tm.createTimer("timer1");
233  FakeTimer* t2 = tm.createTimer("timer2");
234  FakeTimer* t3 = tm.createTimer("timer3");
235  FakeTimer* t4 = tm.createTimer("timer4");
236  FakeTimer* t5 = tm.createTimer("timer5");
237 
238 
239  FakeChronoClock::fake_chrono_clock_increment = convert_to_ns(1.1s);
240  t1->start();
241  t2->start();
242  t3->start();
243  t4->start();
244  t4->stop();
245  t5->start();
246  t5->stop();
247  t3->stop();
248  t2->stop();
249  t3->start();
250  t4->start();
251  t4->stop();
252  t3->stop();
253  t1->stop();
254 
256  tm.collate_stack_profile(NULL, p2);
257  //tm.print_stack(NULL);
258 #ifdef ENABLE_TIMERS
259  REQUIRE(p2.names.size() == 7);
260  REQUIRE(p2.names[0] == "timer1");
261  REQUIRE(p2.names[1] == "timer1/timer2");
262  REQUIRE(p2.names[2] == "timer1/timer2/timer3");
263  REQUIRE(p2.names[3] == "timer1/timer2/timer3/timer4");
264  REQUIRE(p2.names[4] == "timer1/timer2/timer3/timer5");
265  REQUIRE(p2.names[5] == "timer1/timer3");
266  REQUIRE(p2.names[6] == "timer1/timer3/timer4");
267 
268  CHECK(p2.timeList[0] == Approx(14.3));
269  CHECK(p2.timeExclList[0] == Approx(3.3));
270  CHECK(p2.timeList[1] == Approx(7.7));
271  CHECK(p2.timeExclList[1] == Approx(2.2));
272 #endif
273 
275  doc.newDoc("resources");
276  tm.output_timing(NULL, doc, doc.getRoot());
277  doc.dump("tmp2.xml");
278 }
279 
280 TEST_CASE("test_timer_nested_profile_collate", "[utilities]")
281 {
282  FakeTimerManager tm;
284  FakeTimer* t1 = tm.createTimer("timer1");
285  FakeTimer* t2 = tm.createTimer("timer2");
286  FakeTimer* t2b = tm.createTimer("timer2");
287  FakeTimer* t3 = tm.createTimer("timer3");
288 
289 
290  FakeChronoClock::fake_chrono_clock_increment = convert_to_ns(1.1s);
291  t1->start();
292  t2->start();
293  t3->start();
294  t3->stop();
295  t2->stop();
296  t2b->start();
297  t3->start();
298  t3->stop();
299  t2b->stop();
300  t2->start();
301  t3->start();
302  t3->stop();
303  t2->stop();
304  t2b->start();
305  t3->start();
306  t3->stop();
307  t2b->stop();
308  t1->stop();
309 
310 
312  tm.collate_stack_profile(NULL, p2);
313  //tm.print_stack(NULL);
314 #ifdef ENABLE_TIMERS
315  REQUIRE(p2.names.size() == 3);
316  REQUIRE(p2.names[0] == "timer1");
317  REQUIRE(p2.names[1] == "timer1/timer2");
318  REQUIRE(p2.names[2] == "timer1/timer2/timer3");
319 #endif
320 
322  doc.newDoc("resources");
323  tm.output_timing(NULL, doc, doc.getRoot());
324  doc.dump("tmp3.xml");
325 }
326 
327 #ifdef ENABLE_TIMERS
328 TEST_CASE("test stack key")
329 {
330  StackKey sk;
332  for (int i = 0; i < StackKey::max_level + 1; i++)
333  {
334  sk.add_id(1);
335  }
337 }
338 
339 TEST_CASE("test stack exceeded message")
340 {
341  FakeTimerManager tm;
342  tm.set_timer_threshold(timer_level_fine);
343  std::vector<FakeTimer*> timer_list;
344  for (int i = 0; i < StackKey::max_level + 1; i++)
345  {
346  std::ostringstream name;
347  name << "timer" << i;
348  FakeTimer* t = tm.createTimer(name.str());
349  timer_list.push_back(t);
350  }
351 
352  for (int i = 0; i < StackKey::max_level + 1; i++)
353  timer_list[i]->start();
354 
355  for (int i = StackKey::max_level; i >= 0; i--)
356  timer_list[i]->stop();
357 
359 
360  //tm.print_stack(NULL);
361 
363  doc.newDoc("resources");
364  tm.output_timing(NULL, doc, doc.getRoot());
365  doc.dump("tmp4.xml");
366 }
367 
368 TEST_CASE("test max exceeded message")
369 {
370  FakeTimerManager tm;
371  tm.set_timer_threshold(timer_level_fine);
372  std::vector<FakeTimer*> timer_list;
373  for (int i = 0; i < std::numeric_limits<timer_id_t>::max() + 1; i++)
374  {
375  std::ostringstream name;
376  name << "timer" << i;
377  FakeTimer* t = tm.createTimer(name.str());
378  timer_list.push_back(t);
379  }
380 
382  doc.newDoc("resources");
383  tm.output_timing(NULL, doc, doc.getRoot());
384  doc.dump("tmp5.xml");
385 }
386 #endif
387 
388 // Define a list of timers indexed by an enum
389 // First, define an enum with the timers
391 {
394 };
395 
396 // Next define a structure mapping the enum to a string name
397 TimerNameList_t<TestTimer> TestTimerNames = {{MyTimer1, "Timer name 1"}, {MyTimer2, "Timer name 2"}};
398 
399 TEST_CASE("test setup timers", "[utilities]")
400 {
401  FakeTimerManager tm;
402  // Create a list of timers and initialize it
404 
405  FakeChronoClock::fake_chrono_clock_increment = convert_to_ns(1.0s);
406  Timers[MyTimer1].get().start();
407  Timers[MyTimer1].get().stop();
408 
409 #ifdef ENABLE_TIMERS
410  CHECK(Timers[MyTimer1].get().get_total() == Approx(1.0));
411  REQUIRE(Timers[MyTimer1].get().get_num_calls() == 1);
412 #endif
413 }
414 
415 } // namespace qmcplusplus
class that handles xmlDoc
Definition: Libxml2Doc.h:76
long get_num_calls() const
Definition: NewTimer.h:179
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
TimerType< FakeChronoClock > FakeTimer
Definition: NewTimer.h:235
timer_manager class.
void output_timing(Communicate *comm, Libxml2Document &doc, xmlNodePtr root)
std::vector< TimerIDName_t< T > > TimerNameList_t
Definition: TimerManager.h:156
void collate_stack_profile(Communicate *comm, StackProfileData &p)
void newDoc(const std::string &rootName)
Definition: Libxml2Doc.cpp:93
long num_calls
total call counts
Definition: NewTimer.h:143
xmlNodePtr getRoot()
Definition: Libxml2Doc.h:88
Timer accumulates time and call counts.
Definition: NewTimer.h:135
Manager creates timers and handle reports.
Definition: NewTimer.h:40
FakeChronoClock::duration convert_to_ns(T in)
REQUIRE(std::filesystem::exists(filename))
TimerNameList_t< TestTimer > TestTimerNames
Definition: test_timer.cpp:397
void collate_flat_profile(Communicate *comm, FlatProfileData &p)
bool timer_max_level_exceeded
Definition: NewTimer.cpp:26
double total_time
total time accumulated of all the calls
Definition: NewTimer.h:141
TIMER * createTimer(const std::string &myname, timer_levels mytimer=timer_level_fine)
Create a new timer object registred in this manager. This call is thread-safe.
CHECK(log_values[0]==ComplexApprox(std::complex< double >{ 5.603777579195571, -6.1586603331188225 }))
void set_timer_threshold(const timer_levels threshold)
double get_total() const
Definition: NewTimer.h:178
StackKeyParam< 2 > StackKey
Definition: NewTimer.h:129
TimerManager< FakeTimer > FakeTimerManager
Definition: test_timer.cpp:23
void dump(const std::string &newxml)
Definition: Libxml2Doc.cpp:109
TEST_CASE("test setup timers", "[utilities]")
Definition: test_timer.cpp:399
void set_total_time(TimerType< CLOCK > *timer, double total_time_input)
Definition: test_timer.cpp:26
double convert_to_s(T in)
Definition: test_timer.cpp:46
void set_num_calls(TimerType< CLOCK > *timer, long num_calls_input)
Definition: test_timer.cpp:32