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
36#include <boost/algorithm/string.hpp>
37#include <iomanip>
38#include <iostream>
39#include <tuple>
40
42{
43
45{
46 ASSERTL0(!m_isactive, "Call to Timer::Start() done when timer is active.");
47 m_isactive = true;
48 m_start = Clock::now();
49}
50
52{
53 m_end = Clock::now();
54 ASSERTL0(m_isactive, "Call to Timer::Stop() done when timer is inactive.");
55 m_isactive = false;
56}
57
59{
61 "Call to Timer::Elapsed() done before Timer::Stop().");
62 return std::chrono::duration_cast<Seconds>(m_end - m_start);
63}
64
66{
67 return Elapsed().count() / static_cast<NekDouble>(n);
68}
69
70void Timer::AccumulateRegion(std::string region, int iolevel)
71{
72 // search for region
73 auto search = m_elapsedRegion.find(region);
74 if (search == m_elapsedRegion.end())
75 {
76 m_elapsedRegion.insert({region, std::make_tuple<Timer::Seconds, size_t>(
77 this->Elapsed(), 1, iolevel)});
78 }
79 else
80 {
81 std::get<0>(search->second) += this->Elapsed();
82 std::get<1>(search->second) += 1;
83 }
84}
85
87{
88 std::string def("default");
89 char *argv = new char[def.length() + 1];
90 std::strcpy(argv, def.c_str());
93
95
96 delete[] argv;
97}
98
100 std::ostream &o, int iolevel)
101{
102 // Return if there is nothing to write, or the user has disabled printing
103 if (m_elapsedRegion.begin() == m_elapsedRegion.end() || iolevel < 0)
104 {
105 return;
106 }
107
108 // Define content of each column that will be written
109 std::vector<std::string> labels{"Region", "Elapsed time Avg (s)",
110 "Min (s)", "Max (s)",
111 "Count", "IO Level"};
112
113 // Set width of each column (minimum 14 characters)
114 std::vector<size_t> widths;
115 for (const auto &label : labels)
116 {
117 widths.push_back(std::max<size_t>(label.size() + 2, 14));
118 }
119
120 // Make sure that names for each "Region" fits
121 for (const auto &entry : m_elapsedRegion)
122 {
123 widths[0] = std::max<size_t>(entry.first.size() + 2, widths[0]);
124 }
125
126 // Print header
127 if (comm->GetRank() == 0)
128 {
129 o << "-------------------------------------------\n";
130 for (int i = 0; i < labels.size(); ++i)
131 {
132 o << std::setw(widths[i]) << labels[i];
133 }
134 o << '\n';
135 }
136
137 // first write out execute time
138 auto item = m_elapsedRegion.find("Execute");
139 if (item != m_elapsedRegion.end())
140 {
141 auto elapsedAve = std::get<0>(item->second).count();
142 comm->AllReduce(elapsedAve, LibUtilities::ReduceSum);
143 elapsedAve /= comm->GetSize();
144 auto elapsedMin = std::get<0>(item->second).count();
145 comm->AllReduce(elapsedMin, LibUtilities::ReduceMin);
146 auto elapsedMax = std::get<0>(item->second).count();
147 comm->AllReduce(elapsedMax, LibUtilities::ReduceMax);
148
149 if (comm->GetRank() == 0)
150 {
151 o << std::setw(widths[0]) << item->first << std::setw(widths[1])
152 << elapsedAve << std::setw(widths[2]) << elapsedMin
153 << std::setw(widths[3]) << elapsedMax << std::setw(widths[4])
154 << std::get<1>(item->second) << std::setw(widths[5])
155 << std::get<2>(item->second) << '\n';
156 }
157 }
158
159 // Write all remaining timers, grouped by their IO Level
160 for (int i = 0; i <= iolevel; i++)
161 {
162 // Add a newline between each IO Level group
163 if (comm->GetRank() == 0)
164 {
165 o << "\n";
166 }
167
168 for (auto item = m_elapsedRegion.begin(); item != m_elapsedRegion.end();
169 ++item)
170 {
171 // Avoid writing the "Execute" timer twice
172 if (boost::iequals(item->first, "Execute"))
173 {
174 continue;
175 }
176
177 // Check if this timer has the correct IO Level
178 if (std::get<2>(item->second) == i)
179 {
180
181 auto elapsedAve = std::get<0>(item->second).count();
182 comm->AllReduce(elapsedAve, LibUtilities::ReduceSum);
183 elapsedAve /= comm->GetSize();
184 auto elapsedMin = std::get<0>(item->second).count();
185 comm->AllReduce(elapsedMin, LibUtilities::ReduceMin);
186 auto elapsedMax = std::get<0>(item->second).count();
187 comm->AllReduce(elapsedMax, LibUtilities::ReduceMax);
188
189 if (comm->GetRank() == 0)
190 {
191 o << std::setw(widths[0]) << item->first
192 << std::setw(widths[1]) << elapsedAve
193 << std::setw(widths[2]) << elapsedMin
194 << std::setw(widths[3]) << elapsedMax
195 << std::setw(widths[4]) << std::get<1>(item->second)
196 << std::setw(widths[5]) << std::get<2>(item->second)
197 << '\n';
198 }
199 }
200 }
201 }
202}
203
204// static members init
205std::map<std::string, std::tuple<Timer::Seconds, size_t, int>>
207
208} // namespace Nektar::LibUtilities
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
static void PrintElapsedRegions()
Print elapsed time and call count for each region with default serial communicator.
Definition: Timer.cpp:86
CounterType m_start
Definition: Timer.h:84
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:65
void AccumulateRegion(std::string, int iolevel=0)
Accumulate elapsed time for a region.
Definition: Timer.cpp:70
static std::map< std::string, std::tuple< Seconds, size_t, int > > m_elapsedRegion
Definition: Timer.h:88
std::chrono::duration< NekDouble > Seconds
Definition: Timer.h:54
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:55
double NekDouble