Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TimeMonitor_UnitTests.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teuchos_TimeMonitor.hpp"
11 #include "Teuchos_DefaultComm.hpp"
14 
15 // slowLoop does not reliably make a timer nonzero (RHEL6, gcc 4.4.7, OpenMPI 1.5.4).
16 // Thus, I'm introducing headers to make sleep() available.
17 #ifndef ICL
18 #include <unistd.h>
19 #else
20 void sleep(int sec)
21 {
22  Sleep(sec);
23 }
24 #endif
25 
26 #ifdef _MSC_VER
27 #pragma comment(lib, "Ws2_32.lib")
28 # include <Winsock2.h>
29 # include <process.h>
30 void sleep(int sec)
31 {
32  Sleep(sec * 1000);
33 }
34 #endif
35 
36 #ifdef HAVE_TEUCHOS_TIMER_KOKKOS_FENCE
37 #include "Kokkos_Core.hpp"
38 #endif
39 
40 namespace {
41 
42  void func_time_monitor1()
43  {
44  TEUCHOS_FUNC_TIME_MONITOR("FUNC_TIME_MONITOR1");
45  }
46 
47 
48  void func_time_monitor2()
49  {
50  TEUCHOS_FUNC_TIME_MONITOR("FUNC_TIME_MONITOR2");
51  {
52  TEUCHOS_FUNC_TIME_MONITOR_DIFF("FUNC_TIME_MONITOR2_inner", inner);
53  }
54  }
55 
56  // This function is commented out because no code in this file
57  // actually uses it. Commenting it out avoids compiler warnings
58  // ("unused function").
59 #if 0
60  // Slowly compute the n-th Fibonacci number. This gives timers
61  // something to time. Be careful not to make n too large, or you'll
62  // run out of stack space.
63  int
64  fib (const int n)
65  {
66  if (n <= 0) {
67  return 0;
68  } else if (n == 1) {
69  return 1;
70  }
71  else {
72  // You should never compute the n-th Fibonacci number like this.
73  // This is exponentially slow in n. The point of using a slow
74  // algorithm like this is to exercise timers.
75  return fib (n-1) + fib (n-2);
76  }
77  }
78 #endif // 0
79 
80  // Do a number of arithmetic operations proportional to n^3, in
81  // order to have something to time. Unlike the recursive function
82  // fib() commented out above, this function shouldn't take up a lot
83  // of stack space.
84  double
85  slowLoop (const size_t n)
86  {
87  const double inc = 1 / static_cast<double> (n);
88  double x = 1.0;
89 
90  for (size_t i = 0; i < n; ++i) {
91  for (size_t j = 0; j < n; ++j) {
92  for (size_t k = 0; k < n; ++k) {
93  x = x + inc;
94  }
95  }
96  }
97  return x;
98  }
99 
100 } // namespace (anonymous)
101 
102 
103 namespace Teuchos {
104  //
105  // Basic TimeMonitor test: create and exercise a timer on all (MPI)
106  // processes, and make sure that TimeMonitor::summarize() reports it.
107  //
108  TEUCHOS_UNIT_TEST( TimeMonitor, FUNC_TIME_MONITOR )
109  {
111  using Teuchos::parameterList;
112  using Teuchos::RCP;
113 
114  func_time_monitor1 (); // Function to time.
115 
116  { // Repeat test for default output format.
117  std::ostringstream oss;
119 
120  // Echo summarize() output to the FancyOStream out (which is a
121  // standard unit test argument). Output should only appear in
122  // show-all-test-details mode.
123  out << oss.str () << std::endl;
124 
125  // Make sure that the timer's name shows up in the output.
127  const size_t substr_i = oss.str ().find ("FUNC_TIME_MONITOR1");
128  TEST_INEQUALITY(substr_i, std::string::npos);
129  }
130  }
131 
132  { // Repeat test for YAML output, compact style.
133  std::ostringstream oss;
134  RCP<ParameterList> reportParams =
135  parameterList (* (TimeMonitor::getValidReportParameters ()));
136  reportParams->set ("Report format", "YAML");
137  reportParams->set ("YAML style", "compact");
138  TimeMonitor::report (oss, reportParams);
139 
140  // Echo output to the FancyOStream out (which is a standard unit
141  // test argument). Output should only appear in "show all test
142  // details" mode.
143  out << oss.str () << std::endl;
144 
145  // Make sure that the timer's name shows up in the output.
146  const size_t substr_i = oss.str ().find ("FUNC_TIME_MONITOR1");
147  TEST_INEQUALITY(substr_i, std::string::npos);
148  }
149 
150  { // Repeat test for YAML output, spacious style.
151  std::ostringstream oss;
152  RCP<ParameterList> reportParams =
153  parameterList (* (TimeMonitor::getValidReportParameters ()));
154  reportParams->set ("Report format", "YAML");
155  reportParams->set ("YAML style", "spacious");
156  TimeMonitor::report (oss, reportParams);
157 
158  // Echo output to the FancyOStream out (which is a standard unit
159  // test argument). Output should only appear in "show all test
160  // details" mode.
161  out << oss.str () << std::endl;
162 
163  // Make sure that the timer's name shows up in the output.
164  const size_t substr_i = oss.str ().find ("FUNC_TIME_MONITOR1");
165  TEST_INEQUALITY(substr_i, std::string::npos);
166  }
167 
168  // This sets up for the next unit test.
170  }
171 
172  //
173  // Test for TimeMonitor's enableTimer and disableTimer methods.
174  //
176  {
177  using Teuchos::Array;
178  using Teuchos::OSTab;
180  using Teuchos::parameterList;
181  using Teuchos::RCP;
182  using Teuchos::rcpFromRef;
183  using Teuchos::Time;
184  using Teuchos::TimeMonitor;
185  using std::endl;
186  typedef Teuchos::Array<RCP<Time> >::size_type size_type;
187 
188  out << "Testing TimeMonitor's disableTimer() and enableTimer() methods"
189  << endl;
190  OSTab (rcpFromRef (out));
191 
192  out << "Creating timers" << endl;
193  const int numTrials = 5;
194  const int numTimers = 3;
195  Array<RCP<Time> > timers (numTimers);
196  for (size_type i = 0; i < numTimers; ++i) {
197  std::ostringstream os; // construct timer name
198  os << "Timer " << i;
199  timers[i] = TimeMonitor::getNewTimer (os.str ());
200  }
201 
202  out << "Running all timers without disabling any" << endl;
203  // The actual number of operations in slowloop is proportional to
204  // the cube of the loop length. Adjust loopLength as necessary to
205  // ensure the timer reports a nonzero elapsed time for each of the
206  // invocations.
207  const size_t loopLength = 25;
208  for (int k = 0; k < numTrials; ++k) {
209  for (size_type i = 0; i < numTimers; ++i) {
210  TimeMonitor timeMon (* timers[i]);
211  slowLoop (loopLength);
212  }
213  }
214  for (size_type i = 0; i < numTimers; ++i) {
215  TEST_EQUALITY( timers[i]->numCalls(), numTrials );
216  }
217 
218  out << "Disabling one timer and trying again" << endl;
219  // Disable timers[0] only, and repeat the above loops.
221  for (int k = 0; k < numTrials; ++k) {
222  for (size_type i = 0; i < numTimers; ++i) {
223  TimeMonitor timeMon (* timers[i]);
224  slowLoop (loopLength);
225  }
226  }
227  TEST_EQUALITY( timers[0]->numCalls(), numTrials );
228  for (size_type i = 1; i < numTimers; ++i) {
229  TEST_EQUALITY( timers[i]->numCalls(), 2*numTrials );
230  }
231 
232  out << "Reenabling the timer and trying again" << endl;
233  // Enable timers[0] and repeat the above loops.
234  TEST_NOTHROW( TimeMonitor::enableTimer ("Timer 0") );
235  for (int k = 0; k < numTrials; ++k) {
236  for (size_type i = 0; i < numTimers; ++i) {
237  TimeMonitor timeMon (* timers[i]);
238  slowLoop (loopLength);
239  }
240  }
241  TEST_EQUALITY( timers[0]->numCalls(), 2*numTrials );
242  for (size_type i = 1; i < numTimers; ++i) {
243  TEST_EQUALITY( timers[i]->numCalls(), 3*numTrials );
244  }
245 
246  out << "Test that summarize() reports enabled and disabled timers" << endl;
247  // Make sure that summarize() reports all timers. Disabling a
248  // timer must _not_ exclude it from the list of timers printed by
249  // summarize(). Disable a different timer this time just for fun.
251  {
252  std::ostringstream oss;
254 
255  // Echo summarize() output to the FancyOStream out (which is a
256  // standard unit test argument). Output should only appear in
257  // show-all-test-details mode.
258  out << oss.str () << std::endl;
259 
260  // Make sure that each timer's name shows up in the output.
261  for (size_type i = 0; i < numTimers; ++i) {
262  const std::string name = timers[i]->name ();
264  const size_t substr_i = oss.str ().find (name);
265  TEST_INEQUALITY(substr_i, std::string::npos);
266  }
267  }
268  }
269 
270  // This sets up for the next unit test.
272  }
273 
274 
275  //
276  // Test correct quoting of labels for TimeMonitor's YAML output.
277  //
278  TEUCHOS_UNIT_TEST( TimeMonitor, YamlLabelQuoting )
279  {
280  using Teuchos::Array;
282  using Teuchos::parameterList;
283  using Teuchos::RCP;
284  using Teuchos::Time;
285  typedef Array<std::string>::size_type size_type;
286 
287  Array<std::string> inputLabels, outputLabels;
288 
289  // Make sure to exercise things that don't need quoting, like
290  // spaces and certain punctuation, as well as things that do need
291  // quoting, like colons, inner double quotes, and backslashes.
292  inputLabels.push_back ("NoQuotingNeeded");
293  inputLabels.push_back ("No quoting needed");
294  inputLabels.push_back ("\"AlreadyQuotedNoQuotingNeeded\"");
295  inputLabels.push_back ("\"Already quoted, no quoting needed\"");
296  inputLabels.push_back ("\"Already quoted: quoting needed\"");
297  inputLabels.push_back ("NotQuoted:QuotingNeeded");
298  inputLabels.push_back ("Not quoted: quoting needed");
299  // Test both individual double quotes, and pairs of double quotes.
300  inputLabels.push_back ("Not quoted \" quoting needed");
301  inputLabels.push_back ("Not quoted \" \" quoting needed");
302  inputLabels.push_back ("\"Already quoted \" quoting needed\"");
303  inputLabels.push_back ("\"Already quoted \" \" quoting needed\"");
304  // Remember that in C strings, a double backslash turns into a
305  // single backslash. Our YAML output routine should turn each
306  // single backslash back into a double backslash.
307  inputLabels.push_back ("Not quoted \\ quoting needed");
308  inputLabels.push_back ("Not quoted \\\\ quoting needed");
309  inputLabels.push_back ("Not quoted \\ \\ quoting needed");
310  inputLabels.push_back ("\"Already quoted \\ quoting needed\"");
311  inputLabels.push_back ("\"Already quoted \\\\ quoting needed\"");
312  inputLabels.push_back ("\"Already quoted \\ \\ quoting needed\"");
313 
314  outputLabels.push_back ("NoQuotingNeeded");
315  outputLabels.push_back ("No quoting needed");
316  outputLabels.push_back ("\"AlreadyQuotedNoQuotingNeeded\"");
317  outputLabels.push_back ("\"Already quoted, no quoting needed\"");
318  outputLabels.push_back ("\"Already quoted: quoting needed\"");
319  outputLabels.push_back ("\"NotQuoted:QuotingNeeded\"");
320  outputLabels.push_back ("\"Not quoted: quoting needed\"");
321  outputLabels.push_back ("\"Not quoted \\\" quoting needed\"");
322  outputLabels.push_back ("\"Not quoted \\\" \\\" quoting needed\"");
323  outputLabels.push_back ("\"Already quoted \\\" quoting needed\"");
324  outputLabels.push_back ("\"Already quoted \\\" \\\" quoting needed\"");
325  outputLabels.push_back ("\"Not quoted \\\\ quoting needed\"");
326  outputLabels.push_back ("\"Not quoted \\\\\\\\ quoting needed\"");
327  outputLabels.push_back ("\"Not quoted \\\\ \\\\ quoting needed\"");
328  outputLabels.push_back ("\"Already quoted \\\\ quoting needed\"");
329  outputLabels.push_back ("\"Already quoted \\\\\\\\ quoting needed\"");
330  outputLabels.push_back ("\"Already quoted \\\\ \\\\ quoting needed\"");
331 
332  // Sanity check.
334  inputLabels.size () != outputLabels.size (),
335  std::logic_error,
336  "The number of input labels is different than the number of output labels."
337  " Please ask a Teuchos developer to make sure that every test input "
338  "label has a corresponding output label.");
339 
340  Array<RCP<Time> > timers;
341  for (size_type i = 0; i < inputLabels.size (); ++i) {
342  timers.push_back (TimeMonitor::getNewCounter (inputLabels[i]));
343  }
344 
345  // The actual number of operations in the loop is proportional to
346  // the cube of the loop length. Adjust the quantities below as
347  // necessary to ensure the timer reports a nonzero elapsed time
348  // for each of the invocations.
349  const size_t loopLength = 25;
350  for (int k = 0; k < 3; ++k) {
351  for (size_type i = 0; i < timers.size (); ++i) {
352  TimeMonitor timeMon (* timers[i]);
353  slowLoop (loopLength);
354  }
355  }
356 
357  { // YAML output, compact style.
358  std::ostringstream oss;
359  RCP<ParameterList> reportParams =
360  parameterList (* (TimeMonitor::getValidReportParameters ()));
361  reportParams->set ("Report format", "YAML");
362  reportParams->set ("YAML style", "compact");
363  TimeMonitor::report (oss, reportParams);
364 
365  // Echo output to the FancyOStream out (which is a standard unit
366  // test argument). Output should only appear in "show all test
367  // details" mode.
368  out << oss.str () << std::endl;
369 
370  // Make sure that all timer labels appear correctly in the output.
371  for (size_type i = 0; i < inputLabels.size(); ++i) {
372  const size_t pos = oss.str ().find (outputLabels[i]);
373  TEST_INEQUALITY(pos, std::string::npos);
374  }
375  }
376 
377  { // YAML output, spacious style.
378  std::ostringstream oss;
379  RCP<ParameterList> reportParams =
380  parameterList (* (TimeMonitor::getValidReportParameters ()));
381  reportParams->set ("Report format", "YAML");
382  reportParams->set ("YAML style", "spacious");
383  TimeMonitor::report (oss, reportParams);
384 
385  // Echo output to the FancyOStream out (which is a standard unit
386  // test argument). Output should only appear in "show all test
387  // details" mode.
388  out << oss.str () << std::endl;
389 
390  // Make sure that all timer labels appear correctly in the output.
391  for (size_type i = 0; i < inputLabels.size(); ++i) {
392  const size_t pos = oss.str ().find (outputLabels[i]);
393  TEST_INEQUALITY(pos, std::string::npos);
394  }
395  }
396 
397  // This sets up for the next unit test.
399  }
400 
401 
402  //
403  // Test filtering of timer labels.
404  //
405  TEUCHOS_UNIT_TEST( TimeMonitor, TimerLabelFiltering )
406  {
407  using Teuchos::Array;
409  using Teuchos::parameterList;
410  using Teuchos::RCP;
411  using Teuchos::Time;
412  typedef Array<std::string>::size_type size_type;
413 
414  // Filters to use in the test.
415  Array<std::string> filters;
416  filters.push_back ("Foo:");
417  filters.push_back ("Bar:");
418  filters.push_back ("Baz:");
419 
420  // All the timer labels.
421  Array<std::string> labels;
422  labels.push_back ("Foo: timer 1");
423  labels.push_back ("Foo: timer 2");
424  labels.push_back ("Foo: timer 3");
425  labels.push_back ("Bar: timer 1");
426  labels.push_back ("Bar: timer 2");
427  labels.push_back ("Baz: timer 1");
428  labels.push_back ("Xyzzy");
429  labels.push_back ("This is not a pipe");
430  labels.push_back ("You should not see this");
431 
432  Array<Array<std::string> > outLabels (3);
433  // Label(s) that should be printed for filters[0]
434  outLabels[0].push_back ("Foo: timer 1");
435  outLabels[0].push_back ("Foo: timer 2");
436  outLabels[0].push_back ("Foo: timer 3");
437  // Label(s) that should be printed for filters[1]
438  outLabels[1].push_back ("Bar: timer 1");
439  outLabels[1].push_back ("Bar: timer 2");
440  // Label(s) that should be printed for filters[2]
441  outLabels[2].push_back ("Baz: timer 1");
442 
443  // Labels that should not be printed for any of the filters below.
444  Array<std::string> otherLabels;
445  otherLabels.push_back ("Xyzzy");
446  otherLabels.push_back ("This is not a pipe");
447  otherLabels.push_back ("You should not see this");
448 
449  Array<RCP<Time> > timers;
450  for (size_type i = 0; i < labels.size (); ++i) {
451  timers.push_back (TimeMonitor::getNewCounter (labels[i]));
452  }
453 
454  // The actual number of operations in the loop is proportional to
455  // the cube of the loop length. Adjust the quantities below as
456  // necessary to ensure the timer reports a nonzero elapsed time
457  // for each of the invocations.
458  const size_t loopLength = 25;
459  for (int k = 0; k < 3; ++k) {
460  for (size_type i = 0; i < timers.size (); ++i) {
461  TimeMonitor timeMon (* timers[i]);
462  slowLoop (loopLength);
463  }
464  }
465 
466  try {
467  // FIXME (mfh 21 Aug 2012) We don't yet have a test ensuring that
468  // the filter only selects at the beginning of the timer label.
469 
470  // Test for each filter.
471  for (size_type i = 0; i < filters.size (); ++i) {
472  { // Default (tabular) output format.
473  std::ostringstream oss;
474  RCP<ParameterList> reportParams =
475  parameterList (* (TimeMonitor::getValidReportParameters ()));
476  TimeMonitor::report (oss, filters[i], reportParams);
477 
478  // Echo output to the FancyOStream out (which is a standard unit
479  // test argument). Output should only appear in "show all test
480  // details" mode.
481  out << oss.str () << std::endl;
482 
483  // Check whether the labels that were supposed to be printed
484  // were actually printed.
486  for (size_type j = 0; j < outLabels[i].size(); ++j) {
487  const size_t pos = oss.str ().find (outLabels[i][j]);
488  TEST_INEQUALITY(pos, std::string::npos);
489  }
490  }
491 
492  // Check whether the labels that were _not_ supposed to be
493  // printed were actually printed.
494  //
495  // First, check the labels that should only be printed with
496  // the other filters.
497  for (size_type ii = 0; ii < outLabels.size(); ++ii) {
498  if (ii != i) {
499  for (size_type j = 0; j < outLabels[ii].size(); ++j) {
500  const size_t pos = oss.str ().find (outLabels[ii][j]);
501  TEST_EQUALITY(pos, std::string::npos);
502  }
503  }
504  }
505  // Next, check the labels that should not be printed for any
506  // filters.
507  for (size_type j = 0; j < otherLabels.size(); ++j) {
508  const size_t pos = oss.str ().find (otherLabels[j]);
509  TEST_EQUALITY(pos, std::string::npos);
510  }
511  }
512 
513  { // YAML output, compact style.
514  std::ostringstream oss;
515  RCP<ParameterList> reportParams =
516  parameterList (* (TimeMonitor::getValidReportParameters ()));
517  reportParams->set ("Report format", "YAML");
518  reportParams->set ("YAML style", "compact");
519  TimeMonitor::report (oss, filters[i], reportParams);
520 
521  // Echo output to the FancyOStream out (which is a standard unit
522  // test argument). Output should only appear in "show all test
523  // details" mode.
524  out << oss.str () << std::endl;
525 
526  // Check whether the labels that were supposed to be printed
527  // were actually printed.
528  for (size_type j = 0; j < outLabels[i].size(); ++j) {
529  const size_t pos = oss.str ().find (outLabels[i][j]);
530  TEST_INEQUALITY(pos, std::string::npos);
531  }
532 
533  // Check whether the labels that were _not_ supposed to be
534  // printed were actually printed.
535  //
536  // First, check the labels that should only be printed with
537  // the other filters.
538  for (size_type ii = 0; ii < outLabels.size(); ++ii) {
539  if (ii != i) {
540  for (size_type j = 0; j < outLabels[ii].size(); ++j) {
541  const size_t pos = oss.str ().find (outLabels[ii][j]);
542  TEST_EQUALITY(pos, std::string::npos);
543  }
544  }
545  }
546  // Next, check the labels that should not be printed for any
547  // filters.
548  for (size_type j = 0; j < otherLabels.size(); ++j) {
549  const size_t pos = oss.str ().find (otherLabels[j]);
550  TEST_EQUALITY(pos, std::string::npos);
551  }
552  }
553 
554  { // YAML output, spacious style.
555  std::ostringstream oss;
556  RCP<ParameterList> reportParams =
557  parameterList (* (TimeMonitor::getValidReportParameters ()));
558  reportParams->set ("Report format", "YAML");
559  reportParams->set ("YAML style", "spacious");
560  TimeMonitor::report (oss, filters[i], reportParams);
561 
562  // Echo output to the FancyOStream out (which is a standard unit
563  // test argument). Output should only appear in "show all test
564  // details" mode.
565  out << oss.str () << std::endl;
566 
567  // Check whether the labels that were supposed to be printed
568  // were actually printed.
569  for (size_type j = 0; j < outLabels[i].size(); ++j) {
570  const size_t pos = oss.str ().find (outLabels[i][j]);
571  TEST_INEQUALITY(pos, std::string::npos);
572  }
573 
574  // Check whether the labels that were _not_ supposed to be
575  // printed were actually printed.
576  //
577  // First, check the labels that should only be printed with
578  // the other filters.
579  for (size_type ii = 0; ii < outLabels.size(); ++ii) {
580  if (ii != i) {
581  for (size_type j = 0; j < outLabels[ii].size(); ++j) {
582  const size_t pos = oss.str ().find (outLabels[ii][j]);
583  TEST_EQUALITY(pos, std::string::npos);
584  }
585  }
586  }
587  // Next, check the labels that should not be printed for any
588  // filters.
589  for (size_type j = 0; j < otherLabels.size(); ++j) {
590  const size_t pos = oss.str ().find (otherLabels[j]);
591  TEST_EQUALITY(pos, std::string::npos);
592  }
593  }
594  }
595  }
596  catch (...) {
597  // Make sure to clear the counters, so that they don't pollute
598  // the remaining tests. (The Teuchos unit test framework may
599  // catch any exceptions that the above code throws, but allow
600  // the remaining tests to continue.)
602  throw;
603  }
604 
605  // This sets up for the next unit test.
607  }
608 
609 
610 
611  //
612  // TimeMonitor nested timers test: create two timers on all (MPI)
613  // processes, use the second inside the scope of the first, and make
614  // sure that TimeMonitor::summarize() reports both timers.
615  //
616  TEUCHOS_UNIT_TEST( TimeMonitor, FUNC_TIME_MONITOR_tested )
617  {
619  using Teuchos::parameterList;
620  using Teuchos::RCP;
621 
622  func_time_monitor2 ();
623 
624  {
625  std::ostringstream oss;
627 
628  // Echo summarize() output to the FancyOStream out (which is a
629  // standard unit test argument). Output should only appear in
630  // show-all-test-details mode.
631  out << oss.str() << std::endl;
632 
634  const size_t substr_i = oss.str().find ("FUNC_TIME_MONITOR2");
635  TEST_INEQUALITY(substr_i, std::string::npos);
636  const size_t substr_inner_i = oss.str().find ("FUNC_TIME_MONITOR2_inner");
637  TEST_INEQUALITY(substr_inner_i, std::string::npos);
638  }
639  }
640 
641  { // Repeat test for YAML output, compact style.
642  std::ostringstream oss;
643  RCP<ParameterList> reportParams =
644  parameterList (* (TimeMonitor::getValidReportParameters ()));
645  reportParams->set ("Report format", "YAML");
646  reportParams->set ("YAML style", "compact");
647  TimeMonitor::report (oss, reportParams);
648 
649  // Echo output to the FancyOStream out (which is a standard unit
650  // test argument). Output should only appear in "show all test
651  // details" mode.
652  out << oss.str () << std::endl;
653 
654  const size_t substr_i = oss.str().find ("FUNC_TIME_MONITOR2");
655  TEST_INEQUALITY(substr_i, std::string::npos);
656  const size_t substr_inner_i = oss.str().find ("FUNC_TIME_MONITOR2_inner");
657  TEST_INEQUALITY(substr_inner_i, std::string::npos);
658  }
659 
660  { // Repeat test for YAML output, spacious style.
661  std::ostringstream oss;
662  RCP<ParameterList> reportParams =
663  parameterList (* (TimeMonitor::getValidReportParameters ()));
664  reportParams->set ("Report format", "YAML");
665  reportParams->set ("YAML style", "spacious");
666  TimeMonitor::report (oss, reportParams);
667 
668  // Echo output to the FancyOStream out (which is a standard unit
669  // test argument). Output should only appear in "show all test
670  // details" mode.
671  out << oss.str () << std::endl;
672 
673  const size_t substr_i = oss.str().find ("FUNC_TIME_MONITOR2");
674  TEST_INEQUALITY(substr_i, std::string::npos);
675  const size_t substr_inner_i = oss.str().find ("FUNC_TIME_MONITOR2_inner");
676  TEST_INEQUALITY(substr_inner_i, std::string::npos);
677  }
678 
679  // This sets up for the next unit test.
681  }
682 
683  //
684  // Test whether TimeMonitor::summarize() does the right thing when
685  // different MPI processes create different sets of timers. This
686  // test is only meaningful if running with more than one MPI
687  // process, but it should also pass if running in a non-MPI build or
688  // with only one MPI process.
689  //
690  TEUCHOS_UNIT_TEST( TimeMonitor, SUMMARIZE_diffTimerSets )
691  {
693  const int numProcs = comm->getSize ();
694  const int myRank = comm->getRank ();
695 
696  // If MPI has not been initialized, turn the MPI communicator into
697  // a "serial" communicator. This may not be necessary when using
698  // the Teuchos Unit Test Framework.
699 #ifdef HAVE_MPI
700  {
701  int mpiHasBeenInitialized = 0;
702  MPI_Initialized (&mpiHasBeenInitialized);
703  if (! mpiHasBeenInitialized) {
705  }
706  }
707 #endif // HAVE_MPI
708 
709  // Store the output of TimeMonitor::summarize() here.
710  std::ostringstream oss;
711 
712  // Timer A gets created on all MPI processes.
713  // Timer B only gets created on Proc 0.
714  RCP<Time> timerA = TimeMonitor::getNewCounter ("Timer A");
715  RCP<Time> timerB;
716  if (myRank == 0) {
717  timerB = TimeMonitor::getNewCounter ("Timer B");
718  }
719  else {
720  timerB = null; // True anyway, but I want to make this explicit.
721  }
722 
723  // The actual number of operations in the loop is proportional to
724  // the cube of the loop length. Adjust the quantities below as
725  // necessary to ensure the timer reports a nonzero elapsed time
726  // for each of the invocations.
727  const size_t timerA_loopLength = 150;
728  const size_t timerB_loopLength = 200;
729 
730  // Timer A gets a call count of 3.
731  for (size_t k = 0; k < 3; ++k) {
732  TimeMonitor monitorA (*timerA);
733  slowLoop (timerA_loopLength);
734  }
735  if (myRank == 0) { // Timer B gets a call count of 1 on Proc 0.
736  TimeMonitor monitorB (*timerB);
737  slowLoop (timerB_loopLength);
738  }
739 
740  const bool alwaysWriteLocal = false; // the default
741  const bool writeGlobalStats = true; // the default
742  const bool writeZeroTimers = true; // the default
743  TimeMonitor::summarize (oss, alwaysWriteLocal, writeGlobalStats,
744  writeZeroTimers, Intersection);
745 
746  // Echo summarize() output to the FancyOStream out (which is a
747  // standard unit test argument). Output should only appear in
748  // show-all-test-details mode.
749  out << std::endl << "Testing intersection of timers:" << std::endl
750  << oss.str() << std::endl;
751 
752  // Since setOp == Intersection, only Timer A should be reported,
753  // unless there is only one (MPI) process.
755  size_t substr_i = oss.str().find ("Timer A");
756  TEST_INEQUALITY(substr_i, std::string::npos);
757  if (numProcs > 1) {
758  substr_i = oss.str().find ("Timer B");
759  TEST_EQUALITY(substr_i, std::string::npos);
760  }
761  }
762 
763  // Now call summarize(), but ask for a union of timers.
764  std::ostringstream ossUnion;
765  TimeMonitor::summarize (ossUnion, alwaysWriteLocal, writeGlobalStats,
766  writeZeroTimers, Union);
767 
768  // Echo summarize() output to the FancyOStream out (which is a
769  // standard unit test argument). Output should only appear in
770  // show-all-test-details mode.
771  out << std::endl << "Testing union of timers:" << std::endl
772  << ossUnion.str() << std::endl;
773 
774  // Since setOp == Union, both Timer A and Timer B should be
775  // reported.
777  size_t substr_i = ossUnion.str().find ("Timer A");
778  TEST_INEQUALITY(substr_i, std::string::npos);
779  substr_i = ossUnion.str().find ("Timer B");
780  TEST_INEQUALITY(substr_i, std::string::npos);
781  }
782 
783  // This sets up for the next unit test.
785  }
786 
787  //
788  // Test whether the option to filter out zero timers works, for the
789  // case that all (MPI) processes have the same call counts.
790  //
791  TEUCHOS_UNIT_TEST( TimeMonitor, FILTER_ZERO_TIMERS_sameParallelCallCounts )
792  {
793  // Store the output of TimeMonitor::summarize() here.
794  std::ostringstream oss;
795 
796  RCP<Time> timerA = TimeMonitor::getNewCounter ("Timer A");
797  RCP<Time> timerB = TimeMonitor::getNewCounter ("Timer B");
798  RCP<Time> timerC = TimeMonitor::getNewCounter ("Timer C");
799 
800  // Timers A and B get nonzero elapsed times and call counts on all
801  // (MPI) processes. Timer C never gets started, so it should have
802  // a zero elapsed time and zero call count on all processes.
803 
804  // The actual number of operations in the loop is proportional to
805  // the cube of the loop length. Adjust the quantities below as
806  // necessary to ensure the timer reports a nonzero elapsed time
807  // for each of the invocations.
808  const size_t timerA_loopLength = 200;
809  const size_t timerB_loopLength = 250;
810 
811  // Timer A gets a call count of 3.
812  for (size_t k = 0; k < 3; ++k) {
813  TimeMonitor monitorA (*timerA);
814  slowLoop (size_t (timerA_loopLength));
815  }
816  // Timer B gets a call count of 1.
817  {
818  TimeMonitor monitorB (*timerB);
819  slowLoop (size_t (timerB_loopLength));
820  }
821 
822  const bool alwaysWriteLocal = false; // the default
823  const bool writeGlobalStats = true; // the default
824  const bool writeZeroTimers = false; // NOT the default
825  TimeMonitor::summarize (oss, alwaysWriteLocal, writeGlobalStats,
826  writeZeroTimers);
827 
828  // Echo summarize() output to the FancyOStream out (which is a
829  // standard unit test argument). Output should only appear in
830  // show-all-test-details mode.
831  out << oss.str() << std::endl;
832 
833  // Timers A and B should be reported.
835  size_t substr_i = oss.str().find ("Timer A");
836  TEST_INEQUALITY(substr_i, std::string::npos);
837  substr_i = oss.str().find ("Timer B");
838  TEST_INEQUALITY(substr_i, std::string::npos);
839 
840  // Timer C should NOT be reported.
841  substr_i = oss.str().find ("Timer C");
842  TEST_EQUALITY(substr_i, std::string::npos);
843  }
844 
845  // This sets up for the next unit test.
847  }
848 
849 
850  //
851  // Test whether the option to filter out zero timers works, for the
852  // case that different (MPI) processes have different call counts.
853  //
854  TEUCHOS_UNIT_TEST( TimeMonitor, FILTER_ZERO_TIMERS_differentParallelCallCounts )
855  {
857  const int myRank = comm->getRank ();
858 
859  // If MPI has not been initialized, turn the MPI communicator into
860  // a "serial" communicator. This may not be necessary when using
861  // the Teuchos Unit Test Framework.
862 #ifdef HAVE_MPI
863  {
864  int mpiHasBeenInitialized = 0;
865  MPI_Initialized (&mpiHasBeenInitialized);
866  if (! mpiHasBeenInitialized) {
868  }
869  }
870 #endif // HAVE_MPI
871 
872  // Store the output of TimeMonitor::summarize() here.
873  std::ostringstream oss;
874 
875  RCP<Time> timerA = TimeMonitor::getNewCounter ("Timer A");
876  RCP<Time> timerB = TimeMonitor::getNewCounter ("Timer B");
877  RCP<Time> timerC = TimeMonitor::getNewCounter ("Timer C");
878 
879  // Timer A gets a nonzero elapsed time and call count on Proc 0,
880  // but a zero elapsed time and call count elsewhere.
881  //
882  // Timer B gets the same nonzero elapsed time and call count on
883  // all MPI procs.
884  //
885  // Timer C gets a zero elapsed time and call count on all procs.
886  //
887  // The actual number of operations in the loop is proportional to
888  // the cube of the loop length. Adjust the quantities below as
889  // necessary to ensure the timer reports a nonzero elapsed time
890  // for each of the invocations.
891  const size_t timerA_loopLength = 200;
892  const size_t timerB_loopLength = 500;
893 
894  if (myRank == 0) {
895  // Timer A gets a call count of 3 on Proc 0.
896  for (int k = 0; k < 3; ++k) {
897  TimeMonitor monitorA (*timerA);
898  slowLoop (size_t (timerA_loopLength));
899  }
900  }
901 
902  // Timer B gets a call count of 1 on all procs.
903  {
904  TimeMonitor monitorB (*timerB);
905  slowLoop (size_t (timerB_loopLength));
906  }
907 
908  const bool alwaysWriteLocal = false; // the default
909  const bool writeGlobalStats = true; // the default
910  const bool writeZeroTimers = false; // NOT the default
911  TimeMonitor::summarize (oss, alwaysWriteLocal, writeGlobalStats,
912  writeZeroTimers, Union);
913 
914  // Echo summarize() output to the FancyOStream out (which is a
915  // standard unit test argument). Output should only appear in
916  // show-all-test-details mode.
917  out << oss.str() << std::endl;
918 
920  // Timers A and B should both be reported.
921  size_t substr_i = oss.str().find ("Timer A");
922  TEST_INEQUALITY(substr_i, std::string::npos);
923  substr_i = oss.str().find ("Timer B");
924  TEST_INEQUALITY(substr_i, std::string::npos);
925 
926  // Timer C should NOT be reported.
927  substr_i = oss.str().find ("Timer C");
928  TEST_EQUALITY(substr_i, std::string::npos);
929  }
930 
931  // This sets up for the next unit test (if there is one).
933  }
934 
935  //
936  // Test option to disregard missing timers from processes in TimeMonitor::summarize().
937  //
938  TEUCHOS_UNIT_TEST( TimeMonitor, IgnoreMissingTimers )
939  {
941  const int myRank = comm->getRank ();
942 
943 #ifdef HAVE_MPI
944  {
945  int mpiHasBeenInitialized = 0;
946  MPI_Initialized (&mpiHasBeenInitialized);
947  if (! mpiHasBeenInitialized) {
949  }
950  }
951 #endif // HAVE_MPI
952 
953  // Store the output of TimeMonitor::summarize() here.
954  std::ostringstream oss;
955 
956  std::string timerName="Timer Z";
957  // Timer Z appears on all PIDs except 0.
958  {
959  switch (myRank) {
960  case 1 :
961  break;
962  case 0 :
963  {
964  RCP<Time> timer = TimeMonitor::getNewCounter (timerName);
965  TimeMonitor monitor (*timer);
966  sleep(1);
967  }
968  break;
969  case 2 :
970  {
971  RCP<Time> timer = TimeMonitor::getNewCounter (timerName);
972  TimeMonitor monitor (*timer);
973  sleep(1);
974  }
975  break;
976  default :
977  {
978  RCP<Time> timer = TimeMonitor::getNewCounter (timerName);
979  TimeMonitor monitor (*timer);
980  sleep(1);
981  }
982  }
983  }
984 
986  // test two versions of summarize with default behavior
988 
989  //version 1, comm provided
990  const bool alwaysWriteLocal = false;
991  const bool writeGlobalStats = true;
992  const bool writeZeroTimers = false;
993  bool ignoreMissingTimers = false; // the default
994  std::string filter = "";
995  TimeMonitor::summarize (comm.ptr(), oss, alwaysWriteLocal, writeGlobalStats,
996  writeZeroTimers, Union, filter, ignoreMissingTimers);
997 
998  // Echo summarize() output to the FancyOStream out (which is a
999  // standard unit test argument). Output should only appear in
1000  // show-all-test-details mode.
1001  out << oss.str() << std::endl;
1002 
1003  if (comm->getSize() > 1) {
1004  // The min should be 0
1006  size_t substr_i = oss.str().find ("0 (0)");
1007  TEST_INEQUALITY(substr_i, std::string::npos);
1008  }
1009  }
1010 
1011  //version 2, no comm provided
1012  std::ostringstream oss2;
1013  TimeMonitor::summarize (oss2, alwaysWriteLocal, writeGlobalStats,
1014  writeZeroTimers, Union, filter, ignoreMissingTimers);
1015  out << oss2.str() << std::endl;
1016  if (comm->getSize() > 1) {
1017  // The min should be 0
1019  size_t substr_i = oss2.str().find ("0 (0)");
1020  TEST_INEQUALITY(substr_i, std::string::npos);
1021  }
1022  }
1023 
1025  // test two versions of summarize with *non* default behavior
1027  //version 1, comm provided
1028  ignoreMissingTimers = true; // NOT the default
1029  std::ostringstream oss3;
1030  TimeMonitor::summarize (comm.ptr(), oss3, alwaysWriteLocal, writeGlobalStats,
1031  writeZeroTimers, Union, filter, ignoreMissingTimers);
1032  out << oss3.str() << std::endl;
1033 
1034  // The min should be different from 0
1035  size_t substr_i = oss3.str().find ("0 (0)");
1036  TEST_EQUALITY(substr_i, std::string::npos);
1037 
1038  //version 2, no comm provided
1039  std::ostringstream oss4;
1040  TimeMonitor::summarize (oss4, alwaysWriteLocal, writeGlobalStats,
1041  writeZeroTimers, Union, filter, ignoreMissingTimers);
1042  out << oss4.str() << std::endl;
1043  // The min should be different from 0
1044  substr_i = oss4.str().find ("0 (0)");
1045  TEST_EQUALITY(substr_i, std::string::npos);
1046 
1047  // This sets up for the next unit test (if there is one).
1049  }
1050 
1051  //
1052  // Test that Time::start() and Time::stop() call Kokkos::fence(),
1053  // if the option to do that is enabled.
1054  //
1055  #ifdef HAVE_TEUCHOS_TIMER_KOKKOS_FENCE
1056  namespace KokkosFenceCounter
1057  {
1058  static int numFences;
1059 
1060  void reset()
1061  {
1062  numFences = 0;
1063  }
1064 
1065  void begin_fence_callback(const char*, const uint32_t deviceId, uint64_t*) {
1066  using namespace Kokkos::Tools::Experimental;
1067  // Only count global device fences on the default space. Otherwise fences
1068  // could be counted multiple times, depending on how many backends are enabled.
1069  DeviceType fenceDevice = identifier_from_devid(deviceId).type;
1070  DeviceType defaultDevice = DeviceTypeTraits<Kokkos::DefaultExecutionSpace>::id;
1071  if(fenceDevice == defaultDevice)
1072  numFences++;
1073  }
1074  }
1075 
1076  TEUCHOS_UNIT_TEST( TimeMonitor, CheckTimerKokkosFences )
1077  {
1078  // This test doesn't care about the comm size or rank because Kokkos
1079  // fences and profiling is purely local to each rank.
1080  //
1081  // Set up the fence counter (reset count to 0 and set the callback)
1082  KokkosFenceCounter::reset();
1083  Kokkos::Tools::Experimental::set_begin_fence_callback(KokkosFenceCounter::begin_fence_callback);
1084  int fenceCountAfterStart = 0;
1085  int fenceCountAfterStop = 0;
1086 
1087  {
1088  RCP<Time> timer = TimeMonitor::getNewCounter ("Timer XYZ");
1089  TimeMonitor monitor (*timer);
1090  // Timer has started; record current fence count
1091  fenceCountAfterStart = KokkosFenceCounter::numFences;
1092  }
1093  // Timer has stopped; record again
1094  fenceCountAfterStop = KokkosFenceCounter::numFences;
1095  TEST_EQUALITY(fenceCountAfterStart, 1);
1096  TEST_EQUALITY(fenceCountAfterStop, 2);
1097 
1098  // This sets up for the next unit test (if there is one).
1100  }
1101  #endif
1102 
1103 } // namespace Teuchos
static int getRank()
The rank of the calling process in MPI_COMM_WORLD.
#define TEUCHOS_FUNC_TIME_MONITOR(FUNCNAME)
Defines a timer for a specific function.
#define TEST_INEQUALITY(v1, v2)
Assert the inequality of v1 and v2.
static Teuchos::RCP< const Comm< OrdinalType > > getDefaultSerialComm(const Teuchos::RCP< const Comm< OrdinalType > > &comm)
Return a serial Comm if the input Comm is null.
static void clearCounters()
&quot;Forget&quot; about all counters created with getNewCounter().
#define TEST_NOTHROW(code)
Asserr that the statement &#39;code&#39; does not thrown any excpetions.
static RCP< Time > getNewCounter(const std::string &name)
Create a new counter with the specified name and add it to a global set of counters of this type...
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
static void disableTimer(const std::string &name)
Disable the timer with the given name.
#define TEST_EQUALITY(v1, v2)
Assert the equality of v1 and v2.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Templated set method.
static Teuchos::RCP< const Comm< OrdinalType > > getComm()
Return the default global communicator.
static RCP< const ParameterList > getValidReportParameters()
Default parameters (with validators) for report().
basic_OSTab< char > OSTab
static RCP< Time > getNewTimer(const std::string &name)
Return a new timer with the given name (class method).
TEUCHOS_UNIT_TEST(ConstNonconstObjectContainer, create)
static void summarize(Ptr< const Comm< int > > comm, std::ostream &out=std::cout, const bool alwaysWriteLocal=false, const bool writeGlobalStats=true, const bool writeZeroTimers=true, const ECounterSetOp setOp=Intersection, const std::string &filter="", const bool ignoreZeroTimers=false)
Print summary statistics for all timers on the given communicator.
Wall-clock timer.
Ptr< T > ptr() const
Get a safer wrapper raw C++ pointer to the underlying object.
Unit testing support.
A list of parameters of arbitrary type.
void push_back(const value_type &x)
A MPI utilities class, providing methods for initializing, finalizing, and querying the global MPI se...
size_type size() const
Scope guard for Teuchos::Time, with MPI collective timer reporting.
Smart reference counting pointer class for automatic garbage collection.
static void enableTimer(const std::string &name)
Enable the timer with the given name.
Scope guard for Time, that can compute MPI collective timer statistics.
static void report(Ptr< const Comm< int > > comm, std::ostream &out, const std::string &filter, const RCP< ParameterList > &params=null)
Report timer statistics to the given output stream.
#define TEUCHOS_FUNC_TIME_MONITOR_DIFF(FUNCNAME, DIFF)
Defines a timer for a specific function (with differentiator).
Replacement for std::vector that is compatible with the Teuchos Memory Management classes...