Line data Source code
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 :
25 : #include "Ippl.h"
26 :
27 : #include "Utility/IpplTimings.h"
28 :
29 : #include <algorithm>
30 : #include <fstream>
31 : #include <iostream>
32 :
33 : #include "Utility/Inform.h"
34 : #include "Utility/IpplInfo.h"
35 :
36 : #ifdef IPPL_ENABLE_NSYS_PROFILER
37 : #include "nvtx3/nvToolsExt.h"
38 : const uint32_t colors[] = { 0xff00ff00, 0xff0000ff, 0xffffff00, 0xffff00ff, 0xff00ffff, 0xffff0000, 0xffffffff };
39 : const int num_colors = sizeof(colors)/sizeof(uint32_t);
40 : #define PUSH_RANGE(name,cid) { \
41 : int color_id = cid; \
42 : color_id = color_id%num_colors;\
43 : nvtxEventAttributes_t eventAttrib = {0}; \
44 : eventAttrib.version = NVTX_VERSION; \
45 : eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; \
46 : eventAttrib.colorType = NVTX_COLOR_ARGB; \
47 : eventAttrib.color = colors[color_id]; \
48 : eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; \
49 : eventAttrib.message.ascii = name; \
50 : nvtxRangePushEx(&eventAttrib); \
51 : }
52 : #endif
53 :
54 : Timing* IpplTimings::instance = new Timing();
55 : std::stack<Timing*> IpplTimings::stashedInstance;
56 :
57 548 : Timing::Timing()
58 548 : : TimerList()
59 548 : , TimerMap() {}
60 :
61 0 : Timing::~Timing() {
62 0 : for (TimerMap_t::iterator it = TimerMap.begin(); it != TimerMap.end(); ++it) {
63 0 : it->second = 0;
64 : }
65 0 : TimerMap.clear();
66 :
67 0 : TimerList.clear();
68 0 : }
69 :
70 : // create a timer, or get one that already exists
71 344 : Timing::TimerRef Timing::getTimer(const char* nm) {
72 344 : std::string s(nm);
73 344 : TimerInfo* tptr = 0;
74 344 : TimerMap_t::iterator loc = TimerMap.find(s);
75 344 : if (loc == TimerMap.end()) {
76 344 : tptr = new TimerInfo;
77 344 : tptr->indx = TimerList.size();
78 344 : tptr->name = s;
79 344 : TimerMap.insert(TimerMap_t::value_type(s, tptr));
80 344 : TimerList.push_back(my_auto_ptr<TimerInfo>(tptr));
81 : } else {
82 0 : tptr = (*loc).second;
83 : }
84 344 : return tptr->indx;
85 344 : }
86 :
87 : // start a timer
88 336 : void Timing::startTimer(TimerRef t) {
89 336 : if (t >= TimerList.size())
90 0 : return;
91 : #ifdef IPPL_ENABLE_NSYS_PROFILER
92 : PUSH_RANGE(TimerList[t]->name.c_str(), (int)t);
93 : #endif
94 336 : TimerList[t]->start();
95 : }
96 :
97 : // stop a timer, and accumulate it's values
98 252 : void Timing::stopTimer(TimerRef t) {
99 252 : if (t >= TimerList.size())
100 0 : return;
101 : #ifdef IPPL_ENABLE_NSYS_PROFILER
102 : nvtxRangePop();
103 : #endif
104 252 : TimerList[t]->stop();
105 : }
106 :
107 : // clear a timer, by turning it off and throwing away its time
108 0 : void Timing::clearTimer(TimerRef t) {
109 0 : if (t >= TimerList.size())
110 0 : return;
111 0 : TimerList[t]->clear();
112 : }
113 :
114 : // print out the timing results
115 0 : void Timing::print() {
116 0 : if (TimerList.size() < 1)
117 0 : return;
118 :
119 : // report the average time for each timer
120 0 : Inform msg("Timings");
121 0 : msg << level1 << "---------------------------------------------";
122 0 : msg << "\n";
123 0 : msg << " Timing results for " << ippl::Comm->size() << " nodes:"
124 0 : << "\n";
125 0 : msg << "---------------------------------------------";
126 0 : msg << "\n";
127 :
128 : {
129 0 : TimerInfo* tptr = TimerList[0].get();
130 0 : double walltotal = 0.0;
131 0 : ippl::Comm->reduce(tptr->wallTime, walltotal, 1, std::greater<double>());
132 0 : size_t lengthName = std::min(tptr->name.length(), 19lu);
133 0 : msg << tptr->name.substr(0, lengthName) << std::string().assign(20 - lengthName, '.')
134 0 : << " Wall tot = " << std::setw(10) << walltotal << "\n"
135 0 : << "\n";
136 : }
137 :
138 0 : for (unsigned int i = 1; i < TimerList.size(); ++i) {
139 0 : TimerInfo* tptr = TimerList[i].get();
140 0 : double wallmax = 0.0, wallmin = 0.0;
141 0 : double wallavg = 0.0;
142 0 : ippl::Comm->reduce(tptr->wallTime, wallmax, 1, std::greater<double>());
143 0 : ippl::Comm->reduce(tptr->wallTime, wallmin, 1, std::less<double>());
144 0 : ippl::Comm->reduce(tptr->wallTime, wallavg, 1, std::plus<double>());
145 0 : size_t lengthName = std::min(tptr->name.length(), 19lu);
146 :
147 0 : msg << tptr->name.substr(0, lengthName) << std::string().assign(20 - lengthName, '.')
148 0 : << " Wall max = " << std::setw(10) << wallmax << "\n"
149 0 : << std::string().assign(20, ' ') << " Wall avg = " << std::setw(10)
150 0 : << wallavg / ippl::Comm->size() << "\n"
151 0 : << std::string().assign(20, ' ') << " Wall min = " << std::setw(10) << wallmin << "\n"
152 0 : << "\n";
153 : }
154 0 : msg << "---------------------------------------------";
155 0 : msg << endl;
156 0 : }
157 :
158 : // save the timing results into a file
159 0 : void Timing::print(const std::string& fn, const std::map<std::string, unsigned int>& problemSize) {
160 : std::ofstream* timer_stream;
161 : Inform* msg;
162 :
163 0 : if (TimerList.size() < 1)
164 0 : return;
165 :
166 0 : timer_stream = new std::ofstream;
167 0 : timer_stream->open(fn.c_str(), std::ios::out);
168 0 : msg = new Inform(0, *timer_stream, 0);
169 :
170 0 : if (problemSize.size() > 0) {
171 0 : *msg << "Problem size:\n";
172 0 : for (auto it : problemSize) {
173 0 : *msg << " " << std::setw(10) << it.first << ": " << it.second << "\n";
174 0 : }
175 0 : *msg << endl;
176 : }
177 :
178 0 : *msg << std::setw(27) << "ranks" << std::setw(11) << "Wall tot\n"
179 0 : << std::string().assign(37, '=') << "\n";
180 : {
181 0 : TimerInfo* tptr = TimerList[0].get();
182 0 : double walltotal = 0.0;
183 0 : ippl::Comm->reduce(tptr->wallTime, walltotal, 1, std::greater<double>());
184 0 : size_t lengthName = std::min(tptr->name.length(), 19lu);
185 0 : *msg << tptr->name.substr(0, lengthName);
186 0 : for (int j = lengthName; j < 20; ++j) {
187 0 : *msg << ".";
188 : }
189 0 : *msg << " " << std::setw(6) << ippl::Comm->size() << " " << std::setw(9)
190 0 : << std::setprecision(4) << walltotal << "\n";
191 : }
192 :
193 : *msg << "\n"
194 0 : << std::setw(27) << "ranks" << std::setw(10) << "Wall max" << std::setw(10) << "Wall min"
195 0 : << std::setw(11) << "Wall avg\n"
196 0 : << std::string().assign(57, '=') << "\n";
197 0 : for (unsigned int i = 0; i < TimerList.size(); ++i) {
198 0 : TimerInfo* tptr = TimerList[i].get();
199 0 : double wallmax = 0.0, wallmin = 0.0;
200 0 : double wallavg = 0.0;
201 0 : ippl::Comm->reduce(tptr->wallTime, wallmax, 1, std::greater<double>());
202 0 : ippl::Comm->reduce(tptr->wallTime, wallmin, 1, std::less<double>());
203 0 : ippl::Comm->reduce(tptr->wallTime, wallavg, 1, std::plus<double>());
204 0 : size_t lengthName = std::min(tptr->name.length(), 19lu);
205 0 : *msg << tptr->name.substr(0, lengthName);
206 0 : for (int j = lengthName; j < 20; ++j) {
207 0 : *msg << ".";
208 : }
209 0 : *msg << " " << std::setw(6) << ippl::Comm->size() << " " << std::setw(9)
210 0 : << std::setprecision(4) << wallmax << " " << std::setw(9) << std::setprecision(4)
211 0 : << wallmin << " " << std::setw(9) << std::setprecision(4)
212 0 : << wallavg / ippl::Comm->size() << endl;
213 : }
214 0 : timer_stream->close();
215 0 : delete msg;
216 0 : delete timer_stream;
217 : }
218 :
219 0 : IpplTimings::IpplTimings() {}
220 0 : IpplTimings::~IpplTimings() {}
221 :
222 0 : void IpplTimings::stash() {
223 0 : PAssert_EQ(stashedInstance.size(), 0);
224 :
225 0 : stashedInstance.push(instance);
226 0 : instance = new Timing();
227 0 : }
228 :
229 0 : void IpplTimings::pop() {
230 0 : PAssert_GT(stashedInstance.size(), 0);
231 :
232 0 : delete instance;
233 0 : instance = stashedInstance.top();
234 0 : stashedInstance.pop();
235 0 : }
|