11 #include <unordered_set>
13 #include "hebench/modules/general/include/hebench_math_utils.h"
14 #include "hebench/modules/general/include/hebench_utilities.h"
22 std::vector<double> sorted_data(data, data + count);
23 std::sort(sorted_data.begin(), sorted_data.end());
24 std::size_t trim_start = sorted_data.size() / 10;
27 hebench::Utilities::Math::EventStats basic_stats;
28 for (std::size_t i = 0; i < count; ++i)
29 basic_stats.newEvent(data[i]);
30 hebench::Utilities::Math::EventStats trimmed_stats;
31 for (std::size_t i = trim_start; i < sorted_data.size() - trim_start; ++i)
32 trimmed_stats.newEvent(sorted_data[i]);
35 result.
total = basic_stats.getTotal();
36 result.
ave = basic_stats.getMean();
37 result.
variance = basic_stats.getVariance();
38 result.
min = basic_stats.getMin();
39 result.
max = basic_stats.getMax();
41 result.
median = hebench::Utilities::Math::computePercentile(sorted_data.data(), sorted_data.size(), 0.5);
42 result.
pct_1 = hebench::Utilities::Math::computePercentile(sorted_data.data(), sorted_data.size(), 0.01);
43 result.
pct_10 = hebench::Utilities::Math::computePercentile(sorted_data.data(), sorted_data.size(), 0.1);
44 result.
pct_90 = hebench::Utilities::Math::computePercentile(sorted_data.data(), sorted_data.size(), 0.9);
45 result.
pct_99 = hebench::Utilities::Math::computePercentile(sorted_data.data(), sorted_data.size(), 0.95);
47 result.
ave_trim = trimmed_stats.getMean();
49 result.
samples_per_unit = (basic_stats.getTotal() == 0.0 ? 0.0 : basic_stats.getCount() / basic_stats.getTotal());
50 result.
samples_per_unit_trim = (trimmed_stats.getTotal() == 0.0 ? 0.0 : trimmed_stats.getCount() / trimmed_stats.getTotal());
69 EventType(
const std::vector<double> &cpu_events,
const std::vector<double> &wall_events,
70 std::uint32_t event_id,
const std::string_view &event_name);
75 std::uint32_t
getID()
const {
return m_id; }
79 const std::string &
getName()
const {
return m_name; }
83 const std::vector<double> &
getCPUEvents()
const {
return m_cpu_events; }
87 const std::vector<double> &
getWallEvents()
const {
return m_wall_events; }
112 std::vector<double> m_cpu_events;
113 std::vector<double> m_wall_events;
121 std::exception_ptr p_ex;
124 for (std::uint64_t event_i = 0; event_i < report.
getEventCount(); ++event_i)
145 p_ex = std::current_exception();
152 p_ex = std::current_exception();
158 std::rethrow_exception(p_ex);
162 std::uint32_t event_id,
const std::string_view &event_name)
164 if (cpu_events.size() != wall_events.size())
165 throw std::invalid_argument(
"Number of CPU events and Wall events cannot differ.");
168 m_name = std::string(event_name.begin(), event_name.end());
169 m_cpu_events = cpu_events;
170 m_wall_events = wall_events;
215 throw std::invalid_argument(
"Report belongs to a failed benchmark.");
222 std::vector<std::uint32_t> event_ids;
226 std::unordered_map<std::uint32_t, std::vector<double>> cpu_events;
227 std::unordered_map<std::uint32_t, std::vector<double>> wall_events;
231 for (std::uint64_t event_i = 0; event_i < report.
getEventCount(); ++event_i)
240 cpu_events[
event.event_type_id] = std::vector<double>();
245 wall_events[
event.event_type_id] = std::vector<double>();
250 for (std::uint64_t i = 0; i <
event.input_sample_count; ++i)
252 cpu_events[
event.event_type_id].push_back(cpu_time);
253 wall_events[
event.event_type_id].push_back(wall_time);
258 std::sort(event_ids.begin(), event_ids.end());
261 for (std::size_t event_id_i = 0; event_id_i < event_ids.size(); ++event_id_i)
263 std::uint32_t event_id = event_ids[event_id_i];
265 m_event_types_2_stat_idx[event_type.
getID()] = event_id_i;
266 std::shared_ptr<ReportEventTypeStats> p_stats = std::make_shared<ReportEventTypeStats>();
268 m_event_stats.push_back(p_stats);
274 if (index >= m_event_stats.size())
276 std::stringstream ss;
277 ss <<
"Out of range `index`. Received " << index <<
", but expected less than " << m_event_stats.size() <<
".";
278 throw std::out_of_range(ss.str());
280 if (!m_event_stats[index])
281 throw std::runtime_error(
"Unexpected empty stats.");
282 return *m_event_stats[index];
292 return m_event_types_2_stat_idx.at(m_main_event_type_id);
303 throw std::ios_base::failure(
"Output stream is in an invalid state.");
307 <<
"Notes" << std::endl
312 <<
",,,,,Wall Time,,,,,,,,,,,,,CPU Time" << std::endl
313 <<
"ID,Event,Total Wall Time,Samples per sec,Samples per sec trimmed,"
315 <<
"Average,Standard Deviation,Time Unit,Time Factor,Min,Max,Median,Trimmed Average,Trimmed Standard Deviation,1-th percentile,10-th percentile,90-th percentile,99-th percentile,"
317 <<
"Average,Standard Deviation,Time Unit,Time Factor,Min,Max,Median,Trimmed Average,Trimmed Standard Deviation,1-th percentile,10-th percentile,90-th percentile,99-th percentile,Input Samples" << std::endl;
319 throw std::ios_base::failure(
"Error writing statistics report header to stream.");
320 for (std::uint64_t event_stats_i = 0; event_stats_i < m_event_stats.size(); ++event_stats_i)
321 if (m_event_stats[event_stats_i])
322 generateCSV(os, *m_event_stats[event_stats_i], ch_prefix);
328 throw std::ios_base::failure(
"Output stream is in an invalid state.");
337 << hebench::Utilities::convertDoubleToStr(stats.
ops_per_sec) <<
","
368 throw std::ios_base::failure(
"Error writing statistics row to stream.");
374 throw std::ios_base::failure(
"Output stream is in an invalid state.");
378 <<
"Notes" << std::endl
383 <<
",,,Wall Time,,,,CPU Time" << std::endl
384 <<
"ID,Event,Samples per sec,"
385 <<
"Average,Standard Deviation,Time Unit,Time Factor,"
386 <<
"Average,Standard Deviation,Time Unit,Time Factor,Input Samples" << std::endl;
388 throw std::ios_base::failure(
"Error writing summary report header to stream.");
389 for (std::uint64_t event_stats_i = 0; event_stats_i < m_event_stats.size(); ++event_stats_i)
390 if (m_event_stats[event_stats_i])
397 throw std::ios_base::failure(
"Output stream is in an invalid state.");
404 << hebench::Utilities::convertDoubleToStr(stats.
ops_per_sec) <<
","
416 throw std::ios_base::failure(
"Error writing summary row to stream.");
Extracts and maintains the timing report events of the same type.
std::uint32_t getID() const
ID of the event type.
const std::vector< double > & getWallEvents() const
Collection of contained wall-timed events of the same type extracted from the report.
void computeStats(ReportEventTypeStats &result) const
Computes statistics for this event type based on the contained events.
ReportEventTypeStats computeStats() const
Computes statistics for this event type based on the contained events.
EventType(const cpp::TimingReport &report, std::uint32_t event_id)
Constructs an event type from a report.
const std::vector< double > & getCPUEvents() const
Collection of contained CPU-timed events of the same type extracted from the report.
const std::string & getName() const
Name of the event type as per the report.
std::uint64_t getMainEventTypeStatsIndex() const
const std::string & getFooter() const
const ReportEventTypeStats & getEventTypeStats(std::uint64_t index) const
void generateCSV(std::ostream &os, char ch_prefix)
Generates complete CSV stats for this report.
const ReportEventTypeStats & getEventTypeStatsByID(std::uint32_t id) const
void generateSummaryCSV(std::ostream &os, char ch_prefix)
Generates summary CSV for this report.
const std::string & getHeader() const
const ReportEventTypeStats & getMainEventTypeStats() const
ReportStats(const cpp::TimingReport &report)
static void setTimingPrefix(TimingPrefixedSeconds &prefix, double seconds, char ch_prefix)
Converts the time in seconds to the specified time unit.
uint32_t getMainEventType() const
static double computeElapsedWallTime(const TimingReportEventC &event)
std::string getFooter() const
uint64_t getEventTypeCount() const
void getEvent(TimingReportEventC &p_event, uint64_t index) const
uint64_t getEventCount() const
std::string getHeader() const
std::string getEventTypeHeader(uint32_t event_type_id) const
static double computeElapsedCPUTime(const TimingReportEventC &event)
double wall_time_variance
std::string name
Event name.
int64_t time_interval_ratio_den
Denominator of timing scale ratio with respect to a unit.
double wall_time_ave_trim
uint64_t input_sample_count
Number of input samples used.
uint64_t input_sample_count
double cpu_time_variance_trim
void computeStats(StatisticsResult &result, const double *data, std::size_t count)
double wall_time_variance_trim
char symbol[MAX_SYMBOL_BUFFER_SIZE]
Symbol for the prefix.
uint32_t event_type_id
ID specifying the event type.
uint64_t input_sample_count
uint32_t event_id
ID specifying the event type.
double samples_per_unit_trim