1 /******************************************************************************
2 *
3 * Routines for doing timing.
4 *
5 *****************************************************************************/
6
7 #include <Kripke/Timing.h>
8
9 #include<Kripke.h>
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <algorithm>
14 #include <vector>
15 #include <sstream>
16 #include <mpi.h>
17
18 #ifdef KRIPKE_USE_BGPM
19 extern "C" void HPM_Start(char const *);
20 extern "C" void HPM_Stop(char const *);
21 #endif
22
23
24 #ifdef KRIPKE_USE_PAPI
25 #include <papi.h>
26 #endif
27
28
~Timing()29 Timing::~Timing(){
30 #ifdef KRIPKE_USE_PAPI
31 long long tmp[16];
32 PAPI_stop(papi_set, tmp);
33 #endif
34
35 }
36
start(std::string const & name)37 void Timing::start(std::string const &name){
38 // get or create timer
39 Timer &timer = timers[name];
40
41 if(!timer.started){
42 timer.started = true;
43 timer.start_time = MPI_Wtime();
44
45 #ifdef KRIPKE_USE_PAPI
46 int num_papi = papi_event.size();
47 if(num_papi > 0){
48 if(timer.papi_total.size() == 0){
49 timer.papi_start_values.resize(num_papi, 0);
50 timer.papi_total.resize(num_papi, 0);
51 }
52
53 /*
54 // start timers
55 PAPI_start_counters(&papi_event[0], num_papi);
56
57 // clear timers
58 long long tmp[16];
59 PAPI_read_counters(tmp, num_papi);
60 */
61
62 // read initial values
63 PAPI_read(papi_set, &timer.papi_start_values[0]);
64
65 }
66 #endif
67
68 #ifdef KRIPKE_USE_BGPM
69 HPM_Start(name.c_str());
70 #endif
71 }
72 }
73
stop(std::string const & name)74 void Timing::stop(std::string const &name){
75 // get or create timer
76 Timer &timer = timers[name];
77
78 #ifdef KRIPKE_USE_BGPM
79 HPM_Stop(name.c_str());
80 #endif
81
82 if(timer.started){
83 #ifdef KRIPKE_USE_PAPI
84 int num_papi = papi_event.size();
85 if(num_papi > 0){
86 // read timers
87 long long tmp[16];
88 //PAPI_stop_counters(tmp, num_papi);
89 PAPI_read(papi_set, tmp);
90
91 // accumulate to all started timers (since this clears the PAPI values)
92 for(int i = 0;i < num_papi;++ i){
93 timer.papi_total[i] += tmp[i] - timer.papi_start_values[i];
94 }
95
96 }
97 #endif
98
99 // Stop the timer
100 timer.started = false;
101 timer.total_time += MPI_Wtime() - timer.start_time;
102 timer.count ++;
103
104 }
105 }
106
stopAll(void)107 void Timing::stopAll(void){
108 for(TimerMap::iterator i = timers.begin();i != timers.end();++ i){
109 stop((*i).first);
110 }
111 }
112
clear(void)113 void Timing::clear(void){
114 timers.clear();
115 }
116
print(void) const117 void Timing::print(void) const {
118 int rank;
119 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
120 if(rank != 0){
121 return;
122 }
123
124 // build a sorted list of names
125 std::vector<std::string> names;
126 for(TimerMap::const_iterator i = timers.begin();i != timers.end();++ i){
127 names.push_back((*i).first);
128
129 }
130 std::sort(names.begin(), names.end());
131
132 std::vector<Timer const *> ord_timers;
133 for(int i = 0;i < names.size();++ i){
134 std::string &name = names[i];
135 TimerMap::const_iterator iter = timers.find(name);
136 ord_timers.push_back(&(*iter).second);
137 }
138
139 // Display column names
140 printf("Timers:\n");
141 printf(" %-16s %12s %12s", "Timer", "Count", "Seconds");
142 #ifdef KRIPKE_USE_PAPI
143 int num_papi = papi_names.size();
144 for(int i = 0;i < num_papi;++i){
145 printf(" %16s", papi_names[i].c_str());
146 }
147 #endif
148 printf("\n");
149
150 // Dislpay timer results
151 for(int i = 0;i < names.size();++ i){
152 printf(" %-16s %12d %12.5lf", names[i].c_str(), (int)ord_timers[i]->count, ord_timers[i]->total_time);
153 #ifdef KRIPKE_USE_PAPI
154 for(int p = 0;p < num_papi;++ p){
155 printf(" %16ld", (long)ord_timers[i]->papi_total[p]);
156 }
157 #endif
158 printf("\n");
159 }
160 }
161
162
163 namespace {
printTabVector(FILE * fp,std::vector<std::string> const & values)164 void printTabVector(FILE *fp, std::vector<std::string> const &values){
165 int len = values.size();
166 for(int i = 0;i < len;++ i){
167 if(i > 0){
168 fprintf(fp, "\t");
169 }
170 fprintf(fp, "%s", values[i].c_str());
171 }
172 fprintf(fp, "\n");
173 }
174
175 template<typename T>
toString(T const & val)176 std::string toString(T const &val){
177 std::stringstream ss;
178 ss << val;
179 return ss.str();
180 }
181 }
182
printTabular(bool print_header,std::vector<std::string> const & headers0,std::vector<std::string> const & values0,FILE * fp) const183 void Timing::printTabular(bool print_header,
184 std::vector<std::string> const &headers0,
185 std::vector<std::string> const &values0,
186 FILE *fp) const {
187 int rank;
188 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
189 if(rank != 0){
190 return;
191 }
192
193 // build a sorted list of names
194 std::vector<std::string> names;
195 for(TimerMap::const_iterator i = timers.begin();i != timers.end();++ i){
196 names.push_back((*i).first);
197
198 }
199 std::sort(names.begin(), names.end());
200
201 std::vector<Timer const *> ord_timers;
202 for(int i = 0;i < names.size();++ i){
203 std::string &name = names[i];
204 TimerMap::const_iterator iter = timers.find(name);
205 ord_timers.push_back(&(*iter).second);
206 }
207
208 // Output a header
209 std::vector<std::string> values = headers0;
210 values.push_back("timer");
211 values.push_back("count");
212 values.push_back("seconds");
213 #ifdef KRIPKE_USE_PAPI
214 int num_papi = papi_names.size();
215 for(int i = 0;i < papi_names.size();++i){
216 values.push_back(papi_names[i]);
217 }
218 #endif
219 if(print_header){
220 printTabVector(fp, values);
221 }
222
223 // For each timer, print the values
224 for(int i = 0;i < names.size();++ i){
225 values = values0;
226 values.push_back(names[i]);
227 values.push_back(toString(ord_timers[i]->count));
228 values.push_back(toString(ord_timers[i]->total_time));
229 #ifdef KRIPKE_USE_PAPI
230 for(int p = 0;p < num_papi;++ p){
231 values.push_back(toString(ord_timers[i]->papi_total[p]));
232 }
233 #endif
234
235 printTabVector(fp, values);
236 }
237 }
238
getTotal(std::string const & name) const239 double Timing::getTotal(std::string const &name) const{
240 TimerMap::const_iterator i = timers.find(name);
241 if(i == timers.end()){
242 return 0.0;
243 }
244 return (*i).second.total_time;
245 }
246
247
248
setPapiEvents(std::vector<std::string> names)249 void Timing::setPapiEvents(std::vector<std::string> names){
250 #ifdef KRIPKE_USE_PAPI
251
252
253 static bool papi_initialized = false;
254 if(!papi_initialized){
255 //printf("PAPI INIT\n");
256 int retval = PAPI_library_init(PAPI_VER_CURRENT);
257 papi_initialized = true;
258
259 if(retval != PAPI_VER_CURRENT){
260 fprintf(stderr, "ERROR INITIALIZING PAPI\n");
261 exit(1);
262 }
263 }
264
265 //printf("PAPI VERSION=%x\n",
266 // PAPI_VERSION);
267
268 papi_set = PAPI_NULL;
269 PAPI_create_eventset(&papi_set);
270
271
272 for(int i = 0;i < names.size();++ i){
273 // Convert text string to PAPI id
274 int event_code;
275 PAPI_event_name_to_code(
276 const_cast<char*>(names[i].c_str()),
277 &event_code);
278
279 // TODO: error checking?
280
281 // Add to our list of PAPI events
282 papi_names.push_back(names[i]);
283 papi_event.push_back(event_code);
284
285 int retval = PAPI_add_event(papi_set, event_code);
286 if(retval != PAPI_OK){
287 fprintf(stderr, "ERROR ADDING %s, retval=%d, ID=0x%-10x\n", names[i].c_str(), retval, event_code);
288 }
289
290 //printf("EVT=%s, ID=0x%-10x\n", names[i].c_str(), event_code);
291 }
292 PAPI_start(papi_set);
293 #else
294 if(names.size() > 0){
295 fprintf(stderr, "WARNING: PAPI NOT ENABLED, IGNORING PAPI EVENTS\n");
296 }
297 #endif
298 }
299