source: src/base/timer.cpp@ 49f8653

Last change on this file since 49f8653 was 6fee21, checked in by Julian Iseringhausen <isering@…>, 14 years ago

Timer::PrintGlobal is now less vulnerable to different processes having different sets of timing entities.

git-svn-id: https://svn.version.fz-juelich.de/scafacos/trunk@1781 5161e1c8-67bf-11de-9fd5-51895aff932f

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/**
2 * @file timer.cpp
3 * @author Julian Iseringhausen <isering@ins.uni-bonn.de>
4 * @date Tue Sep 6 16:17:40 2011
5 *
6 * @brief Class to measure timings.
7 *
8 */
9
10#ifdef HAVE_CONFIG_H
11#include <config.h>
12#endif
13
14#ifdef HAVE_MPI
15#include <mpi.h>
16#ifdef HAVE_MARMOT
17#include <enhancempicalls.h>
18#include <sourceinfompicalls.h>
19#endif
20#endif
21
22#include <iostream>
23#include <limits>
24#include <sstream>
25
26#include "base/helper.hpp"
27#include "base/timer.hpp"
28#include "comm/comm.hpp"
29#include "thirdparty/pugixml/pugixml.hpp"
30#include "mg.hpp"
31
32using namespace VMG;
33
34std::map<std::string, TimerData> Timer::td;
35
36void Timer::Start(std::string event)
37{
38#ifdef HAVE_MPI
39#ifdef DEBUG_MEASURE_TIME
40 std::map<std::string, TimerData>::iterator iter = td.find(event);
41 if (iter == td.end())
42 iter = td.insert(std::make_pair(event, TimerData())).first;
43
44 iter->second.time_start = MPI_Wtime();
45#endif
46#endif
47}
48
49void Timer::Stop(std::string event)
50{
51#ifdef HAVE_MPI
52#ifdef DEBUG_MEASURE_TIME
53 double time_end = MPI_Wtime();
54
55 std::map<std::string, TimerData>::iterator iter = td.find(event);
56
57 if (time_end - iter->second.time_start < std::numeric_limits<double>::min())
58 ++(iter->second.warning);
59
60 ++(iter->second.total);
61
62 iter->second.duration += time_end - iter->second.time_start;
63#endif
64#endif
65}
66
67void Timer::Clear()
68{
69 td.clear();
70}
71
72pugi::xml_node Timer::ToXMLNode()
73{
74 std::map<std::string, TimerData>::iterator iter;
75
76 pugi::xml_node node_process;
77 node_process.append_attribute("Rank").set_value(MG::GetComm()->GlobalRank());
78
79 pugi::xml_node node_timings = node_process.append_child("Timings");
80
81 for (iter=Timer::td.begin(); iter!=Timer::td.end(); ++iter) {
82
83 pugi::xml_node node_entry = node_timings.append_child("Sample");
84 node_entry.append_attribute("Name").set_value(Helper::ToString(iter->first).c_str());
85
86 node_entry.append_child("Duration")
87 .append_child(pugi::node_pcdata)
88 .set_value(Helper::ToString(iter->second.duration).c_str());
89
90 node_entry.append_child("Warnings")
91 .append_child(pugi::node_pcdata)
92 .set_value(Helper::ToString(iter->second.warning).c_str());
93
94 node_entry.append_child("Total")
95 .append_child(pugi::node_pcdata)
96 .set_value(Helper::ToString(iter->second.total).c_str());
97
98 }
99
100 return node_process;
101}
102
103std::string Timer::ToString()
104{
105 pugi::xml_node node = Timer::ToXMLNode();
106 std::stringstream str;
107 node.print(str);
108 return str.str();
109}
110
111void Timer::Print()
112{
113#ifdef DEBUG_MEASURE_TIME
114 std::map<std::string, TimerData>::const_iterator iter;
115 Comm& comm = *MG::GetComm();
116
117 if (comm.GlobalRank() == 0) {
118 comm.PrintStringOnce("Running times:");
119 for (iter=Timer::td.begin(); iter!=Timer::td.end(); ++iter)
120 comm.PrintStringOnce(" %s: %e s (%d)", iter->first.c_str(), iter->second.duration, iter->second.total);
121 }
122#endif
123}
124
125template <class T>
126static T min(T* data, int num_data, int& at_rank)
127{
128 at_rank = 0;
129 T min = data[0];
130
131 for (int i=1; i<num_data; ++i)
132 if (data[i] < min) {
133 at_rank = i;
134 min = data[i];
135 }
136 return min;
137}
138
139template <class T>
140static T max(T* data, int num_data, int& at_rank)
141{
142 at_rank = 0;
143 T max = data[0];
144
145 for (int i=1; i<num_data; ++i)
146 if (data[i] > max) {
147 at_rank = i;
148 max = data[i];
149 }
150 return max;
151}
152
153template <class T>
154static vmg_float avg(T* data, int num_data)
155{
156 vmg_float average = 0.0;
157 vmg_float num_data_inv = 1.0 / static_cast<vmg_float>(num_data);
158 for (int i=0; i<num_data; ++i)
159 average += data[i] * num_data_inv;
160 return average;
161}
162
163void Timer::PrintGlobal()
164{
165#ifdef DEBUG_MEASURE_TIME
166 std::map<std::string, TimerData>::const_iterator iter;
167 Comm& comm = *MG::GetComm();
168 char name[80];
169 int rank, size;
170
171 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
172 MPI_Comm_size(MPI_COMM_WORLD, &size);
173
174 vmg_float times[size];
175 int calls[size];
176
177 comm.PrintStringOnce("Running times (global):");
178
179 int timer_size = Timer::td.size();
180 MPI_Bcast(timer_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
181
182 if (rank == 0) {
183 for (iter=Timer::td.begin(); iter!=Timer::td.end(); ++iter) {
184 std::strcpy(name, iter->first.c_str());
185 MPI_Bcast(name, 80, MPI_CHAR, 0, MPI_COMM_WORLD);
186 MPI_Gather(&Timer::td[name].duration, 1, MPI_DOUBLE, times, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
187 MPI_Gather(&Timer::td[name].total, 1, MPI_INT, calls, 1, MPI_INT, 0, MPI_COMM_WORLD);
188
189 int min_calls, max_calls;
190 vmg_float avg_calls;
191 vmg_float min_duration, max_duration, avg_duration;
192 int rank_min_calls, rank_max_calls, rank_min_duration, rank_max_duration;
193
194 min_duration = min(times, size, rank_min_duration);
195 max_duration = max(times, size, rank_max_duration);
196 avg_duration = avg(times, size);
197 min_calls = min(calls, size, rank_min_calls);
198 max_calls = max(calls, size, rank_max_calls);
199 avg_calls = avg(calls, size);
200
201 comm.PrintStringOnce(" %s: %e s (%d)", iter->first.c_str(), iter->second.duration, iter->second.total);
202 comm.PrintStringOnce(" Min: %e s @ %d", min_duration, rank_min_duration);
203 comm.PrintStringOnce(" Max: %e s @ %d", max_duration, rank_max_duration);
204 comm.PrintStringOnce(" Avg: %e s", avg_duration);
205 comm.PrintStringOnce(" Min calls: %d @ %d", min_calls, rank_min_calls);
206 comm.PrintStringOnce(" Max calls: %d @ %d", max_calls, rank_max_calls);
207 comm.PrintStringOnce(" Avg calls: %f", avg_calls);
208 }
209 }else {
210 for (int i=0; i<timer_size; ++i) {
211 MPI_Bcast(name, 80, MPI_CHAR, 0, MPI_COMM_WORLD);
212 MPI_Gather(&Timer::td[name].duration, 1, MPI_DOUBLE, times, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
213 MPI_Gather(&Timer::td[name].total, 1, MPI_INT, calls, 1, MPI_INT, 0, MPI_COMM_WORLD);
214 }
215 }
216
217#endif
218}
219
220std::ostream& VMG::operator<<(std::ostream& out, const Timer&)
221{
222 return out << Timer::ToString();
223}
Note: See TracBrowser for help on using the repository browser.