Added a way to manually override the PAPI interpolation basis
[charm.git] / examples / bigsim / tools / rewritelog / EventInterpolator.C
1 #include <EventInterpolator.h>
2
3 //#define DEBUG
4 #define PRETEND_NO_ENERGY
5
6 using namespace std;
7
8
9 /** Create a vector such that "count" items out of "length" in the vector are set to true */
10 vector<bool> random_select(int count, int length){
11   vector<bool> v(length);
12   int c=0;
13   // Initialize all to false
14   for(int i=0;i<length;++i)
15         v[i] = false;
16   while(c < count){
17         // find a random entry int the vector
18         int r = rand() % length;
19         // mark it as true, incrementing c if this is the first time we mark it
20         if(v[r] == false){
21           c++;
22           v[r] = true;
23         }
24   }
25   return v;
26 }
27
28 template <typename T, typename T2>
29 multimap<T,T2> random_select_multimap(multimap<T,T2> input_map , int count){
30     assert(input_map.size() >= count);
31     vector<bool> which_to_keep = random_select(count, input_map.size());
32     multimap<T,T2> output_map;
33     int len = which_to_keep.size();
34     typename multimap<T, T2>::iterator itr=input_map.begin();
35     for(int i=0; i<len; ++i, ++itr){
36         if(which_to_keep[i] == true){
37           // Do something like this to keep them around:
38             output_map.insert(make_pair((*itr).first, (*itr).second));
39         }
40     }
41 //     assert(output_map.size()==count);
42     return output_map;
43 }
44
45 int distance(int i1, int i2, int i3, int i4, int i5, int i6){
46     int x1 =(abs(13+i1-i4)%13)*4;
47     int x2 =(abs(13+i4-i1)%13)*4;
48     int x = min(x1,x2);
49
50     int y1 =(abs(6+i2-i5)%6)*2;
51     int y2 =(abs(6+i5-i2)%6)*2;
52     int y = min(y1,y2);
53
54     int z1 =(abs(4+i3-i6)%4)*1;
55     int z2 =(abs(4+i6-i3)%4)*1;
56     int z = min(z1,z2);
57
58     return x+y+z;
59
60 }
61
62 string parseStreamUntilSquiggle(istream &in){
63   string temp;
64   ostringstream out;
65   in >> temp;
66   while(temp != string("}") && in.good()){
67
68         out << temp << " ";
69
70         in >> temp;
71   }
72
73   return out.str();
74 }
75
76
77 /** Record the number of parameters for the given type of event. Subsequent invocation for the same function identifier will fail if num_params doesn't match the recorded value from the first invocation  */
78 void EventInterpolator::recordNumCoefficients(const string &f, int c){
79     // find existing entry and verify it matches
80     if(number_of_coefficients.find(f) != number_of_coefficients.end()){
81         if(number_of_coefficients[f] != c){
82             cerr << "Number of coefficients for function " << f << " is not consistent" << endl;
83             exit(-5);
84         }
85     } else {
86         // create if no entry was found
87         number_of_coefficients[f] = c;
88     }
89 }
90
91
92 int EventInterpolator::numCoefficients(const string &funcname){
93      if(number_of_coefficients.find(funcname) == number_of_coefficients.end()){
94             cerr << "Number of coefficients looked up before it was set." << endl;
95             exit(-5);
96     }
97     int num = number_of_coefficients[funcname];
98     return num;
99 }
100
101 counterValues EventInterpolator::parseCounters(istringstream &line){
102     vector<long> c;
103     long val;
104     while(line.good()){
105         line >> val;
106         if(line.good()){
107             c.push_back(val);
108         }
109     }
110     return c;
111 }
112
113
114
115
116 /** First parameter is a category or subclass for a particular timed region. For example, we wish to consider computation for adjacent patches differently than patches that are neighbors of adjacent patches. This allows a single timed region to be broken out and treated as a number of different cases.
117
118 @note The use should modify this function to incorporate better models of the interpolation function basis
119
120 */
121 pair<int,vector<double> > EventInterpolator::parseParameters(const string &funcname, istringstream &line){
122     vector<double> params;
123     int category=0;
124
125     if( funcname == string("calc_self_energy_merge_fullelect") ||
126         funcname == string("calc_pair_energy_merge_fullelect") ||
127         funcname == string("calc_self_energy_fullelect") ||
128         funcname == string("calc_pair_energy_fullelect") ||
129         funcname == string("calc_self_merge_fullelect") ||
130         funcname == string("calc_pair_merge_fullelect") ||
131         funcname == string("calc_self") ||
132         funcname == string("calc_pair") ||
133         funcname == string("calc_self_energy") ||
134         funcname == string("calc_pair_energy") ){
135
136         double d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14;
137
138         line >> d1 >> d2 >> d3 >> d4 >> d5 >> d6 >> d7 >> d8 >> d9 >> d10 >> d11 >> d12 >> d13 >> d14;
139
140         params.push_back( 1.0);
141
142         params.push_back( d3 );
143         params.push_back( d4 );
144         params.push_back( d5 );
145
146         params.push_back( min(d1,d2)*d1*d2 );
147         params.push_back( d1*d2 );
148
149         category = distance((int)d9,(int)d10,(int)d11,(int)d12,(int)d13,(int)d14);
150
151     }
152     else { /** @note default model is quadratic in each variable */
153         double d;
154         int count=0;
155         params.push_back( 1.0);
156         while(line.good()){
157             line >> d;
158             if(line.good()){
159                 params.push_back(d);
160                 params.push_back(d*d);
161                 count++;
162             }
163         }
164     }
165     recordNumCoefficients(funcname,params.size());
166     return make_pair(category,params);
167 }
168
169
170 void EventInterpolator::LoadTimingsFile(char *table_filename){
171
172   cout << "Loading timings file: " << table_filename << endl;
173   ifstream accurateTimeTable(table_filename);
174   if(! accurateTimeTable.good() ){
175     cerr << "FATAL ERROR: Couldn't open file(perhaps it doesn't exist): " << table_filename << endl;
176     throw new runtime_error("missing file");
177   }
178
179
180   // Scan through cycle accurate time file inserting the entries into a map
181   while(accurateTimeTable.good())  {
182     string line_s;
183     getline(accurateTimeTable,line_s);
184     istringstream line(line_s);
185
186     // Expected format is:
187     // TRACEBIGSIM: event:{ eid } time:{ t } PAPI:{ list } params:{ list }
188     // params must currently come after event and time.
189
190     string funcname(""), paramstring(""), counterstring("");
191     double time = -1;
192     string temp;
193     line >> temp;
194     if(temp == string("TRACEBIGSIM:")){
195       // parse the next piece of the line
196       string field;
197       line >> field;
198       while(line.good() && accurateTimeTable.good()){
199         if(field == string("event:{")){
200           line >> funcname;
201           line >> temp; // gobble up the '}'
202           if(temp != string("}"))
203             cerr << "ERROR: malformed entry in expected times file" << endl;
204         } else if (field == string("time:{")){
205           line >> time;
206           line >> temp; // gobble up the '}'
207           if(temp != string("}"))
208             cerr << "ERROR: malformed entry in expected times file" << endl;
209         } else if (field == string("PAPI:{")){
210           counterstring = parseStreamUntilSquiggle(line);
211         } else if (field == string("params:{")){
212           paramstring = parseStreamUntilSquiggle(line);
213         } else {
214           cout << "Unknown event field: " << field  << endl;
215         }
216         line >> field;
217       }
218
219       if(funcname != string("") && time != -1){
220
221         istringstream paramstream(paramstring);
222         fullParams params = parseParameters(funcname,paramstream);
223
224
225         funcIdentifier func(funcname,params.first);
226
227         sample_count[func]++;
228
229         cycle_accurate_time_sum[funcname] += time;
230
231         accurateTimings.insert(make_pair(make_pair(func,params.second),time));
232
233         istringstream counterstream(counterstring);
234         counterValues counters = parseCounters(counterstream);
235         papiTimings.insert(make_pair(counters,time));
236
237       } else {
238         cerr << "malformed TRACEBIGSIM: line" << endl;
239       }
240
241     }
242
243   }
244
245
246   accurateTimeTable.close();
247
248 }
249
250 void EventInterpolator::AnalyzeTimings(double sample_rate){
251
252   std::map<string,double>::iterator cycle_i;
253   cout << "\nThe following table displays the total cycle count for each event in the \n"
254     "cycle-accurate timings file. This may be useful for back of the envelope \n"
255     "calculations for expected performance " << endl << endl;
256   cout << "\t|===============================|===================|" << endl;
257   cout << "\t|                        event  | total time (sec)  |" << endl;
258   cout << "\t|-------------------------------|-------------------|" << endl;
259   for(cycle_i= cycle_accurate_time_sum.begin();cycle_i!=cycle_accurate_time_sum.end();++cycle_i){
260     cout << "\t|";
261     assert((*cycle_i).first.length() <= 30); // the event names should be at most 30 characters
262     for(int i=0;i<30-(*cycle_i).first.length();++i)
263       cout << " ";
264     cout << (*cycle_i).first << " | ";
265     cout.width(17);
266     cout << (*cycle_i).second;
267     cout << " |" << endl;
268   }
269   cout << "\t|===============================|===================|" << endl << endl;
270
271
272
273   unsigned long sample_keep = (unsigned long) ceil(sample_rate * accurateTimings.size());
274   if (sample_rate < 1.0){
275     cout << "Randomly dropping " << (1.0-sample_rate)*100 << "% of the cycle accurate timings" << endl;
276     accurateTimings = random_select_multimap(accurateTimings, sample_keep);
277   }
278
279   analyzeExactVariances();
280
281   cout << "\nThe following table displays the number of timing samples from \n the cycle-accurate file for each event." << endl << endl;
282   cout << "\t|===================================|==========================|" << endl;
283   cout << "\t|                            event  | number of timing samples |" << endl;
284   cout << "\t|-----------------------------------|--------------------------|" << endl;
285
286
287   // Create a gsl interpolator workspace for each event/function
288   for(map<funcIdentifier,unsigned long>::iterator i=sample_count.begin(); i!=sample_count.end();++i){
289     funcIdentifier func = (*i).first;
290     unsigned long samples = (*i).second;
291
292     cout << "\t|";
293
294     for(int i=0;i<30-func.first.length();++i)
295       cout << " ";
296     cout << func.first << ",";
297     cout.width(3);
298     cout << func.second;
299
300     cout << " | ";
301     cout.width(24);
302     cout << samples << " |" << endl;
303
304
305     if(samples < numCoefficients(func.first) ){
306       cerr << "FATAL ERROR: Not enough input timing samples for " << func.first << "," << func.second << " which has " << numCoefficients(func.first) << " coefficients" << endl;
307       throw new runtime_error("samples < numCoefficients");
308     }
309     else {
310       work[func] = gsl_multifit_linear_alloc(samples,numCoefficients(func.first));
311       X[func] = gsl_matrix_alloc (samples,numCoefficients(func.first));
312       y[func] = gsl_vector_alloc (samples);
313       c[func] = gsl_vector_alloc(numCoefficients(func.first));
314       cov[func] = gsl_matrix_alloc(numCoefficients(func.first),numCoefficients(func.first));
315
316       for(int i=0;i<numCoefficients(func.first);++i){
317         gsl_vector_set(c[func],i,1.0);
318       }
319
320     }
321   }
322   cout << "\t|===================================|==========================|" << endl << endl;
323
324
325 #ifdef WRITESTATS
326   ofstream statfile("stats-out");
327 #endif
328
329   // Fill in values for matrix X and vector Y which will be fed into the least square fit algorithm
330   // The data is currently in  accurateTimings[pair<funcIdentifier,vector<double> >(func,params.second)]=time;
331
332   //iterate through accurateTimings
333   map< pair<funcIdentifier,vector<double> >, double >::iterator itr;
334   for(itr=accurateTimings.begin();itr!=accurateTimings.end();++itr){
335     const double &time = (*itr).second;
336     const vector<double> &paramsSecond =(*itr).first.second;
337     const funcIdentifier func = (*itr).first.first;
338
339     // lookup the next unused entry in X
340     unsigned next = Xcount[func] ++;
341     gsl_matrix * x = X[func];
342
343     // copy data into array X and Y
344     for(int param_index=0;param_index<paramsSecond.size();++param_index){
345       gsl_matrix_set(x,next,param_index, paramsSecond[param_index]);
346     }
347     gsl_vector_set(y[func],next,time);
348
349   }
350
351
352 #ifdef WRITESTATS
353   statfile.close();
354 #endif
355
356   // Perform a sanity check now
357   int count1=0, count2=0;
358   for(map<funcIdentifier, gsl_multifit_linear_workspace *>::iterator i=work.begin();i!=work.end();++i){
359 #if DEBUG
360     cout << "sample count vs Xcount (" << (*i).first.first << "): " << sample_count[(*i).first] << "?=" << Xcount[(*i).first] << " " << endl;
361 #endif
362     count1 += sample_count[(*i).first];
363     count2 += Xcount[(*i).first] ;
364   }
365   cout << "Samples from cycle accurate file : " << count1 << ".  Keeping only " << count2 << " of them " << endl;
366
367   cout << "Performing Least Squared Fit to sampled time data" << endl;
368
369   //  Now do Least Square Fit: Find C where y=Xc
370   cout << "\nThe following table displays the chi^2 measure for how well the model fits the input times." << endl << endl;
371   cout << "\t|===================================|=========|=========|" << endl;
372   cout << "\t|                            event  |   chi^2 |     chi |" << endl;
373   cout << "\t|-----------------------------------|---------|---------|" << endl;
374
375   cout.setf(ios_base::scientific, ios_base::floatfield);
376   cout.precision(1);
377
378   map<funcIdentifier, gsl_multifit_linear_workspace *>::iterator i;
379   for(i=work.begin();i!=work.end();++i){
380     funcIdentifier func = (*i).first;
381     assert(! gsl_multifit_linear(X[func],y[func],c[func],cov[func],&chisqr[func],work[func]));
382     gsl_matrix_free(X[func]);
383     gsl_vector_free(y[func]);
384
385     cout << "\t|";
386
387     for(int i=0;i<30-func.first.length();++i)
388       cout << " ";
389     cout << func.first << ",";
390     cout.width(3);
391     cout << func.second;
392
393     cout << " | ";
394     cout.width(7);
395     cout << chisqr[func];
396
397     cout << " | ";
398     cout.width(7);
399     cout << sqrt(chisqr[func]) << " |" << endl;
400
401   }
402   cout << "\t|===================================|=========|=========|" << endl << endl;
403
404 }
405
406 /** 
407         The model is currently a linear combination of the PAPI counters.
408         The first coefficient is associated with a constant value 1.0, and all 
409         other coefficients are associated with the performance counters in order.
410 */
411 void EventInterpolator::AnalyzeTimings_PAPI(){
412
413     cout << "Analyzing the PAPI performance counters. Using all samples" << endl;
414
415     gsl_multifit_linear_workspace * work;
416     gsl_vector * c;
417     gsl_matrix * cov;
418     double chisqr;
419
420     gsl_matrix * X;  // Each row of matrix is a set of parameters  [1, a, b, c, ... ] for each input parameter set
421     gsl_vector *y;  // vector of cycle accurate times for each input parameter setAnalyzeTimings(
422
423     if(papiTimings.begin() != papiTimings.end()){
424         int numCounters = (*papiTimings.begin()).first.size();
425         int numCoefficients = numCounters + 1; // currently we use a linear function of the counter values
426 #define MANUAL_COUNTER_SELECTION
427 #ifdef MANUAL_COUNTER_SELECTION 
428         numCoefficients = 2;
429 #endif
430         int samples = papiTimings.size();
431
432         // Create a gsl interpolator workspace, and populate with values from papiTimings
433         work = gsl_multifit_linear_alloc(samples,numCoefficients);
434         X = gsl_matrix_alloc (samples,numCoefficients);
435         y = gsl_vector_alloc (samples);
436         c = gsl_vector_alloc(numCoefficients);
437         cov = gsl_matrix_alloc(numCoefficients,numCoefficients);
438
439         // Initialize c. Probably unneeded.
440         for(int i=0;i<numCoefficients;++i){
441             gsl_vector_set(c,i,1.0);
442         }
443
444
445         // Build matrix X and vector y from the samples
446         int whichSample=0;
447         for(map<counterValues,double>::iterator itr=papiTimings.begin(); itr!=papiTimings.end();++itr){
448             const double &time = (*itr).second;
449             const vector<long> &counterValues =(*itr).first;
450
451 #ifndef MANUAL_COUNTER_SELECTION
452             // put a constant coefficient in there
453             gsl_matrix_set(X, whichSample, 0, 1.0);
454
455             // For each PAPI counter
456             assert(counterValues.size() == numCounters);
457             for(int counter_index=0;counter_index<counterValues.size();++counter_index){
458                 gsl_matrix_set(X, whichSample, counter_index+1, (double)counterValues[counter_index]);
459             }
460 #else 
461
462             gsl_matrix_set(X, whichSample, 0, 1.0);
463             gsl_matrix_set(X, whichSample, 1, (double)counterValues[1]);
464
465 #endif
466
467
468
469             gsl_vector_set(y, whichSample, (double)time);
470             whichSample++;
471         }
472
473
474         //  Now do Least Square Fit: Find C where y=Xc
475         assert(! gsl_multifit_linear(X,y,c,cov,&chisqr,work));
476         gsl_matrix_free(X);
477         gsl_vector_free(y);
478
479         cout << "Fit data to PAPI based model to get the following results:" << endl;
480         cout << "    > chisqr=" << chisqr << endl;
481         cout << "    > coefficients=";
482         for(int i=0;i<numCoefficients;i++){
483             cout.setf(ios_base::scientific, ios_base::floatfield);
484             cout.precision(2);
485             cout << gsl_vector_get(c, i) <<  " ";
486         }
487         cout << endl;
488
489     }
490     else {
491         cout << "No PAPI timings found in the file" << endl;
492     }
493
494 }
495
496
497 void EventInterpolator::LoadParameterFiles(){
498
499 // Load in Parameter File which maps event id to function name and parameters
500   cout << "Loading parameter files (May take a while)" << endl;
501
502   for(int i=0;true;++i){
503     char name[512];
504     sprintf(name,"param.%d",i);
505     ifstream parameterEventTable(name);
506
507     if(parameterEventTable.good()){
508 #ifdef DEBUG
509       cout << "     >  Loading " << name << endl;
510 #endif
511
512       while(parameterEventTable.good()){
513         string line_s;
514         getline(parameterEventTable,line_s);
515         istringstream line(line_s);
516
517         if(parameterEventTable.good()){
518           string t1, t2;
519           string funcname;
520           unsigned eventid;
521
522           line >> eventid;
523           line >> t1 >> t2;
524           line >> funcname;
525
526           if(t1 == string("TRACEBIGSIM")){
527 #ifdef PRETEND_NO_ENERGY
528             if(funcname == string("calc_pair_energy")){\
529               funcname = "calc_pair";
530             }
531             else if(funcname == string("calc_self_energy")){
532               funcname = "calc_self";
533             }
534 #endif
535
536             fullParams params = parseParameters(funcname,line);
537             funcIdentifier func(funcname,params.first);
538             Xcount[func] ++;
539             eventparams[make_pair(i,eventid)] = make_pair(func,params.second);
540           }
541         }
542       }
543
544     }
545     else{ // file was no good
546       break;
547     }
548
549     parameterEventTable.close();
550   }
551 }
552
553
554 EventInterpolator::EventInterpolator(char *table_filename, double sample_rate) :
555   exact_matches(0),
556   exact_positive_matches(0),
557   approx_matches(0),
558   approx_positive_matches(0)
559 {
560     LoadTimingsFile(table_filename);
561     AnalyzeTimings(sample_rate);
562    // AnalyzeTimings_PAPI();
563     LoadParameterFiles();
564 }
565
566
567 bool EventInterpolator::haveExactTime(const unsigned pe, const unsigned eventid){
568     return haveExactTime(eventparams[make_pair(pe,eventid)]);
569 }
570
571 bool EventInterpolator::haveExactTime(const pair<funcIdentifier,vector<double> > &p) {
572     return haveExactTime(p.first,p.second);
573 }
574
575 bool EventInterpolator::haveExactTime(const funcIdentifier& func, const vector<double> &p){
576   return (accurateTimings.find(make_pair(func,p)) != accurateTimings.end());
577 }
578
579 double EventInterpolator::lookupExactTime(const unsigned pe, const unsigned eventid){
580     return lookupExactTime(eventparams[make_pair(pe,eventid)]);
581 }
582
583 double EventInterpolator::lookupExactTime(const pair<funcIdentifier,vector<double> > &p) {
584     return lookupExactTime(p.first,p.second);
585 }
586
587 double EventInterpolator::lookupExactTime(const funcIdentifier& func, const vector<double> &p){
588     const  pair<funcIdentifier,vector<double> > key(func,p);
589     const int count = accurateTimings.count(key);
590
591         pair<timings_type::iterator, timings_type::iterator> itrs = accurateTimings.equal_range(key);
592         double time_sum=0;
593         for(timings_type::iterator itr=itrs.first; itr!=itrs.second; ++itr){
594           time_sum += (*itr).second;
595         }
596         double time_average = time_sum / count;
597
598     exact_matches++;
599         assert(time_average >= 0.0 );
600     return time_average;
601 }
602
603
604 /** Print out some statistics about the timings for any parameter that has multiple associated cycle-accurate timings */
605 void EventInterpolator::analyzeExactVariances(){
606
607     map< pair<funcIdentifier,vector<double> >, double > variances;
608     map< pair<funcIdentifier,vector<double> >, double > means;
609         map< funcIdentifier, double > max_std_dev;
610         map< funcIdentifier, double > associated_mean;
611
612         // Iterate through items in accurateTimings and store variances
613         timings_type::iterator itr;
614         for(itr=accurateTimings.begin();itr!=accurateTimings.end();++itr){
615           variances[(*itr).first] = lookupExactVariance( (*itr).first );
616           means[(*itr).first] = lookupExactMean( (*itr).first );
617         }
618
619         // Display the variances
620         map< pair<funcIdentifier,vector<double> >, double >::iterator vItr;
621         for(vItr = variances.begin(); vItr!=variances.end(); ++vItr){
622           double var = (*vItr).second;
623           double stddev = sqrt(var);
624           double mean = means[(*vItr).first];
625
626           if(var > 0.0){
627                 if(stddev > max_std_dev[(*vItr).first.first]){
628                   max_std_dev[(*vItr).first.first] = stddev;
629                   associated_mean[(*vItr).first.first] = mean;
630                 }
631           }
632         }
633
634         // Display the max std dev for any given event
635         cout << "\nThe following events have differing exact times for one or more parameter set.\n"
636                 "Each line corresponds to whichever parameter list produced the greatest variance\n"
637                 "(and equivalently std dev). The mean is the mean timing value associated with the\n"
638             " same parameter list of greatest variance" << endl << endl;
639
640
641         cout << "\t|===================================|=================|=================|==============|" << endl;
642         cout << "\t|                            event  |     max std dev |      mean (sec) | sd % of mean |" << endl;
643         cout << "\t|-----------------------------------|-----------------|-----------------|--------------|" << endl;
644
645 //      cout.setf(ios_base::fixed, ios_base::floatfield);
646     cout.setf(ios_base::scientific, ios_base::floatfield);
647         cout.precision(3);
648
649         int func_name_field_width=30;
650         map< funcIdentifier, double >::iterator sItr;
651         for(sItr=max_std_dev.begin(); sItr!=max_std_dev.end(); ++sItr) {
652           double stddev = (*sItr).second;
653           double mean = associated_mean[(*sItr).first];
654           cout << "\t|";
655           for(int i=0;i<func_name_field_width-(*sItr).first.first.length();++i)
656                 cout << " ";
657           cout << (*sItr).first.first ;
658           cout << ",";
659           cout.width(3);
660           cout << (*sItr).first.second;
661           cout << " | ";
662           cout.width(15);
663       cout.setf(ios_base::scientific, ios_base::floatfield);
664       cout.precision(3);
665           cout <<  stddev;
666           cout << " | ";
667       cout.width(15);
668       cout.setf(ios_base::scientific, ios_base::floatfield);
669       cout.precision(3);
670           cout << mean << " | ";
671           cout.width(9);
672       cout.setf(ios_base::fixed, ios_base::floatfield);
673       cout.precision(1);
674           cout << (stddev * 100.0 / mean) << "    | " << endl;
675         }
676         cout.setf(ios_base::fmtflags(0), ios_base::floatfield);
677         cout << "\t|===================================|=================|=================|==============|" << endl << endl;
678
679 }
680
681 /** Lookup the average timing for a given event and parameter list */
682 double EventInterpolator::lookupExactVariance(const unsigned pe, const unsigned eventid){
683     return lookupExactVariance(eventparams[make_pair(pe,eventid)]);
684 }
685
686 /** Lookup the variance in the timings for a given event and parameter list */
687 double EventInterpolator::lookupExactVariance(const pair<funcIdentifier,vector<double> > &p) {
688     return lookupExactVariance(p.first,p.second);
689 }
690
691 /** Lookup the variance in the timings for a given event and parameter list */
692 double EventInterpolator::lookupExactVariance(const funcIdentifier& func, const vector<double> &p){
693     const  pair<funcIdentifier,vector<double> > key(func,p);
694     const int count = accurateTimings.count(key);
695
696         // Compute mean
697         pair<timings_type::iterator, timings_type::iterator> itrs = accurateTimings.equal_range(key);
698         double time_sum=0;
699         for(timings_type::iterator itr=itrs.first; itr!=itrs.second; ++itr){
700           time_sum += (*itr).second;
701         }
702         const double time_average = time_sum / count;
703
704         // Compute Variance
705         double V_sum=0;
706         for(timings_type::iterator itr=itrs.first; itr!=itrs.second; ++itr){
707           const double d = (*itr).second-time_average;
708           V_sum += d*d;
709         }
710         const double Var = V_sum / count;
711
712     return Var;
713 }
714
715 /** Lookup the average timing for a given event and parameter list */
716 double EventInterpolator::lookupExactMean(const unsigned pe, const unsigned eventid){
717     return lookupExactMean(eventparams[make_pair(pe,eventid)]);
718 }
719 /** Lookup the average timing for a given event and parameter list */
720 double EventInterpolator::lookupExactMean(const pair<funcIdentifier,vector<double> > &p) {
721     return lookupExactMean(p.first,p.second);
722 }
723 /** Lookup the average timing for a given event and parameter list */
724 double EventInterpolator::lookupExactMean(const funcIdentifier& func, const vector<double> &p){
725     const  pair<funcIdentifier,vector<double> > key(func,p);
726     const int count = accurateTimings.count(key);
727
728         // Compute mean
729         pair<timings_type::iterator, timings_type::iterator> itrs = accurateTimings.equal_range(key);
730         double time_sum=0;
731         for(timings_type::iterator itr=itrs.first; itr!=itrs.second; ++itr){
732           time_sum += (*itr).second;
733         }
734         return time_sum / count;
735 }
736
737
738 /** If we have a parameterfile entry for the requested pe,eventid pair */
739 double EventInterpolator::haveNewTiming(const unsigned pe, const unsigned eventid) {
740     return eventparams.find( make_pair(pe,eventid) ) != eventparams.end();
741 }
742
743 double EventInterpolator::predictTime(const unsigned pe, const unsigned eventid) {
744     return predictTime(eventparams[make_pair(pe,eventid)]);
745 }
746
747 double EventInterpolator::predictTime(const pair<funcIdentifier,vector<double> > &p) {
748     return predictTime(p.first,p.second);
749 }
750
751 bool EventInterpolator::canInterpolateFunc(const funcIdentifier& func){
752     return (work.find(func) != work.end());
753 }
754
755
756 double EventInterpolator::getNewTiming(const unsigned pe, const unsigned eventid){
757   if(haveExactTime(pe,eventid) )
758         return lookupExactTime(pe,eventid);
759   else
760         return predictTime(pe,eventid);
761 }
762
763 double EventInterpolator::predictTime(const funcIdentifier &func, const vector<double> &params) {
764
765     // check name
766     if(!canInterpolateFunc(func)){
767         cerr << "FATAL ERROR: function name not found in cycle accurate timing file: " << func.first << "," << func.second << endl;
768        throw new runtime_error("function name not found");
769     }
770
771     // Estimate time for a given set of parameters p
772     gsl_vector *desired_params;
773
774     desired_params = gsl_vector_alloc(numCoefficients(func.first));
775     assert(numCoefficients(func.first)==params.size());
776
777     for(int i=0;i<params.size();++i){
778         gsl_vector_set(desired_params,i,params[i]);
779     }
780
781     double desired_time, desired_time_err;
782     assert(c[func]);
783     assert(cov[func]);
784     assert(! gsl_multifit_linear_est(desired_params,c[func],cov[func],&desired_time,&desired_time_err));
785
786     gsl_vector_free(desired_params);
787
788
789     if(min_interpolated_time.find(func) == min_interpolated_time.end())
790         min_interpolated_time[func] = desired_time;
791     else
792         min_interpolated_time[func] = min( min_interpolated_time[func], desired_time);
793
794     if(max_interpolated_time.find(func) == max_interpolated_time.end())
795         max_interpolated_time[func] = desired_time;
796     else
797         max_interpolated_time[func] = max( max_interpolated_time[func], desired_time);
798
799
800     approx_matches++;
801     if(desired_time>=0.0)
802         approx_positive_matches++;
803
804 //    gsl_vector_free(desired_params);
805
806
807     return desired_time;
808 }
809
810
811 void EventInterpolator::printMinInterpolatedTimes(){
812
813     cout << "The following functions were interpolated(as opposed to approximated:" << endl;
814
815     for(map<funcIdentifier,double>::iterator i=min_interpolated_time.begin();i!=min_interpolated_time.end();++i){
816         cout << "   > min predicted/interpolated time for function " << (*i).first.first << "," << (*i).first.second << " is " << (*i).second << " cycles " << endl;
817     }
818     for(map<funcIdentifier,double>::iterator i=max_interpolated_time.begin();i!=max_interpolated_time.end();++i){
819         cout << "   > max predicted/interpolated time for function " << (*i).first.first << "," << (*i).first.second << " is " << (*i).second << " cycles " << endl;
820     }
821
822     cout << endl;
823 }
824
825 void EventInterpolator::printMatches(){
826     cout << "    > Exact lookup = " << exact_matches << " (" << exact_positive_matches << " positive)" << endl;
827     cout << "    > Approximated = " << approx_matches << " (" << approx_positive_matches << " positive)" << endl;
828     cout << "    > Total        = " << approx_matches+exact_matches <<  " (" << exact_positive_matches+approx_positive_matches << " positive)" << endl;
829 }
830
831 void EventInterpolator::printCoefficients(){
832
833     for(map<funcIdentifier,gsl_vector*>::iterator i=c.begin();i!=c.end();++i){
834         cout << "    > Coefficients for function " << (*i).first.first << "," << (*i).first.second << " :" << endl;
835         for(int j=0; j < ((*i).second)->size; ++j){
836             cout << "    >    " << j << " is " << gsl_vector_get ((*i).second, j) << endl;
837         }
838     }
839
840 }
841
842
843
844
845 /** Free the gsl arrays and workspaces */
846 EventInterpolator::~EventInterpolator(){
847     map<funcIdentifier, gsl_multifit_linear_workspace *>::iterator i;
848     for(i=work.begin();i!=work.end();++i){
849         const funcIdentifier &func = (*i).first;
850         gsl_multifit_linear_free(work[func]);
851         gsl_matrix_free(cov[func]);
852         gsl_vector_free(c[func]);
853     }
854         log1.close();
855 }
856
857
858
859