Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
stacked_timer.cpp
Go to the documentation of this file.
1 // @HEADER
2 // @HEADER
3 
9 #include <sstream>
10 #include <thread> // std::this_thread::sleep_for;
11 #include <tuple>
12 #include <regex>
13 #include <iterator>
14 
15 
16 TEUCHOS_UNIT_TEST(PerformanceMonitorBase, UnsortedMergeUnion) {
17 
19 
20  Teuchos::Array<std::string> a,b, tmp_a, tmp_b;
21 
22  a.push_back("foo");
23  a.push_back("bar");
24  a.push_back("car");
25 
26  b.push_back("car");
27  b.push_back("bar");
28  b.push_back("cat");
29 
30 
31  tmp_a=a;
32  tmp_b=b;
34  TEST_EQUALITY(tmp_b.size(),4);
35  TEST_EQUALITY(tmp_b[0], "car");
36  TEST_EQUALITY(tmp_b[1], "bar");
37  TEST_EQUALITY(tmp_b[2], "cat");
38  TEST_EQUALITY(tmp_b[3], "foo");
39 }
40 
41 TEUCHOS_UNIT_TEST(PerformanceMonitorBase, UnsortedMergeIntersection) {
42 
44 
45  Teuchos::Array<std::string> a,b, tmp_a, tmp_b;
46 
47  a.push_back("foo");
48  a.push_back("bar");
49  a.push_back("car");
50 
51  b.push_back("car");
52  b.push_back("bar");
53  b.push_back("cat");
54 
55 
56  tmp_a=a;
57  tmp_b=b;
59  TEST_EQUALITY(tmp_b.size(),2);
60  TEST_EQUALITY(tmp_b[0], "car");
61  TEST_EQUALITY(tmp_b[1], "bar");
62 }
63 
64 
65 TEUCHOS_UNIT_TEST(StackedTimer, Basic)
66 {
68  const int myRank = Teuchos::rank(*comm);
69 
70  Teuchos::StackedTimer timer("My New Timer");
71  timer.start("Total Time");
72  {
73  for (int i=0; i < 10; ++i) {
74 
75  timer.start("Assembly");
76  std::this_thread::sleep_for(std::chrono::milliseconds{100});
77  timer.stop("Assembly");
78 
79  timer.start("Solve");
80  {
81  timer.start("Prec");
82  std::this_thread::sleep_for(std::chrono::milliseconds{50});
83  timer.stop("Prec");
84 
85  // Test different timers on different mpi processes
86  if (myRank == 0 ) {
87  const std::string label = "Rank 0 ONLY";
88  timer.start(label);
89  std::this_thread::sleep_for(std::chrono::milliseconds{50});
90  TEST_ASSERT((timer.findTimer("Total Time@Solve@Rank 0 ONLY")).running);
91  timer.stop(label);
92  TEST_ASSERT(not (timer.findTimer("Total Time@Solve@Rank 0 ONLY")).running);
93  } else {
94  timer.start("Not Rank 0");
95  std::this_thread::sleep_for(std::chrono::milliseconds{50});
96  TEST_ASSERT((timer.findTimer("Total Time@Solve@Not Rank 0")).running);
97  timer.stop("Not Rank 0");
98  TEST_ASSERT(not (timer.findTimer("Total Time@Solve@Not Rank 0")).running);
99  }
100  }
101  timer.stop("Solve");
102 
103  }
104  }
105  timer.stop("Total Time");
106 
107 
108  TEST_EQUALITY((timer.findTimer("Total Time")).count, 1);
109  TEST_EQUALITY((timer.findTimer("Total Time@Assembly")).count, 10);
110  TEST_EQUALITY((timer.findTimer("Total Time@Solve")).count, 10);
111  TEST_EQUALITY((timer.findTimer("Total Time@Solve@Prec")).count, 10);
112 
113  // Test for exception for bad timer name
114  TEST_THROW(timer.findTimer("Testing misspelled timer name!"),std::runtime_error);
115 
116  // Pre-aggregation
117  if (myRank == 0) {
118  TEST_EQUALITY((timer.findTimer("Total Time@Solve@Rank 0 ONLY")).count, 10);
119  }
120  else {
121  TEST_EQUALITY((timer.findTimer("Total Time@Solve@Not Rank 0")).count, 10);
122  }
123 
125  options.output_histogram=true;
126  options.num_histogram=3;
127  options.print_warnings=false;
128 
129  // Get the report
130  std::stringstream sout1;
131  timer.report(sout1, comm, options);
132 
133  // Make sure can call report() multiple times, i.e. aggregation
134  // resets correctly for each call report()
135  std::stringstream sout2;
136  timer.report(sout2, comm, options);
137  TEST_EQUALITY(sout1.str(),sout2.str());
138 
139  // Gold file results (timer name,expected runtime,number of calls)
140  std::vector<std::tuple<std::string,double,unsigned long>> lineChecks;
141  lineChecks.push_back(std::make_tuple("My New Timer:",0.0,1));
142  lineChecks.push_back(std::make_tuple("Total Time:",2.0,1));
143  lineChecks.push_back(std::make_tuple("Assembly:",1.0,10));
144  lineChecks.push_back(std::make_tuple("Solve:",1.0,10));
145  lineChecks.push_back(std::make_tuple("Prec:",0.5,10));
146 
147  // Check the report() output. Read the first few lines and parse the
148  // expected timer label, the runtime and the counts.
149  //
150  // * NOTE: The report only combines values to a single MPI process, so
151  // only check on that process.
152  // * NOTE: regex not supported in gcc until 4.9. Can drop this check
153  // when Trilinos drops support for gcc 4.8.
154 #if !defined(__GNUC__) \
155  || ( defined(__GNUC__) && (__GNUC__ > 4) ) \
156  || ( defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC__MINOR__ > 8) )
157 
158  if (myRank == 0) {
159  const double timerTolerance = 0.25; // +- 0.25 seconds
160  std::istringstream is(sout1.str());
161  for (const auto& check : lineChecks) {
162 
163  std::string line;
164  std::getline(is,line);
165  std::smatch regexSMatch;
166  std::regex timerName(std::get<0>(check));
167  std::regex_search(line,regexSMatch,timerName);
168  TEST_ASSERT(not regexSMatch.empty());
169 
170  // Split string to get time and count
171  std::regex delimiter(":\\s|\\s\\[|\\]\\s");
172  std::sregex_token_iterator tok(line.begin(), line.end(),delimiter,-1);
173 
174  const std::string timeAsString = (++tok)->str();
175  const double time = std::stod(timeAsString);
176  TEST_FLOATING_EQUALITY(time,std::get<1>(check),timerTolerance);
177 
178  const std::string countAsString = (++tok)->str();
179  const unsigned long count = std::stoul(countAsString);
180  TEST_EQUALITY(count,std::get<2>(check));
181  }
182  }
183 #endif
184 
185  // Print to screen
186  timer.report(out, comm, options);
187 }
188 
189 
190 TEUCHOS_UNIT_TEST(StackedTimer, TimeMonitorInteroperability)
191 {
193 
194  const auto diffTimer = Teuchos::TimeMonitor::getNewTimer("Diffusion Term");
195  const auto rxnTimer = Teuchos::TimeMonitor::getNewTimer("Reaction Term");
196  const auto precTimer = Teuchos::TimeMonitor::getNewTimer("Prec");
197  const auto gmresTimer = Teuchos::TimeMonitor::getNewTimer("GMRES");
198 
199  // Test the set and get stacked timer methods on TimeMonitor
200  const auto timeMonitorDefaultStackedTimer = Teuchos::TimeMonitor::getStackedTimer();
201  const auto timer = Teuchos::rcp(new Teuchos::StackedTimer("StackedTimerTest::TimeMonitorInteroperability"));
202  TEST_ASSERT(nonnull(timeMonitorDefaultStackedTimer));
203  TEST_ASSERT(nonnull(timer));
204  TEST_ASSERT(timeMonitorDefaultStackedTimer != timer);
207 
208  timer->start("Total Time");
209  {
210  for (int i=0; i < 10; ++i) {
211 
212  timer->start("Assembly");
213  {
214  {
215  Teuchos::TimeMonitor tm(*diffTimer);
216  std::this_thread::sleep_for(std::chrono::milliseconds{25});
217  }
218  {
219  Teuchos::TimeMonitor tm(*rxnTimer);
220  std::this_thread::sleep_for(std::chrono::milliseconds{75});
221  }
222  // Remainder
223  std::this_thread::sleep_for(std::chrono::milliseconds{100});
224  }
225  timer->stop("Assembly");
226  timer->start("Solve");
227  {
228  {
229  Teuchos::TimeMonitor tm(*precTimer);
230  std::this_thread::sleep_for(std::chrono::milliseconds{50});
231  }
232  {
233  Teuchos::TimeMonitor tm(*gmresTimer);
234  std::this_thread::sleep_for(std::chrono::milliseconds{50});
235  }
236  // Remainder
237  std::this_thread::sleep_for(std::chrono::milliseconds{100});
238  }
239  timer->stop("Solve");
240  std::this_thread::sleep_for(std::chrono::milliseconds{100});
241  }
242  }
243  timer->stop("Total Time");
244 
245  assert(size(*comm)>0);
246 
247  TEST_EQUALITY((timer->findTimer("Total Time")).count, 1);
248  TEST_EQUALITY((timer->findTimer("Total Time@Assembly")).count, 10);
249 
250  // Make sure the TimeMonitor added the timers
251 #ifdef HAVE_TEUCHOS_ADD_TIME_MONITOR_TO_STACKED_TIMER
252  TEST_EQUALITY((timer->findTimer("Total Time@Solve@Prec")).count, 10);
253  TEST_EQUALITY((timer->findTimer("Total Time@Solve@GMRES")).count, 10);
254 #endif
255 
257  options.output_histogram=true;
258  options.num_histogram=3;
259  options.output_fraction=true;
260  timer->report(out, comm, options);
261 }
262 
263 // Overlapping timers are not allowed in a StackedTimer, but are in
264 // TimeMonitor. Since StackedTimer is automatically used in
265 // TimeMonitor by default, we have seen this error - a throw from the
266 // stacked timer. In every instance so far, the intention was not to
267 // actually overlap but a constructor/destructor ordering issue
268 // (suually involving RCPs). To prevent tests from failing,
269 // StackedTimer now automatically shuts itself off if it detects
270 // overlaped timers in a TimeMonitor instance, reports a warning on
271 // how to fix and allows the code to continue runnning. Where this has
272 // occurred in Trilinos is when a TimeMonitor object is stored in an
273 // RCP and then the RCP is reassigned to a new timer. The intention
274 // was to stop one and start another. But the destruction of one and
275 // the creation of the new one occurs in the wrong order. This test
276 // demonstrates the issue.
277 TEUCHOS_UNIT_TEST(StackedTimer, OverlappingTimersException)
278 {
279  Teuchos::StackedTimer timer("My Timer");
280  timer.start("Outer");
281  timer.start("Inner");
282  // Should stop inner before outer
283  TEST_THROW(timer.stop("Outer"),std::runtime_error);
284 }
285 
286 
287 #ifdef HAVE_TEUCHOS_ADD_TIME_MONITOR_TO_STACKED_TIMER
288 TEUCHOS_UNIT_TEST(StackedTimer, OverlappingTimersViaRCP)
289 {
290  const auto precTimer = Teuchos::TimeMonitor::getNewTimer("Prec");
291  const auto gmresTimer = Teuchos::TimeMonitor::getNewTimer("GMRES");
292 
294  timer = Teuchos::rcp(new Teuchos::TimeMonitor(*gmresTimer));
295 
297 }
298 #endif
299 
300 
Teuchos::TimeMonitor::setStackedTimer
static void setStackedTimer(const Teuchos::RCP< Teuchos::StackedTimer > &t)
Sets the StackedTimer that the TimeMonitor will use to insert timings into.
Definition: Teuchos_TimeMonitor.cpp:1483
Teuchos::TimeMonitor::getNewTimer
static RCP< Time > getNewTimer(const std::string &name)
Return a new timer with the given name (class method).
Definition: Teuchos_TimeMonitor.hpp:207
Teuchos_DefaultComm.hpp
Teuchos::StackedTimer::OutputOptions::output_histogram
bool output_histogram
Definition: Teuchos_StackedTimer.hpp:513
Teuchos::Array::size
size_type size() const
Definition: Teuchos_Array.hpp:1017
TEST_ASSERT
#define TEST_ASSERT(v1)
Assert the given statement is true.
Definition: Teuchos_LocalTestingHelpers.hpp:71
Teuchos::ArrayRCP::is_null
bool is_null(const ArrayRCP< T > &p)
Returns true if p.get()==NULL.
TEST_EQUALITY
#define TEST_EQUALITY(v1, v2)
Assert the equality of v1 and v2.
Definition: Teuchos_LocalTestingHelpers.hpp:87
Teuchos_PerformanceMonitorBase.hpp
Provides common capabilities for collecting and reporting performance data across processors.
Teuchos::TimeMonitor::getStackedTimer
static const Teuchos::RCP< Teuchos::StackedTimer > & getStackedTimer()
Returns the StackedTimer used by the TimeMonitor.
Definition: Teuchos_TimeMonitor.cpp:1489
Teuchos::StackedTimer::OutputOptions::print_warnings
bool print_warnings
Definition: Teuchos_StackedTimer.hpp:517
Teuchos::Array::push_back
void push_back(const value_type &x)
Definition: Teuchos_Array.hpp:1156
Teuchos::rcp
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
Definition: Teuchos_RCPDecl.hpp:1224
Teuchos::StackedTimer::start
void start()
Definition: Teuchos_StackedTimer.hpp:413
TEST_THROW
#define TEST_THROW(code, ExceptType)
Assert that the statement 'code' throws the exception 'ExceptType' (otherwise the test fails).
Definition: Teuchos_LocalTestingHelpers.hpp:198
Teuchos_TimeMonitor.hpp
Scope protection wrapper for Teuchos::Time, with timer reporting functionality.
Teuchos::RCP
Smart reference counting pointer class for automatic garbage collection.
Definition: Teuchos_RCPDecl.hpp:429
Teuchos::Comm::size
int size(const Comm< Ordinal > &comm)
Get the number of processes in the communicator.
Teuchos_UnitTestHarness.hpp
Unit testing support.
Teuchos::Array< std::string >
TEUCHOS_UNIT_TEST
TEUCHOS_UNIT_TEST(PerformanceMonitorBase, UnsortedMergeUnion)
Definition: stacked_timer.cpp:16
Teuchos::StackedTimer::OutputOptions::num_histogram
int num_histogram
Definition: Teuchos_StackedTimer.hpp:515
Teuchos::TimeMonitor
A scope-safe timer wrapper class, that can compute global timer statistics.
Definition: Teuchos_TimeMonitor.hpp:178
Teuchos::Union
Definition: Teuchos_PerformanceMonitorBase.hpp:66
Teuchos::Intersection
Definition: Teuchos_PerformanceMonitorBase.hpp:66
Teuchos::StackedTimer::OutputOptions::output_fraction
bool output_fraction
Definition: Teuchos_StackedTimer.hpp:511
Teuchos::StackedTimer::stop
void stop(const std::string &name="RootTimer")
Definition: Teuchos_StackedTimer.hpp:436
Teuchos_StackedTimer.hpp
Teuchos::unsortedMergePair
void unsortedMergePair(const Array< std::string > &localNames, Array< std::string > &globalNames, const ECounterSetOp setOp)
Definition: Teuchos_PerformanceMonitorBase.cpp:481
Teuchos::DefaultComm::getComm
static Teuchos::RCP< const Comm< OrdinalType > > getComm()
Return the default global communicator.
Definition: Teuchos_DefaultComm.hpp:212
Teuchos::StackedTimer::OutputOptions
Struct for controlling output options like histograms.
Definition: Teuchos_StackedTimer.hpp:507
Teuchos::StackedTimer
This class allows one to push and pop timers on and off a stack.
Definition: Teuchos_StackedTimer.hpp:169
Teuchos::StackedTimer::report
void report(std::ostream &os)
Definition: Teuchos_StackedTimer.hpp:502
Teuchos::ArrayRCP::nonnull
bool nonnull(const ArrayRCP< T > &p)
Returns true if p.get()!=NULL.
TEST_FLOATING_EQUALITY
#define TEST_FLOATING_EQUALITY(v1, v2, tol)
Assert the relative floating-point equality of rel_error(v1,v2) <= tol.
Definition: Teuchos_LocalTestingHelpers.hpp:112
Teuchos::StackedTimer::findTimer
BaseTimer::TimeInfo findTimer(const std::string &name)
Definition: Teuchos_StackedTimer.hpp:494