HEBench
hebench_report_cpp.cpp
Go to the documentation of this file.
1 
2 // Copyright (C) 2021 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include <limits>
6 #include <memory>
7 #include <sstream>
8 #include <vector>
9 
10 #include "hebench_report.h"
11 #include "hebench_report_cpp.h"
12 
13 #define INTERNAL_LOG_MSG(message) prepareLogMessage((message), \
14  __func__, m_private_class_name, \
15  __FILE__, __LINE__)
16 
17 std::string prepareLogMessage(const char *message,
18  const char *function, const char *container,
19  const char *filename, int line_no)
20 {
21  // prepare log message
22  std::stringstream ss_retval;
23 
24  bool bheader =
25  (filename && filename[0] != '\0') || (container && container[0] != '\0') || (function && function[0] != '\0') || (line_no >= 0);
26  if (filename && filename[0] != '\0')
27  ss_retval << filename;
28  if (line_no >= 0)
29  ss_retval << ":" << line_no;
30  if (container && container[0] != '\0')
31  ss_retval << ":" << container;
32  if (function && function[0] != '\0')
33  ss_retval << "::" << function << "()";
34  if (bheader && message && message[0])
35  ss_retval << ": ";
36  if (message && message[0])
37  ss_retval << message;
38 
39  return ss_retval.str();
40 }
41 
42 std::string prepareLogMessage(const std::string &message,
43  const std::string &function, const std::string &container,
44  const std::string &filename, int line_no)
45 {
46  return prepareLogMessage(message.c_str(),
47  function.c_str(), container.c_str(),
48  filename.c_str(), line_no);
49 }
50 
51 namespace hebench {
52 namespace ReportGen {
53 namespace cpp {
54 
55 //---------------------------
56 // class TimingPrefixUtility
57 //---------------------------
58 
59 void TimingPrefixUtility::setTimingPrefix(TimingPrefixedSeconds &prefix, double seconds, char ch_prefix)
60 {
61  hebench::ReportGen::setTimingPrefix(&prefix, seconds, ch_prefix);
62 }
63 
65 {
67 }
68 
69 //--------------------
70 // class TimingReport
71 //--------------------
72 
73 TimingReport::TimingReport(const std::string &header) :
74  m_lib_handle(nullptr)
75 {
76  m_lib_handle = allocateReport();
77  if (!m_lib_handle)
78  throw std::runtime_error(INTERNAL_LOG_MSG("Error allocating report."));
79  if (!header.empty()
80  && !setReportHeader(m_lib_handle, header.c_str()))
81  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new header."));
82 }
83 
85 {
86  m_lib_handle = src.m_lib_handle;
87  src.m_lib_handle = nullptr;
88 }
89 
91 {
92  if (&src != this)
93  {
94  if (m_lib_handle)
95  freeReport(m_lib_handle);
96  m_lib_handle = src.m_lib_handle;
97  src.m_lib_handle = nullptr;
98  } // end if
99  return *this;
100 }
101 
103 {
104  if (m_lib_handle)
105  freeReport(m_lib_handle);
106 }
107 
108 void TimingReport::setHeader(const std::string &new_header)
109 {
110  if (!setReportHeader(m_lib_handle, new_header.c_str()))
111  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new header."));
112 }
113 
114 void TimingReport::appendHeader(const std::string &new_header, bool new_line)
115 {
116  if (!appendReportHeader(m_lib_handle, new_header.c_str(), new_line ? 1 : 0))
117  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new header."));
118 }
119 
120 void TimingReport::prependHeader(const std::string &new_header, bool new_line)
121 {
122  if (!prependReportHeader(m_lib_handle, new_header.c_str(), new_line ? 1 : 0))
123  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new header."));
124 }
125 
126 std::string TimingReport::getHeader() const
127 {
128  std::vector<char> ch_retval;
129  std::uint64_t n = getReportHeader(m_lib_handle, nullptr, 0);
130  if (n <= 0)
131  throw std::runtime_error(INTERNAL_LOG_MSG("Unexpected error retrieving report header."));
132  ch_retval.resize(n);
133  if (getReportHeader(m_lib_handle, ch_retval.data(), ch_retval.size()) <= 0)
134  throw std::runtime_error(INTERNAL_LOG_MSG("Unexpected error retrieving report header."));
135  return ch_retval.data();
136 }
137 
138 void TimingReport::setFooter(const std::string &new_footer)
139 {
140  if (!setReportFooter(m_lib_handle, new_footer.c_str()))
141  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new footer."));
142 }
143 
144 void TimingReport::appendFooter(const std::string &new_footer, bool new_line)
145 {
146  if (!appendReportFooter(m_lib_handle, new_footer.c_str(), new_line ? 1 : 0))
147  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new footer."));
148 }
149 
150 void TimingReport::prependFooter(const std::string &new_footer, bool new_line)
151 {
152  if (!prependReportFooter(m_lib_handle, new_footer.c_str(), new_line ? 1 : 0))
153  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new footer."));
154 }
155 
156 std::string TimingReport::getFooter() const
157 {
158  std::vector<char> ch_retval;
159  std::uint64_t n = getReportFooter(m_lib_handle, nullptr, 0);
160  if (n <= 0)
161  throw std::runtime_error(INTERNAL_LOG_MSG("Unexpected error retrieving report footer."));
162  ch_retval.resize(n);
163  if (getReportFooter(m_lib_handle, ch_retval.data(), ch_retval.size()) <= 0)
164  throw std::runtime_error(INTERNAL_LOG_MSG("Unexpected error retrieving report footer."));
165  return ch_retval.data();
166 }
167 
168 void TimingReport::addEventType(uint32_t event_type_id, const std::string &event_type_header, bool is_main_event)
169 {
170  bool retval = (is_main_event ?
171  hebench::ReportGen::addMainEventType(m_lib_handle, event_type_id, event_type_header.c_str()) != 0 :
172  hebench::ReportGen::addEventType(m_lib_handle, event_type_id, event_type_header.c_str()) != 0);
173  if (!retval)
174  {
175  std::string err_msg = (is_main_event ?
176  "Error adding main event type." :
177  "Error adding event.");
178  throw std::runtime_error(INTERNAL_LOG_MSG(err_msg));
179  } // end if
180 }
181 
182 bool TimingReport::hasEventType(uint32_t event_type_id) const
183 {
184  int32_t retval = hebench::ReportGen::hasEventType(m_lib_handle, event_type_id);
185 
186  if (retval < 0)
187  throw std::runtime_error(INTERNAL_LOG_MSG("Error querying for event type."));
188 
189  return retval > 0;
190 }
191 
192 std::string TimingReport::getEventTypeHeader(uint32_t event_type_id) const
193 {
194  std::vector<char> ch_retval;
195  std::uint64_t n = hebench::ReportGen::getEventTypeHeader(m_lib_handle, event_type_id, nullptr, 0);
196  if (n <= 0)
197  throw std::runtime_error(INTERNAL_LOG_MSG("Unexpected error retrieving event type header."));
198  ch_retval.resize(n);
199  if (hebench::ReportGen::getEventTypeHeader(m_lib_handle, event_type_id, ch_retval.data(), ch_retval.size()) <= 0)
200  throw std::runtime_error(INTERNAL_LOG_MSG("Unexpected error retrieving event type header."));
201  return ch_retval.data();
202 }
203 
205 {
206  return hebench::ReportGen::getEventTypeCount(m_lib_handle);
207 }
208 
209 uint32_t TimingReport::getEventType(uint64_t index) const
210 {
211  uint32_t retval = hebench::ReportGen::getEventType(m_lib_handle, index);
212  if (retval == std::numeric_limits<decltype(retval)>::max())
213  throw std::runtime_error(INTERNAL_LOG_MSG("Error retrieving event type ID for event type index " + std::to_string(index) + "."));
214  return retval;
215 }
216 
218 {
219  uint32_t retval;
220 
221  if (!hebench::ReportGen::getMainEventType(m_lib_handle, &retval))
222  throw std::runtime_error(INTERNAL_LOG_MSG("Error retrieving main event type."));
223 
224  return retval;
225 }
226 
228 {
229  if (!hebench::ReportGen::addEvent(m_lib_handle, &p_event))
230  throw std::runtime_error(INTERNAL_LOG_MSG("Error adding new event to report."));
231 }
232 
234 {
235  if (!hebench::ReportGen::getEvent(m_lib_handle, &p_event, index))
236  throw std::runtime_error(INTERNAL_LOG_MSG("Error retrieving event from report."));
237 }
238 
240 {
241  return hebench::ReportGen::getEventCount(m_lib_handle);
242 }
243 
245 {
246  return hebench::ReportGen::getEventCapacity(m_lib_handle);
247 }
248 
249 void TimingReport::setEventCapacity(uint64_t new_capacity)
250 {
251  if (!hebench::ReportGen::setEventCapacity(m_lib_handle, new_capacity))
252  throw std::runtime_error(INTERNAL_LOG_MSG("Error setting new capacity for events."));
253 }
254 
256 {
257  if (!hebench::ReportGen::clearEvents(m_lib_handle))
258  throw std::runtime_error(INTERNAL_LOG_MSG("Error clearning up events."));
259 }
260 
261 void TimingReport::save2CSV(const std::string &filename)
262 {
263  if (!hebench::ReportGen::save2CSV(m_lib_handle, filename.c_str()))
264  throw std::runtime_error(INTERNAL_LOG_MSG("Error saving report to CSV file."));
265 }
266 
268 {
269  char *p_tmp = nullptr;
270  if (!hebench::ReportGen::convert2CSV(m_lib_handle, &p_tmp))
271  throw std::runtime_error(INTERNAL_LOG_MSG("Error converting report to CSV format."));
272  std::shared_ptr<char> sp_csv_content = std::shared_ptr<char>(p_tmp,
273  [](char *p) {
274  if (p)
276  });
277  std::string retval = sp_csv_content.get();
278  return retval;
279 }
280 
281 TimingReport TimingReport::loadReportFromCSV(const std::string &s_csv_content)
282 {
283  TimingReport retval;
284 
285  char error_description[MAX_DESCRIPTION_BUFFER_SIZE];
286  retval.m_lib_handle = hebench::ReportGen::loadReportFromCSV(s_csv_content.c_str(), error_description);
287  if (!retval.m_lib_handle)
288  throw std::runtime_error(INTERNAL_LOG_MSG(error_description));
289 
290  return retval;
291 }
292 
294 {
295  TimingReport retval;
296 
297  char error_description[MAX_DESCRIPTION_BUFFER_SIZE];
298  retval.m_lib_handle = hebench::ReportGen::loadReportFromCSVFile(filename.c_str(), error_description);
299  if (!retval.m_lib_handle)
300  throw std::runtime_error(INTERNAL_LOG_MSG(error_description));
301 
302  return retval;
303 }
304 
305 } // namespace cpp
306 } // namespace ReportGen
307 } // namespace hebench
static void setTimingPrefix(TimingPrefixedSeconds &prefix, double seconds, char ch_prefix)
Converts the time in seconds to the specified time unit.
static void computeTimingPrefix(TimingPrefixedSeconds &prefix, double seconds)
Given a time interval in seconds, computes the timing prefix.
TimingReport & operator=(TimingReport &&)
bool hasEventType(uint32_t event_type_id) const
static TimingReport loadReportFromCSVFile(const std::string &filename)
void save2CSV(const std::string &filename)
static TimingReport loadReportFromCSV(const std::string &s_csv_content)
void setFooter(const std::string &new_footer)
void addEvent(const TimingReportEventC &p_event)
void prependFooter(const std::string &new_header, bool new_line=true)
void setEventCapacity(uint64_t new_capacity)
void getEvent(TimingReportEventC &p_event, uint64_t index) const
void prependHeader(const std::string &new_header, bool new_line=true)
void addEventType(uint32_t event_type_id, const std::string &event_type_header, bool is_main_event=false)
Adds a new event type to the types of events.
std::string getEventTypeHeader(uint32_t event_type_id) const
void appendFooter(const std::string &new_header, bool new_line=true)
uint32_t getEventType(uint64_t index) const
Retrieve an event type ID.
TimingReport(const TimingReport &)=delete
void setHeader(const std::string &new_header)
void appendHeader(const std::string &new_header, bool new_line=true)
#define INTERNAL_LOG_MSG(message)
std::string prepareLogMessage(const char *message, const char *function, const char *container, const char *filename, int line_no)
#define MAX_DESCRIPTION_BUFFER_SIZE
uint32_t getEventType(void *p_report, uint64_t index)
Retrieve an event type ID.
void freeCSVContent(char *p_csv_content)
Releases resources allocated by functions that generate CSV formatted reports from a timing report.
int32_t setReportFooter(void *p_report, const char *new_footer)
int32_t addMainEventType(void *p_report, uint32_t event_type_id, const char *event_type_header)
Adds an event type and marks it as the main event.
void * loadReportFromCSVFile(const char *filename, char error_description[MAX_DESCRIPTION_BUFFER_SIZE])
int32_t appendReportHeader(void *p_report, const char *new_header, int32_t new_line)
Appends text to existing header.
int32_t prependReportHeader(void *p_report, const char *new_header, int32_t new_line)
Prepends text to existing header.
uint64_t getReportHeader(void *p_report, char *header, uint64_t size)
std::string to_string(const std::string_view &s)
int32_t getMainEventType(void *p_report, uint32_t *p_event_type_id)
getMainEventType
int32_t hasEventType(void *p_report, uint32_t event_type_id)
hasEventType
int32_t addEvent(void *p_report, const TimingReportEventC *p_event)
addEvent
uint64_t getEventCapacity(void *p_report)
int32_t save2CSV(void *p_report, const char *filename)
uint64_t getEventTypeCount(void *p_report)
void freeReport(void *p_report)
int32_t addEventType(void *p_report, uint32_t event_type_id, const char *event_type_header)
addEventType
uint64_t getReportFooter(void *p_report, char *footer, uint64_t size)
void * loadReportFromCSV(const char *p_csv_content, char error_description[MAX_DESCRIPTION_BUFFER_SIZE])
int32_t setTimingPrefix(TimingPrefixedSeconds *p_prefix, double seconds, char prefix)
Computes the value for the time unit based on a specified prefix.
int32_t setReportHeader(void *p_report, const char *new_header)
int32_t appendReportFooter(void *p_report, const char *new_footer, int32_t new_line)
Appends text to existing footer.
uint64_t getEventTypeHeader(void *p_report, uint32_t event_type_id, char *event_type_header, uint64_t size)
uint64_t getEventCount(void *p_report)
int32_t getEvent(void *p_report, TimingReportEventC *p_event, uint64_t index)
getEvent
int32_t convert2CSV(void *p_report, char **pp_csv_content)
convert2CSV
int32_t setEventCapacity(void *p_report, uint64_t new_capacity)
setEventCapacity
int32_t clearEvents(void *p_report)
int32_t prependReportFooter(void *p_report, const char *new_footer, int32_t new_line)
Prepends text to existing footer.
int32_t computeTimingPrefix(TimingPrefixedSeconds *p_prefix, double seconds)
Retrieves the prefix for the time unit.