| // |
| // See README-LCALS_license.txt for access and distribution restrictions |
| // |
| |
| // |
| // Source file containing routines used to gather and report |
| // performance data for LCALS suite |
| // |
| |
| #include "LCALSStats.hxx" |
| |
| #include<string> |
| #include<iostream> |
| #include<iomanip> |
| #include<sstream> |
| #include<fstream> |
| #include<limits> |
| #include<cstdlib> |
| #include<cmath> |
| |
| using namespace std; |
| |
| // |
| // LoopStat print routine for debugging. |
| // |
| void LoopStat::print(ostream& os) const |
| { |
| os << "\nLoopStat::print..." << endl; |
| os << "\tloop_is_run = " << loop_is_run << endl; |
| os << "\tnum loop lengths = " << loop_length.size() << endl; |
| for (unsigned i = 0; i < loop_length.size(); ++i) { |
| os << "\t\t ilength = " << i << " --> " << endl; |
| os << "\t\t\t loop_length = " << loop_length[i] << endl; |
| os << "\t\t\t samples_per_pass = " << samples_per_pass[i] << endl; |
| os << "\t\t\t loop_run_count = " << loop_run_count[i] << endl; |
| if ( loop_run_count[i] > 0 ) { |
| for (unsigned j = 0; j < loop_run_time[i].size(); ++j) { |
| os << "\t\t\t\t sample time = " << loop_run_time[i][j] << endl; |
| } |
| os << "\t\t\t\t mean = " << mean[i] << endl; |
| os << "\t\t\t\t std_dev = " << std_dev[i] << endl; |
| os << "\t\t\t\t min = " << min[i] << endl; |
| os << "\t\t\t\t max = " << max[i] << endl; |
| os << "\t\t\t\t harm_mean = " << harm_mean[i] << endl; |
| os << "\t\t\t\t meanrel2ref = " << meanrel2ref[i] << endl; |
| os << endl; |
| for (unsigned j = 0; j < loop_run_time[i].size(); ++j) { |
| os << "\t\t\t\t sample time = " << loop_run_time[i][j] << endl; |
| } |
| } |
| } |
| os << endl; |
| } |
| |
| |
| // |
| // File scope data holding structures needed to execute and time loops. |
| // |
| static LoopSuiteRunInfo* s_loop_suite_run_info = 0; |
| |
| // |
| // Accessor routine for suite run info. |
| // |
| LoopSuiteRunInfo& getLoopSuiteRunInfo() { return *s_loop_suite_run_info; } |
| |
| |
| // |
| // Define how suite will run and initialize timing structures for loops. |
| // |
| void allocateLoopSuiteRunInfo(const string& host_name, |
| unsigned num_loops, |
| unsigned num_loop_lengths, |
| unsigned num_suite_passes, |
| bool run_loop_length[], |
| CacheIndex_type cache_size) |
| { |
| #ifdef TESTSUITE |
| cout << "\n allocateLoopSuiteRunInfo..." << endl; |
| #endif |
| if ( s_loop_suite_run_info == 0 ) { |
| s_loop_suite_run_info = new LoopSuiteRunInfo(); |
| } |
| |
| s_loop_suite_run_info->host_name = host_name; |
| |
| s_loop_suite_run_info->num_loops = num_loops; |
| s_loop_suite_run_info->num_loop_lengths = num_loop_lengths; |
| s_loop_suite_run_info->num_suite_passes = num_suite_passes; |
| for (unsigned ilen = 0; ilen < num_loop_lengths; ++ilen) { |
| s_loop_suite_run_info->run_loop_length.push_back( |
| run_loop_length[ilen]); |
| } |
| |
| // |
| // To make sure all data cache levels are flushed completely, we |
| // define a data buffer with length equal to twice given cache size. |
| // |
| s_loop_suite_run_info->cache_flush_data_len = |
| (cache_size*2)/sizeof(Real_type); |
| s_loop_suite_run_info->cache_flush_data = |
| new double[s_loop_suite_run_info->cache_flush_data_len]; |
| for (CacheIndex_type i = 0; |
| i < s_loop_suite_run_info->cache_flush_data_len; ++i) { |
| s_loop_suite_run_info->cache_flush_data[i] = drand48() + 0.1; |
| } |
| |
| } |
| |
| // |
| // Free data structures defining loop suite execution. |
| // |
| void freeLoopSuiteRunInfo() |
| { |
| if ( s_loop_suite_run_info ) { |
| if ( s_loop_suite_run_info->cache_flush_data ) { |
| delete [] s_loop_suite_run_info->cache_flush_data; |
| } |
| delete s_loop_suite_run_info; |
| s_loop_suite_run_info = 0; |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////// |
| // |
| // Routines used for loop timing... |
| // |
| ////////////////////////////////////////////////////////////////// |
| |
| // |
| // Flush cache before each loop is run to minimize impact of one |
| // loop on another's execution. |
| // |
| void flushCache() |
| { |
| for (CacheIndex_type i = 0; |
| i < s_loop_suite_run_info->cache_flush_data_len; ++i) { |
| s_loop_suite_run_info->cache_flush_data_sum += |
| s_loop_suite_run_info->cache_flush_data[i]; |
| } |
| s_loop_suite_run_info->cache_flush_data_sum /= |
| s_loop_suite_run_info->cache_flush_data_len; |
| } |
| |
| |
| // |
| // Copy loop run time to LoopStat. |
| // |
| void copyTimer(LoopStat& loop_stat, int ilength, |
| const LoopTimer& loop_timer) |
| { |
| if ( loop_timer.was_run ) { |
| #if defined(LCALS_USE_CYCLE) |
| long double run_time = elapsed(loop_timer.stop, |
| loop_timer.start); |
| #elif defined(LCALS_USE_CLOCK) |
| long double run_time = |
| static_cast<long double>(loop_timer.stop - |
| loop_timer.start) / CLOCKS_PER_SEC; |
| #else |
| #error LCALS_TIMER_TYPE is undefined! |
| |
| #endif |
| loop_stat.loop_run_time[ilength].push_back( run_time ); |
| } |
| } |
| |
| |
| |
| // |
| // Compute statistics for loop run for variant with given index. |
| // |
| void computeStats( unsigned ilv, vector<LoopStat>& loop_stats, |
| bool do_fom ) |
| { |
| |
| // compute stats for each loop... |
| for ( unsigned iloop = 0; iloop < loop_stats.size(); ++iloop ) { |
| |
| LoopStat& stat = loop_stats[iloop]; |
| |
| if ( stat.loop_is_run ) { |
| |
| // compute stats for each length loop is run... |
| for ( unsigned ilen = 0; ilen < stat.loop_length.size(); ++ilen ) { |
| |
| if ( stat.loop_run_count[ilen] > 0 ) { |
| |
| vector<long double>& time_sample = |
| stat.loop_run_time[ilen]; |
| unsigned sample_size = time_sample.size(); |
| |
| long double mean = 0.0; |
| long double sdev = 0.0; |
| long double max = -std::numeric_limits<long double>::max(); |
| long double min = std::numeric_limits<long double>::max(); |
| long double harm = 0.0; |
| |
| for (unsigned is = 0; is < sample_size; ++is) { |
| mean += time_sample[is]; |
| max = std::max(max, time_sample[is]); |
| min = std::min(min, time_sample[is]); |
| if ( time_sample[is] > 0.0 ) { |
| harm += 1.0/time_sample[is]; |
| } |
| } |
| |
| mean /= sample_size; |
| |
| if ( harm > 0.0 ) { harm = sample_size/harm; } |
| |
| for (unsigned is = 0; is < sample_size; ++is) { |
| sdev += (time_sample[is] - mean)*(time_sample[is] - mean); |
| } |
| |
| sdev /= sample_size; |
| |
| stat.mean[ilen] = mean; |
| stat.std_dev[ilen] = sdev; |
| stat.min[ilen] = min; |
| stat.max[ilen] = max; |
| stat.harm_mean[ilen] = harm; |
| |
| } // if loop length was run |
| |
| } // iterate over loop lengths |
| |
| } // if loop is run |
| |
| } // iterate over loops |
| |
| // |
| // FOM calculations (done separately for simplicity) |
| // |
| if ( do_fom ) { |
| |
| LoopSuiteRunInfo& suite_info = getLoopSuiteRunInfo(); |
| LoopStat& ref_loop_stat = suite_info.ref_loop_stat; |
| |
| std::vector<int> num_loops_run(suite_info.num_loop_lengths, 0); |
| std::vector< long double > tot_weight(suite_info.num_loop_lengths, 0.0); |
| std::vector< long double > tot_time(suite_info.num_loop_lengths, 0.0); |
| std::vector< long double > fom_rel(suite_info.num_loop_lengths, 0.0); |
| std::vector< long double > fom_rate(suite_info.num_loop_lengths, 0.0); |
| |
| for ( unsigned iloop = 0; iloop < loop_stats.size(); ++iloop ) { |
| |
| LoopStat& stat = loop_stats[iloop]; |
| |
| if ( stat.loop_is_run ) { |
| |
| for ( unsigned ilen = 0; ilen < stat.loop_length.size(); ++ilen ) { |
| |
| if ( stat.loop_run_count[ilen] > 0 ) { |
| |
| num_loops_run[ilen]++; |
| tot_weight[ilen] += stat.loop_weight; |
| tot_time[ilen] += stat.mean[ilen]; |
| |
| // |
| // sum weighted loop time |
| // |
| fom_rel[ilen] += stat.loop_weight * stat.mean[ilen]; |
| |
| // |
| // sum weighted loop iteration rate |
| // |
| fom_rate[ilen] += (stat.loop_weight * stat.mean[ilen]) / |
| (stat.loop_length[ilen] * stat.samples_per_pass[ilen]); |
| |
| } // if loop length was run |
| |
| } // iterate over loop lengths |
| |
| } // if loop is run |
| |
| } // iterate over loops |
| |
| for (unsigned ilen = 0; ilen < suite_info.num_loop_lengths; ++ilen) { |
| suite_info.num_loops_run[ilv][ilen] = num_loops_run[ilen]; |
| suite_info.tot_time[ilv][ilen] = tot_time[ilen]; |
| |
| long double ref_time = ref_loop_stat.loop_run_time[ilen][0]; |
| |
| if ( num_loops_run[ilen] > 0 ) { |
| #if 0 // this makes 0 <= fom_rel <= 1/tot_time |
| suite_info.fom_rel[ilv][ilen] = |
| ref_time * tot_weight[ilen] / ( tot_time[ilen] * fom_rel[ilen] ); |
| #else // this makes 0 <= fom_rel <= 1 |
| suite_info.fom_rel[ilv][ilen] = |
| ref_time * tot_weight[ilen] / fom_rel[ilen] ; |
| #endif |
| suite_info.fom_rate[ilv][ilen] = 1.0 / fom_rate[ilen]; |
| } |
| } |
| |
| } |
| |
| } |
| |
| |
| // |
| // Forward declarations for routines that write loop reports. |
| // |
| namespace { |
| |
| void writeTimingSummaryReport( |
| const vector< string >& run_loop_variants, |
| ostream& os); |
| |
| void writeChecksumReport( |
| const vector< string >& run_loop_variants, |
| ostream& os); |
| |
| void writeFOMReport( |
| const vector< string >& run_loop_variants, |
| ostream& os); |
| |
| void writeMeanTimeReport(const string& variant_name, |
| const string& output_dirname); |
| |
| void writeRelativeTimeReport(const string& variant_name, |
| const string& output_dirname); |
| |
| std::string buildVersionInfo(); |
| |
| }; // unnamed namespace |
| |
| |
| // |
| // Routine called from main() to generate timing report(s). |
| // |
| void generateTimingReport(const vector< string >& run_loop_variants, |
| const string& output_dirname) |
| { |
| if ( run_loop_variants.size() == 0 ) return; |
| |
| bool do_fom = true; |
| |
| std::string ver_info = buildVersionInfo(); |
| |
| // |
| // Compute statistics for all loops. |
| // |
| LoopSuiteRunInfo& suite_run_info = getLoopSuiteRunInfo(); |
| const unsigned nvariants = run_loop_variants.size(); |
| for (unsigned ilv = 0; ilv < nvariants; ++ilv) { |
| computeStats( ilv, suite_run_info.getLoopStats(run_loop_variants[ilv]), |
| do_fom ); |
| } |
| |
| // |
| // If output directory name is given, write files in that directory. |
| // Else, write only summary to standard output. |
| // |
| if (!output_dirname.empty()) { |
| |
| string timing_fname(output_dirname + "/" + "timing.txt"); |
| ofstream file(timing_fname.c_str(), ios::out | ios::trunc); |
| if ( !file ) { |
| cout << " ERROR: Can't open output file " |
| << timing_fname << endl; |
| } |
| cout << "\n writeTimingSummaryReport... " << timing_fname << endl; |
| writeTimingSummaryReport(run_loop_variants, file); |
| |
| // |
| // Write mean run time file for each loop variant. |
| // |
| for (unsigned ilv = 0; ilv < nvariants; ++ilv) { |
| writeMeanTimeReport( run_loop_variants[ilv], output_dirname ); |
| } |
| |
| // |
| // Write relative run time file for each loop variant. |
| // |
| // NOTE: We assume variant "zero" is reference. |
| // |
| for (unsigned ilv = 1; ilv < nvariants; ++ilv) { |
| writeRelativeTimeReport( run_loop_variants[ilv], output_dirname ); |
| } |
| |
| } else { |
| |
| writeTimingSummaryReport(run_loop_variants, cout); |
| |
| } |
| } |
| |
| // |
| // Routine called from main() to generate checksum report. |
| // |
| void generateChecksumReport( |
| const vector< string >& run_loop_variants, |
| const string& output_dirname) |
| { |
| #if defined(LCALS_VERIFY_CHECKSUM) |
| if ( run_loop_variants.size() == 0 ) return; |
| |
| // |
| // If output directory name is given, write file in that directory. |
| // Else, write summary to standard output. |
| // |
| if (!output_dirname.empty()) { |
| string checksum_fname(output_dirname + "/" + "checksum.txt"); |
| ofstream file(checksum_fname.c_str(), ios::out | ios::trunc); |
| if ( !file ) { |
| cout << " ERROR: Can't open output file " |
| << checksum_fname << endl; |
| } |
| cout << "\n writeChecksumReport... " << checksum_fname << endl; |
| writeChecksumReport(run_loop_variants, file); |
| } else { |
| writeChecksumReport(run_loop_variants, cout); |
| } |
| #endif |
| } |
| |
| // |
| // Routine called from main() to generate FOM report. |
| // |
| void generateFOMReport( |
| const vector< string >& run_loop_variants, |
| const string& output_dirname) |
| { |
| if ( run_loop_variants.size() == 0 ) return; |
| |
| // |
| // If output directory name is given, write file in that directory. |
| // Else, write only summary to standard output. |
| // |
| if (!output_dirname.empty()) { |
| string fom_fname(output_dirname + "/" + "fom.txt"); |
| ofstream file(fom_fname.c_str(), ios::out | ios::trunc); |
| if ( !file ) { |
| cout << " ERROR: Can't open output file " |
| << fom_fname << endl; |
| } |
| cout << "\n writeFOMReport... " << fom_fname << endl; |
| writeFOMReport(run_loop_variants, file); |
| } else { |
| writeFOMReport(run_loop_variants, cout); |
| } |
| } |
| |
| |
| // |
| // Implementation of file-scope routines that write loop reports. |
| // |
| namespace { |
| |
| // |
| // Write report about loop execution timings to given output stream. |
| // |
| void writeTimingSummaryReport(const vector< string >& run_loop_variants, |
| ostream& os) |
| { |
| LoopSuiteRunInfo& suite_run_info = getLoopSuiteRunInfo(); |
| const unsigned nvariants = run_loop_variants.size(); |
| |
| const string& ref_variant = run_loop_variants[0]; |
| vector<string>& loop_names = suite_run_info.loop_names; |
| |
| // |
| // Define some strings used to print summary table. |
| // |
| string equal_line("===========================================================================================================\n"); |
| string dash_line("------------------------------------------------------------------------------------------------------------\n"); |
| string dash_line_part("-------------------------------------------------------\n"); |
| string dot_line_part("............................................\n"); |
| vector<string> len_id(suite_run_info.loop_length_names.size()); |
| for (unsigned ilen = 0; ilen < len_id.size(); ++ilen) { |
| len_id[ilen] = suite_run_info.loop_length_names[ilen][0]; |
| } |
| |
| std::string ver_info = buildVersionInfo(); |
| |
| // |
| // Print compilation summary information. |
| // |
| os << "\n\n\n"; |
| os << equal_line; |
| os << equal_line; |
| |
| os << "LCALS compilation summary: " << endl; |
| os << ver_info << endl; |
| |
| // |
| // Print basic run summary information. |
| // |
| os << "\n\n"; |
| os << equal_line; |
| os << equal_line; |
| |
| os << "LCALS run summary: " << endl; |
| os << "sizeof(Real_type) = " << sizeof(Real_type) << endl; |
| os << " num suite passes = " << suite_run_info.num_suite_passes << endl; |
| os << " loop sample fraction = " << suite_run_info.loop_samp_frac << endl; |
| os << " loop variants run : "; |
| for (unsigned ilv = 0; ilv < nvariants; ++ilv) { |
| string last_char; |
| if ( ilv+1 < run_loop_variants.size() ) last_char = string(" , "); |
| os << run_loop_variants[ilv] << last_char; |
| } |
| os << "\n reference variant : " << ref_variant << endl; |
| os << equal_line; |
| os << equal_line; |
| |
| // |
| // Set basic table formatting. |
| // |
| size_t max_name_len = 0; |
| for (size_t iloop = 0; iloop < loop_names.size(); ++iloop) { |
| max_name_len = max(max_name_len, loop_names[iloop].size()); |
| } |
| |
| size_t max_var_name_len = 0; |
| for (size_t ilv = 0; ilv < nvariants; ++ilv) { |
| max_var_name_len = |
| max(max_var_name_len, run_loop_variants[ilv].size()); |
| } |
| |
| string var_field("Variant(length id)"); |
| size_t var_field_len = var_field.size(); |
| unsigned prec = 10; |
| unsigned prec_buf = prec + 8; |
| unsigned reldiff_prec = 6; |
| |
| // |
| // Print table column headers. |
| // |
| os << "Loop name(Loop ID) --> <length id>:(length, samples/pass), etc." |
| << endl; |
| os <<left<< setw(var_field_len+1) << var_field; |
| os <<right<< setw(prec_buf) << " Mean Time "; |
| os <<left<< setw(prec_buf) << " Min Time"; |
| os <<left<< setw(prec_buf) << " Max Time"; |
| os <<left<< setw(prec_buf) << " Std. Dev."; |
| os <<left<< setw(prec_buf) << "Mean time rel to ref variant" << endl; |
| os << dash_line; |
| |
| |
| // |
| // Print timing results for all loops in a table. |
| // |
| for (unsigned iloop = 0; iloop < loop_names.size(); ++iloop) { |
| |
| LoopStat& ref_variant_stat = suite_run_info. |
| getLoopStats(run_loop_variants[0])[iloop]; |
| vector<long double> ref_mean(ref_variant_stat.mean); |
| |
| if ( !loop_names[iloop].empty() && ref_variant_stat.loop_is_run ) { |
| |
| if ( iloop > 1 ) { // magic numbers are bad!! |
| os << endl << dash_line_part; |
| } |
| os <<left << loop_names[iloop] << " (" << iloop << ") --> "; |
| |
| for (unsigned ilv = 0; ilv < nvariants; ++ilv) { |
| |
| LoopStat& stat = suite_run_info. |
| getLoopStats(run_loop_variants[ilv])[iloop]; |
| |
| if ( stat.loop_is_run ) { |
| |
| // |
| // Print separator line for new loop or new variant. |
| // |
| if ( ilv == 0 ) { |
| |
| for (unsigned ilen = 0; ilen < stat.loop_length.size(); ++ilen) { |
| os << " " << len_id[ilen] << ":(" |
| << stat.loop_length[ilen] << ", " |
| << stat.samples_per_pass[ilen] << ")"; |
| } |
| os << endl; |
| |
| } else { |
| |
| os << dot_line_part; |
| |
| } |
| |
| // |
| // Print statistics for each length of loop run. |
| // |
| for (unsigned ilen = 0; ilen < stat.loop_length.size(); ++ilen) { |
| |
| if ( stat.loop_run_count[ilen] > 0 ) { |
| |
| string var_string(run_loop_variants[ilv] + |
| "(" + len_id[ilen] + ")"); |
| |
| os << showpoint << setprecision(prec) |
| <<left<< setw(var_field_len+1) << var_string; |
| |
| os <<right<< setw(prec_buf) << stat.mean[ilen]; |
| os <<right<< setw(prec_buf) << stat.min[ilen]; |
| os <<right<< setw(prec_buf) << stat.max[ilen]; |
| os <<right<< setw(prec_buf) << stat.std_dev[ilen]; |
| |
| if ( ilv > 0 ) { |
| // compare mean run time to reference variant |
| |
| long double rel_mean_diff = 0; |
| if ( ref_mean[ilen] != 0.0 ) { |
| rel_mean_diff = 1.0 + |
| (stat.mean[ilen]-ref_mean[ilen])/ref_mean[ilen]; |
| } |
| os <<right<< setprecision(reldiff_prec) << setw(prec_buf) |
| << rel_mean_diff << endl; |
| stat.meanrel2ref[ilen] = rel_mean_diff; |
| } else { |
| os << endl; |
| } |
| |
| } // if loop length was run |
| |
| } // iterate over loop lengths |
| |
| } // if loop is run |
| |
| } // iterate over variants of loop run |
| |
| } // if loop name is not empty |
| |
| } // iterate over loops |
| |
| |
| os << dash_line; |
| os << "\n\n\n"; |
| |
| os.flush(); |
| } |
| |
| |
| // |
| // Write report about loop chksums to given output stream. |
| // |
| void writeChecksumReport(const vector< string >& run_loop_variants, |
| ostream& os) |
| { |
| LoopSuiteRunInfo& suite_run_info = getLoopSuiteRunInfo(); |
| const unsigned nvariants = run_loop_variants.size(); |
| const string& ref_variant = run_loop_variants[0]; |
| vector<string>& loop_names = suite_run_info.loop_names; |
| |
| // |
| // Define some strings used to print summary table. |
| // |
| string equal_line("===========================================================================================================\n"); |
| string dash_line("------------------------------------------------------------------------------------------------------------\n"); |
| string dash_line_part("-------------------------------------------------------\n"); |
| string dot_line_part("............................................\n"); |
| vector<string> len_id(suite_run_info.loop_length_names.size()); |
| for (unsigned ilen = 0; ilen < len_id.size(); ++ilen) { |
| len_id[ilen] = suite_run_info.loop_length_names[ilen][0]; |
| } |
| |
| std::string ver_info = buildVersionInfo(); |
| |
| // |
| // Print compilation summary information. |
| // |
| os << "\n\n\n"; |
| os << equal_line; |
| os << equal_line; |
| |
| os << "LCALS compilation summary: " << endl; |
| os << ver_info << endl; |
| |
| // |
| // Print checksum information. |
| // |
| os << "\n\n"; |
| os << equal_line; |
| os << equal_line; |
| |
| // |
| // Set basic table formatting. |
| // |
| size_t max_name_len = 0; |
| for (size_t iloop = 0; iloop < loop_names.size(); ++iloop) { |
| max_name_len = max(max_name_len, loop_names[iloop].size()); |
| } |
| |
| size_t max_var_name_len = 0; |
| for (size_t ilv = 0; ilv < nvariants; ++ilv) { |
| max_var_name_len = |
| max(max_var_name_len, run_loop_variants[ilv].size()); |
| } |
| |
| string var_field("Variant(length #)"); |
| size_t var_field_len = var_field.size(); |
| unsigned prec = 32; |
| unsigned prec_buf = prec + 8; |
| |
| // |
| // Print table column headers. |
| // |
| os << "Loop name -->" << endl; |
| os <<left<< setw(var_field_len+1) << var_field; |
| os <<right<< setw(prec_buf) << "Check Sum "; |
| os <<left<< setw(prec_buf) << " Delta from reference" << endl; |
| os << dash_line; |
| |
| // |
| // Print check sums for all loops in a table. |
| // |
| for (unsigned iloop = 0; iloop < loop_names.size(); ++iloop) { |
| |
| LoopStat& ref_variant_stat = suite_run_info. |
| getLoopStats(run_loop_variants[0])[iloop]; |
| vector<long double> ref_chksum(ref_variant_stat.loop_chksum); |
| |
| if ( !loop_names[iloop].empty() && ref_variant_stat.loop_is_run ) { |
| |
| if ( iloop > 1 ) { // magic numbers are bad!! |
| os << endl << dash_line_part; |
| } |
| os <<left << loop_names[iloop] << " (" << iloop << ") --> "; |
| |
| for (unsigned ilv = 0; ilv < nvariants; ++ilv) { |
| |
| LoopStat& stat = suite_run_info. |
| getLoopStats(run_loop_variants[ilv])[iloop]; |
| |
| if ( stat.loop_is_run ) { |
| |
| // |
| // Print separator line for new loop or new variant. |
| // |
| if ( ilv == 0 ) { |
| os << endl; |
| } else { |
| os << dot_line_part; |
| } |
| |
| // |
| // Print checksum for each length of loop run. |
| // |
| for (unsigned ilen = 0; ilen < stat.loop_length.size(); ++ilen) { |
| |
| if ( stat.loop_run_count[ilen] > 0 ) { |
| |
| string var_string(run_loop_variants[ilv] + |
| "(" + len_id[ilen] + ")"); |
| |
| os << showpoint << setprecision(prec) |
| <<left<< setw(var_field_len+1) << var_string; |
| |
| os <<right<< setw(prec_buf) << stat.loop_chksum[ilen]; |
| |
| if ( ilv > 0 ) { |
| // compare checksum to reference variant |
| long double chksum_diff = fabs( |
| stat.loop_chksum[ilen]-ref_chksum[ilen] ); |
| os <<right<< setw(prec_buf) |
| << chksum_diff << endl; |
| } else { |
| os << endl; |
| } |
| |
| } // if loop length was run |
| |
| } // iterate over loop lengths |
| |
| } // if loop is run |
| |
| } // iterate over variants of loop run |
| |
| } // if loop name is not empty |
| |
| } // iterate over loops |
| |
| |
| os << dash_line; |
| os << "\n\n\n"; |
| |
| os.flush(); |
| } |
| |
| // |
| // Generate FOM report file to given output stream. |
| // |
| void writeFOMReport(const vector< string >& run_loop_variants, |
| ostream& os) |
| { |
| LoopSuiteRunInfo& suite_run_info = getLoopSuiteRunInfo(); |
| const unsigned nvariants = run_loop_variants.size(); |
| |
| // |
| // Define some strings used to print FOM summary table. |
| // |
| string equal_line("===========================================================================================================\n"); |
| string dash_line_part("-------------------------------------------------------\n"); |
| string dot_line_part("............................................\n"); |
| |
| std::string ver_info = buildVersionInfo(); |
| |
| // |
| // Print compilation summary information. |
| // |
| os << "\n\n\n"; |
| os << equal_line; |
| os << equal_line; |
| |
| os << "LCALS compilation summary: " << endl; |
| os << ver_info << endl; |
| |
| // |
| // Print checksum information. |
| // |
| os << "\n\n"; |
| os << equal_line; |
| os << equal_line; |
| |
| os << "LCALS FOM results: " << endl; |
| os << equal_line; |
| |
| vector<string>& len_name = suite_run_info.loop_length_names; |
| |
| unsigned prec = 32; |
| // |
| // Output FOM for each loop variant (and loop lengths) |
| // |
| for (unsigned ilv = 0; ilv < nvariants; ++ilv) { |
| |
| vector< int >& num_loops_run = suite_run_info.num_loops_run[ilv]; |
| vector< long double >& tot_time = suite_run_info.tot_time[ilv]; |
| vector< long double >& fom_rel = suite_run_info.fom_rel[ilv]; |
| vector< long double >& fom_rate = suite_run_info.fom_rate[ilv]; |
| |
| os <<left << "Loop variant -- " << run_loop_variants[ilv] << endl; |
| |
| for (unsigned ilen = 0; ilen < len_name.size(); ++ilen) { |
| os << "\t" << len_name[ilen] |
| << " : # loops run = " << num_loops_run[ilen]; |
| os << showpoint << setprecision(prec) |
| << " , total exec time = " << tot_time[ilen] << endl; |
| os << "\t\tFOM_relative = " << fom_rel[ilen] << endl; |
| #if 0 // It's not clear what this FOM rate means... |
| os << "\t\tFOM_rate = " << fom_rate[ilen] << endl; |
| #endif |
| |
| if ( ilen < len_name.size() - 1 ) { |
| os << dot_line_part; |
| } |
| } |
| |
| if ( ilv < nvariants - 1 ) { |
| os << endl << dash_line_part; |
| } |
| |
| } |
| |
| os << equal_line; |
| os << "\n\n\n"; |
| |
| os.flush(); |
| } |
| |
| // |
| // Write mean run time report file. |
| // |
| void writeMeanTimeReport(const string& variant_name, |
| const string& output_dirname) |
| { |
| string rept_fname(output_dirname + "/"); |
| rept_fname += variant_name; |
| rept_fname += string("-meantime.txt"); |
| |
| ofstream file(rept_fname.c_str(), ios::out | ios::trunc); |
| if ( !file ) { |
| cout << " ERROR: Can't open output file " << rept_fname << endl; |
| } |
| cout << "\n writeMeanTimeReport... " << rept_fname << endl; |
| |
| LoopSuiteRunInfo& suite_run_info = getLoopSuiteRunInfo(); |
| |
| vector<string>& loop_names = suite_run_info.loop_names; |
| vector<string>& len_names = suite_run_info.loop_length_names; |
| |
| const string sepchr(" , "); |
| unsigned prec = 8; |
| |
| // |
| // Print title line. |
| // |
| file << variant_name << " Mean Run Times "; |
| for (unsigned i = 0; i < len_names.size(); ++i) { |
| file << sepchr; |
| } |
| file << endl; |
| |
| // |
| // Print column header line. |
| // |
| for (unsigned i = 0; i < len_names.size(); ++i) { |
| file << sepchr << len_names[i]; |
| } |
| file << endl; |
| |
| // |
| // Print row of times for each loop. |
| // |
| for (unsigned iloop = 0; iloop < loop_names.size(); ++iloop) { |
| |
| LoopStat& stat = suite_run_info. |
| getLoopStats(variant_name)[iloop]; |
| |
| if ( !loop_names[iloop].empty() && stat.loop_is_run ) { |
| |
| file << loop_names[iloop]; |
| for (unsigned ilen = 0; ilen < stat.loop_length.size(); ++ilen) { |
| file << sepchr << setprecision(prec) << stat.mean[ilen]; |
| } |
| file << endl; |
| |
| } |
| |
| } |
| |
| file.flush(); |
| } |
| |
| // |
| // Write relative run time report file. |
| // |
| void writeRelativeTimeReport(const string& variant_name, |
| const string& output_dirname) |
| { |
| string rept_fname(output_dirname + "/"); |
| rept_fname += variant_name; |
| rept_fname += string("-reltime.txt"); |
| |
| ofstream file(rept_fname.c_str(), ios::out | ios::trunc); |
| if ( !file ) { |
| cout << " ERROR: Can't open output file " << rept_fname << endl; |
| } |
| cout << "\n writeRelativeTimeReport... " << rept_fname << endl; |
| |
| LoopSuiteRunInfo& suite_run_info = getLoopSuiteRunInfo(); |
| |
| vector<string>& loop_names = suite_run_info.loop_names; |
| vector<string>& len_names = suite_run_info.loop_length_names; |
| |
| const string sepchr(" , "); |
| unsigned prec = 6; |
| |
| // |
| // Print title line. |
| // |
| file << variant_name << " Relative Run Times "; |
| for (unsigned i = 0; i < len_names.size(); ++i) { |
| file << sepchr; |
| } |
| file << endl; |
| |
| // |
| // Print column header line. |
| // |
| for (unsigned i = 0; i < len_names.size(); ++i) { |
| file << sepchr << len_names[i]; |
| } |
| file << endl; |
| |
| // |
| // Print row of times for each loop. |
| // |
| for (unsigned iloop = 0; iloop < loop_names.size(); ++iloop) { |
| |
| LoopStat& stat = suite_run_info. |
| getLoopStats(variant_name)[iloop]; |
| |
| if ( !loop_names[iloop].empty() && stat.loop_is_run ) { |
| |
| file << loop_names[iloop]; |
| for (unsigned ilen = 0; ilen < stat.loop_length.size(); ++ilen) { |
| file << sepchr << setprecision(prec) << stat.meanrel2ref[ilen]; |
| } |
| file << endl; |
| |
| } |
| |
| } |
| |
| file.flush(); |
| } |
| |
| // |
| // Build string containing LCALS compilation information from |
| // file created when make is invoked. |
| // |
| std::string buildVersionInfo() |
| { |
| std::ifstream infile("lcalsversioninfo.txt", std::ios::in); |
| |
| std::string ver_info; |
| |
| infile.seekg(0, std::ios::end); |
| ver_info.reserve(infile.tellg()); |
| infile.seekg(0, std::ios::beg); |
| |
| ver_info.assign((std::istreambuf_iterator<char>(infile)), |
| std::istreambuf_iterator<char>()); |
| infile.close(); |
| |
| #if 0 |
| std::string ver_info = "LCALS compilation info: \n" |
| << "\tUser = " << VER_PERSON << "\n" |
| << "\tDate, Time = " << VER_DATE << " , " << VER_TIME << "\n" |
| << "\tMachine = " << VER_MACHINE << "\n" |
| << "\tOS = " << VER_OS << "\n" |
| << "\t-----------------------------------------------" << "\n" |
| << "\tCompiler + options = " << lcals_ver_info_values[0] << "\n" |
| << "\tLCALS rules (defines) = " << lcals_ver_info_values[1] << "\n"; |
| #endif |
| return ver_info; |
| } |
| |
| }; // unnamed namespace |
| |
| |
| |