OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
IpplTimings.cpp
Go to the documentation of this file.
1//
2// Class IpplTimings
3// IpplTimings - a simple singleton class which lets the user create and
4// timers that can be printed out at the end of the program.
5//
6// General usage
7// 1) create a timer:
8// IpplTimings::TimerRef val = IpplTimings::getTimer("timer name");
9// This will either create a new one, or return a ref to an existing one
10//
11// 2) start a timer:
12// IpplTimings::startTimer(val);
13// This will start the referenced timer running. If it is already running,
14// it will not change anything.
15//
16// 3) stop a timer:
17// IpplTimings::stopTimer(val);
18// This will stop the timer, assuming it was running, and add in the
19// time to the accumulating time for that timer.
20//
21// 4) print out the results:
22// IpplTimings::print();
23//
24// Copyright (c) 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
25// All rights reserved
26//
27// This file is part of IPPL.
28//
29// IPPL is free software: you can redistribute it and/or modify
30// it under the terms of the GNU General Public License as published by
31// the Free Software Foundation, either version 3 of the License, or
32// (at your option) any later version.
33//
34// You should have received a copy of the GNU General Public License
35// along with IPPL. If not, see <https://www.gnu.org/licenses/>.
36//
37#include "Utility/IpplTimings.h"
38#include "Utility/Inform.h"
39#include "Message/GlobalComm.h"
41
42#include <algorithm>
43#include <cctype>
44#include <fstream>
45#include <iomanip>
46#include <iostream>
47#include <map>
48#include <stack>
49#include <string>
50
52std::stack<Timing*> IpplTimings::stashedInstance;
53
55// default constructor
57 TimerList(),
58 TimerMap()
59{ }
60
62// destructor
64 for (TimerMap_t::iterator it = TimerMap.begin(); it != TimerMap.end(); ++ it) {
65 it->second = 0;
66 }
67 TimerMap.clear();
68
69 TimerList.clear();
70}
71
73// create a timer, or get one that already exists
75 std::string s(nm);
76 TimerInfo* tptr = 0;
77 TimerMap_t::iterator loc = TimerMap.find(s);
78 if (loc == TimerMap.end()) {
79 tptr = new TimerInfo;
80 tptr->indx = TimerList.size();
81 tptr->name = s;
82 TimerMap.insert(TimerMap_t::value_type(s,tptr));
83 TimerList.push_back(my_auto_ptr<TimerInfo>(tptr));
84 } else {
85 tptr = (*loc).second;
86 }
87 return tptr->indx;
88}
89
91// start a timer
93 if (t >= TimerList.size())
94 return;
95 TimerList[t]->start();
96}
97
99// stop a timer, and accumulate it's values
101 if (t >= TimerList.size())
102 return;
103 TimerList[t]->stop();
104}
105
107// clear a timer, by turning it off and throwing away its time
109 if (t >= TimerList.size())
110 return;
111 TimerList[t]->clear();
112}
113
115// print out the timing results
117 if (TimerList.size() < 1)
118 return;
119
120 // report the average time for each timer
121 Inform msg("Timings");
122 msg << level1
123 << "-----------------------------------------------------------------";
124 msg << "\n";
125 msg << " Timing results for " << Ippl::getNodes() << " nodes:" << "\n";
126 msg << "-----------------------------------------------------------------";
127 msg << "\n";
128
129 {
130 TimerInfo* tptr = TimerList[0].get();
131 double walltotal = 0.0, cputotal = 0.0;
132 reduce(tptr->wallTime, walltotal, OpMaxAssign());
133 reduce(tptr->cpuTime, cputotal, OpMaxAssign());
134 size_t lengthName = std::min(tptr->name.length(), 19lu);
135 msg << tptr->name.substr(0,lengthName)
136 << std::string().assign(20 - lengthName,'.')
137 << " Wall tot = " << std::setw(10) << walltotal << ","
138 << " CPU tot = " << std::setw(10) << cputotal << "\n"
139 << "\n";
140 }
141
142 auto begin = ++ TimerList.begin();
143 auto end = TimerList.end();
144 std::sort(begin, end, [](const my_auto_ptr<TimerInfo>& a, const my_auto_ptr<TimerInfo>& b)
145 {
146 return std::lexicographical_compare(
147 a->name.begin(), a->name.end(),
148 b->name.begin(), b->name.end(),
149 [](unsigned char c1, unsigned char c2) {
150 return std::tolower(c1) < std::tolower(c2);
151 });
152 });
153
154 for (unsigned int i=1; i < TimerList.size(); ++i) {
155 TimerInfo* tptr = TimerList[i].get();
156 double wallmax = 0.0, cpumax = 0.0, wallmin = 0.0, cpumin = 0.0;
157 double wallavg = 0.0, cpuavg = 0.0;
158 reduce(tptr->wallTime, wallmax, OpMaxAssign());
159 reduce(tptr->cpuTime, cpumax, OpMaxAssign());
160 reduce(tptr->wallTime, wallmin, OpMinAssign());
161 reduce(tptr->cpuTime, cpumin, OpMinAssign());
162 reduce(tptr->wallTime, wallavg, OpAddAssign());
163 reduce(tptr->cpuTime, cpuavg, OpAddAssign());
164 size_t lengthName = std::min(tptr->name.length(), 19lu);
165
166 msg << tptr->name.substr(0,lengthName)
167 << std::string().assign(20 - lengthName, '.')
168 << " Wall max = " << std::setw(10) << wallmax << ","
169 << " CPU max = " << std::setw(10) << cpumax << "\n"
170 << std::string().assign(20,' ')
171 << " Wall avg = " << std::setw(10) << wallavg / Ippl::getNodes() << ","
172 << " CPU avg = " << std::setw(10) << cpuavg / Ippl::getNodes() << "\n"
173 << std::string().assign(20,' ')
174 << " Wall min = " << std::setw(10) << wallmin << ","
175 << " CPU min = " << std::setw(10) << cpumin << "\n"
176 << "\n";
177 }
178 msg << "-----------------------------------------------------------------";
179 msg << endl;
180}
181
183// save the timing results into a file
184void Timing::print(const std::string& fn, const std::map<std::string, unsigned int>& problemSize) {
185
186 std::ofstream *timer_stream;
187 Inform *msg;
188
189 if (TimerList.size() < 1)
190 return;
191
192 timer_stream = new std::ofstream;
193 timer_stream->open( fn.c_str(), std::ios::out );
194 msg = new Inform( 0, *timer_stream, 0 );
195 // report the average time for each timer
196 // Inform msg("Timings");
197 /*
198 *msg << "---------------------------------------------------------------------------";
199 *msg << "\n";
200 *msg << " Timing results for " << Ippl::getNodes() << " nodes:" << "\n";
201 *msg << "---------------------------------------------------------------------------";
202 *msg << " name nodes (cputot cpumax) (walltot wallmax) cpumin wallmin cpuav wallav ";
203 *msg << "\n";
204 */
205
206 if (!problemSize.empty()) {
207 *msg << "Problem size:\n";
208 for (auto it: problemSize) {
209 *msg << " " << std::setw(10) << it.first << ": " << it.second << "\n";
210 }
211 *msg << endl;
212 }
213
214 *msg << std::setw(27) << "num Nodes"
215 << std::setw(10) << "CPU tot"
216 << std::setw(11) << "Wall tot\n"
217 << std::string().assign(47,'=')
218 << "\n";
219 {
220 TimerInfo *tptr = TimerList[0].get();
221 double walltotal = 0.0, cputotal = 0.0;
222 reduce(tptr->wallTime, walltotal, OpMaxAssign());
223 reduce(tptr->cpuTime, cputotal, OpMaxAssign());
224 size_t lengthName = std::min(tptr->name.length(), 19lu);
225 *msg << tptr->name.substr(0,lengthName);
226 for (int j=lengthName; j < 20; ++j) {
227 *msg << ".";
228 }
229 *msg << " " << std::setw(6) << Ippl::getNodes()
230 << " " << std::setw(9) << std::setprecision(4) << cputotal
231 << " " << std::setw(9) << std::setprecision(4) << walltotal
232 << "\n";
233 }
234
235 auto begin = ++ TimerList.begin();
236 auto end = TimerList.end();
237 std::sort(begin, end, [](const my_auto_ptr<TimerInfo>& a, const my_auto_ptr<TimerInfo>& b)
238 {
239 return std::lexicographical_compare(
240 a->name.begin(), a->name.end(),
241 b->name.begin(), b->name.end(),
242 [](unsigned char c1, unsigned char c2) {
243 return std::tolower(c1) < std::tolower(c2);
244 });
245 });
246
247 *msg << "\n"
248 << std::setw(27) << "num Nodes"
249 << std::setw(10) << "CPU max"
250 << std::setw(10) << "Wall max"
251 << std::setw(10) << "CPU min"
252 << std::setw(10) << "Wall min"
253 << std::setw(10) << "CPU avg"
254 << std::setw(11) << "Wall avg\n"
255 << std::string().assign(87,'=')
256 << "\n";
257 for (unsigned int i=0; i < TimerList.size(); ++i) {
258 TimerInfo *tptr = TimerList[i].get();
259 double wallmax = 0.0, cpumax = 0.0, wallmin = 0.0, cpumin = 0.0;
260 double wallavg = 0.0, cpuavg = 0.0;
261 reduce(tptr->wallTime, wallmax, OpMaxAssign());
262 reduce(tptr->cpuTime, cpumax, OpMaxAssign());
263 reduce(tptr->wallTime, wallmin, OpMinAssign());
264 reduce(tptr->cpuTime, cpumin, OpMinAssign());
265 reduce(tptr->wallTime, wallavg, OpAddAssign());
266 reduce(tptr->cpuTime, cpuavg, OpAddAssign());
267 size_t lengthName = std::min(tptr->name.length(), 19lu);
268 *msg << tptr->name.substr(0,lengthName);
269 for (int j=lengthName; j < 20; ++j) {
270 *msg << ".";
271 }
272 *msg << " " << std::setw(6) << Ippl::getNodes()
273 << " " << std::setw(9) << std::setprecision(4) << cpumax
274 << " " << std::setw(9) << std::setprecision(4) << wallmax
275 << " " << std::setw(9) << std::setprecision(4) << cpumin
276 << " " << std::setw(9) << std::setprecision(4) << wallmin
277 << " " << std::setw(9) << std::setprecision(4) << cpuavg / Ippl::getNodes()
278 << " " << std::setw(9) << std::setprecision(4) << wallavg / Ippl::getNodes()
279 << endl;
280 }
281 timer_stream->close();
282 delete msg;
283 delete timer_stream;
284}
285
288
290 PAssert_EQ(stashedInstance.size(), 0);
291
293 instance = new Timing();
294}
295
297 PAssert_GT(stashedInstance.size(), 0);
298
299 delete instance;
301 stashedInstance.pop();
302}
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
PartBunchBase< T, Dim >::ConstIterator begin(PartBunchBase< T, Dim > const &bunch)
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
#define PAssert_EQ(a, b)
Definition PAssert.h:104
#define PAssert_GT(a, b)
Definition PAssert.h:108
Inform & endl(Inform &inf)
Definition Inform.cpp:42
Inform & level1(Inform &inf)
Definition Inform.cpp:45
std::complex< double > a
static int getNodes()
Definition IpplInfo.cpp:670
std::string name
Definition IpplTimings.h:98
TimerRef indx
unsigned int TimerRef
void clearTimer(TimerRef)
IpplTimerInfo TimerInfo
TimerMap_t TimerMap
void print()
void stopTimer(TimerRef)
TimerList_t TimerList
void startTimer(TimerRef)
TimerRef getTimer(const char *)
static void stash()
static std::stack< Timing * > stashedInstance
static Timing * instance
static void pop()