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