Nektar++
Timer.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Timer.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Scientific Computing and Imaging Institute,
10 // University of Utah (USA) and Department of Aeronautics, Imperial
11 // College London (UK).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Time getting class
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
37 #include <boost/algorithm/string.hpp>
38 #include <iomanip>
39 #include <iostream>
40 #include <tuple>
41 
42 namespace Nektar
43 {
44 namespace LibUtilities
45 {
46 
48 {
49  ASSERTL0(!m_isactive, "Call to Timer::Start() done when timer is active.");
50  m_isactive = true;
51  m_start = Clock::now();
52 }
53 
55 {
56  m_end = Clock::now();
57  ASSERTL0(m_isactive, "Call to Timer::Stop() done when timer is inactive.");
58  m_isactive = false;
59 }
60 
62 {
64  "Call to Timer::Elapsed() done before Timer::Stop().");
65  return std::chrono::duration_cast<Seconds>(m_end - m_start);
66 }
67 
69 {
70  return Elapsed().count() / static_cast<NekDouble>(n);
71 }
72 
73 void Timer::AccumulateRegion(std::string region, int iolevel)
74 {
75  // search for region
76  auto search = m_elapsedRegion.find(region);
77  if (search == m_elapsedRegion.end())
78  {
79  m_elapsedRegion.insert({region, std::make_tuple<Timer::Seconds, size_t>(
80  this->Elapsed(), 1, iolevel)});
81  }
82  else
83  {
84  std::get<0>(search->second) += this->Elapsed();
85  std::get<1>(search->second) += 1;
86  }
87 }
88 
90 {
91  std::string def("default");
92  char *argv = new char[def.length() + 1];
93  std::strcpy(argv, def.c_str());
96 
97  PrintElapsedRegions(comm);
98 
99  delete[] argv;
100 }
101 
103  std::ostream &o, int iolevel)
104 {
105  // Return if there is nothing to write, or the user has disabled printing
106  if (m_elapsedRegion.begin() == m_elapsedRegion.end() || iolevel < 0)
107  {
108  return;
109  }
110 
111  // Define content of each column that will be written
112  std::vector<std::string> labels{"Region", "Elapsed time Avg (s)",
113  "Min (s)", "Max (s)",
114  "Count", "IO Level"};
115 
116  // Set width of each column (minimum 14 characters)
117  std::vector<size_t> widths;
118  for (const auto &label : labels)
119  {
120  widths.push_back(std::max<size_t>(label.size() + 2, 14));
121  }
122 
123  // Make sure that names for each "Region" fits
124  for (const auto &entry : m_elapsedRegion)
125  {
126  widths[0] = std::max<size_t>(entry.first.size() + 2, widths[0]);
127  }
128 
129  // Print header
130  if (comm->GetRank() == 0)
131  {
132  o << "-------------------------------------------\n";
133  for (int i = 0; i < labels.size(); ++i)
134  {
135  o << std::setw(widths[i]) << labels[i];
136  }
137  o << '\n';
138  }
139 
140  // first write out execute time
141  auto item = m_elapsedRegion.find("Execute");
142  if (item != m_elapsedRegion.end())
143  {
144  auto elapsedAve = std::get<0>(item->second).count();
145  comm->AllReduce(elapsedAve, LibUtilities::ReduceSum);
146  elapsedAve /= comm->GetSize();
147  auto elapsedMin = std::get<0>(item->second).count();
148  comm->AllReduce(elapsedMin, LibUtilities::ReduceMin);
149  auto elapsedMax = std::get<0>(item->second).count();
150  comm->AllReduce(elapsedMax, LibUtilities::ReduceMax);
151 
152  if (comm->GetRank() == 0)
153  {
154  o << std::setw(widths[0]) << item->first << std::setw(widths[1])
155  << elapsedAve << std::setw(widths[2]) << elapsedMin
156  << std::setw(widths[3]) << elapsedMax << std::setw(widths[4])
157  << std::get<1>(item->second) << std::setw(widths[5])
158  << std::get<2>(item->second) << '\n';
159  }
160  }
161 
162  // Write all remaining timers, grouped by their IO Level
163  for (int i = 0; i <= iolevel; i++)
164  {
165  // Add a newline between each IO Level group
166  if (comm->GetRank() == 0)
167  o << "\n";
168 
169  for (auto item = m_elapsedRegion.begin(); item != m_elapsedRegion.end();
170  ++item)
171  {
172  // Avoid writing the "Execute" timer twice
173  if (boost::iequals(item->first, "Execute"))
174  {
175  continue;
176  }
177 
178  // Check if this timer has the correct IO Level
179  if (std::get<2>(item->second) == i)
180  {
181 
182  auto elapsedAve = std::get<0>(item->second).count();
183  comm->AllReduce(elapsedAve, LibUtilities::ReduceSum);
184  elapsedAve /= comm->GetSize();
185  auto elapsedMin = std::get<0>(item->second).count();
186  comm->AllReduce(elapsedMin, LibUtilities::ReduceMin);
187  auto elapsedMax = std::get<0>(item->second).count();
188  comm->AllReduce(elapsedMax, LibUtilities::ReduceMax);
189 
190  if (comm->GetRank() == 0)
191  {
192  o << std::setw(widths[0]) << item->first
193  << std::setw(widths[1]) << elapsedAve
194  << std::setw(widths[2]) << elapsedMin
195  << std::setw(widths[3]) << elapsedMax
196  << std::setw(widths[4]) << std::get<1>(item->second)
197  << std::setw(widths[5]) << std::get<2>(item->second)
198  << '\n';
199  }
200  }
201  }
202  }
203 }
204 // static members init
205 std::map<std::string, std::tuple<Timer::Seconds, size_t, int>>
207 
208 } // namespace LibUtilities
209 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
static void PrintElapsedRegions()
Print elapsed time and call count for each region with default serial communicator.
Definition: Timer.cpp:89
CounterType m_start
Definition: Timer.h:86
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:68
void AccumulateRegion(std::string, int iolevel=0)
Accumulate elapsed time for a region.
Definition: Timer.cpp:73
static std::map< std::string, std::tuple< Seconds, size_t, int > > m_elapsedRegion
Definition: Timer.h:90
std::chrono::duration< NekDouble > Seconds
Definition: Timer.h:56
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble