HEBench
hebench_report.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 <cstring>
6 #include <fstream>
7 #include <limits>
8 #include <new>
9 #include <sstream>
10 #include <string>
11 
12 #include "hebench/modules/general/include/hebench_math_utils.h"
13 #include "hebench/modules/general/include/hebench_utilities.h"
14 #include "hebench_report.h"
15 #include "hebench_report_impl.h"
16 
17 namespace hebench {
18 namespace ReportGen {
19 
20 extern "C"
21 {
22 
24  {
25  TimingReportImpl *p_retval = nullptr;
26 
27  try
28  {
29  p_retval = new TimingReportImpl();
30  }
31  catch (...)
32  {
33  if (p_retval)
34  {
35  delete p_retval;
36  p_retval = nullptr;
37  } // end if
38  }
39 
40  return p_retval;
41  }
42 
43  void freeReport(void *p_report)
44  {
45  try
46  {
47  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
48  if (p)
49  delete p;
50  }
51  catch (...)
52  {
53  // do not throw in C
54  }
55  }
56 
57  int32_t setReportHeader(void *p_report, const char *new_header)
58  {
59  int32_t retval = 0;
60  try
61  {
62  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
63  if (!p)
64  throw std::invalid_argument("");
65 
66  p->setHeader(new_header ? new_header : "");
67 
68  retval = 1; // success
69  }
70  catch (...)
71  {
72  retval = 0;
73  }
74 
75  return retval;
76  }
77 
78  int32_t appendReportHeader(void *p_report, const char *new_header, int32_t new_line)
79  {
80  int32_t retval = 0;
81  try
82  {
83  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
84  if (!p)
85  throw std::invalid_argument("");
86 
87  p->appendHeader(new_header ? new_header : "", new_line != 0);
88 
89  retval = 1; // success
90  }
91  catch (...)
92  {
93  retval = 0;
94  }
95 
96  return retval;
97  }
98 
99  int32_t prependReportHeader(void *p_report, const char *new_header, int32_t new_line)
100  {
101  int32_t retval = 0;
102  try
103  {
104  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
105  if (!p)
106  throw std::invalid_argument("");
107 
108  p->prependHeader(new_header ? new_header : "", new_line != 0);
109 
110  retval = 1; // success
111  }
112  catch (...)
113  {
114  retval = 0;
115  }
116 
117  return retval;
118  }
119 
120  uint64_t getReportHeader(void *p_report, char *header, uint64_t size)
121  {
122  uint64_t retval = 0;
123  try
124  {
125  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
126  if (!p)
127  throw std::invalid_argument("");
128 
129  retval = hebench::Utilities::copyString(header, size, p->getHeader());
130  }
131  catch (...)
132  {
133  retval = 0;
134  }
135 
136  return retval;
137  }
138 
139  int32_t setReportFooter(void *p_report, const char *new_footer)
140  {
141  int32_t retval = 0;
142  try
143  {
144  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
145  if (!p)
146  throw std::invalid_argument("");
147 
148  p->setFooter(new_footer ? new_footer : "");
149 
150  retval = 1; // success
151  }
152  catch (...)
153  {
154  retval = 0;
155  }
156 
157  return retval;
158  }
159 
160  int32_t appendReportFooter(void *p_report, const char *new_footer, int32_t new_line)
161  {
162  int32_t retval = 0;
163  try
164  {
165  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
166  if (!p)
167  throw std::invalid_argument("");
168 
169  p->appendFooter(new_footer ? new_footer : "", new_line != 0);
170 
171  retval = 1; // success
172  }
173  catch (...)
174  {
175  retval = 0;
176  }
177 
178  return retval;
179  }
180 
181  int32_t prependReportFooter(void *p_report, const char *new_footer, int32_t new_line)
182  {
183  int32_t retval = 0;
184  try
185  {
186  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
187  if (!p)
188  throw std::invalid_argument("");
189 
190  p->prependFooter(new_footer ? new_footer : "", new_line != 0);
191 
192  retval = 1; // success
193  }
194  catch (...)
195  {
196  retval = 0;
197  }
198 
199  return retval;
200  }
201 
202  uint64_t getReportFooter(void *p_report, char *footer, uint64_t size)
203  {
204  uint64_t retval = 0;
205  try
206  {
207  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
208  if (!p)
209  throw std::invalid_argument("");
210 
211  retval = hebench::Utilities::copyString(footer, size, p->getFooter());
212  }
213  catch (...)
214  {
215  retval = 0;
216  }
217 
218  return retval;
219  }
220 
221  int32_t addEventType(void *p_report, uint32_t event_type_id, const char *event_type_header)
222  {
223  int32_t retval = 0;
224  try
225  {
226  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
227  if (!p)
228  throw std::invalid_argument("");
229 
230  p->newEventType(event_type_id, event_type_header ? event_type_header : "", false);
231 
232  retval = 1; // success
233  }
234  catch (...)
235  {
236  retval = 0;
237  }
238 
239  return retval;
240  }
241 
242  int32_t addMainEventType(void *p_report, uint32_t event_type_id, const char *event_type_header)
243  {
244  int32_t retval = 0;
245  try
246  {
247  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
248  if (!p)
249  throw std::invalid_argument("");
250 
251  p->newEventType(event_type_id, event_type_header ? event_type_header : "", true);
252 
253  retval = 1; // success
254  }
255  catch (...)
256  {
257  retval = 0;
258  }
259 
260  return retval;
261  }
262 
263  int32_t hasEventType(void *p_report, uint32_t event_type_id)
264  {
265  int32_t retval = 0;
266  try
267  {
268  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
269  if (!p)
270  throw std::invalid_argument("");
271 
272  retval = p->getEventTypes().count(event_type_id) > 0 ? 1 : 0;
273  }
274  catch (...)
275  {
276  retval = -1;
277  }
278 
279  return retval;
280  }
281 
282  uint64_t getEventTypeHeader(void *p_report, uint32_t event_type_id, char *event_type_header, uint64_t size)
283  {
284  uint64_t retval = 0;
285  try
286  {
287  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
288  if (!p)
289  throw std::invalid_argument("");
290 
291  const auto &map_event_types = p->getEventTypes();
292  if (map_event_types.count(event_type_id) <= 0)
293  throw std::invalid_argument("ID not found.");
294 
295  retval = hebench::Utilities::copyString(event_type_header, size, map_event_types.at(event_type_id));
296  }
297  catch (...)
298  {
299  retval = 0;
300  }
301 
302  return retval;
303  }
304 
305  uint64_t getEventTypeCount(void *p_report)
306  {
307  uint64_t retval = 0;
308  try
309  {
310  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
311  if (!p)
312  throw std::invalid_argument("");
313 
314  retval = p->getEventTypes().size();
315  }
316  catch (...)
317  {
318  retval = 0;
319  }
320 
321  return retval;
322  }
323 
324  uint32_t getEventType(void *p_report, uint64_t index)
325  {
326  uint32_t retval = std::numeric_limits<uint32_t>::max();
327  try
328  {
329  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
330  if (!p || p->getEventTypeIDs().size() <= index)
331  throw std::invalid_argument("");
332 
333  retval = p->getEventTypeIDs().at(index);
334  }
335  catch (...)
336  {
337  retval = std::numeric_limits<uint32_t>::max();
338  }
339 
340  return retval;
341  }
342 
343  int32_t getMainEventType(void *p_report, uint32_t *p_event_type_id)
344  {
345  int32_t retval = 0;
346  try
347  {
348  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
349  if (!p || !p_event_type_id)
350  throw std::invalid_argument("");
351 
352  if (p->getMainEventID() != std::numeric_limits<uint32_t>::max())
353  {
354  *p_event_type_id = p->getMainEventID();
355  retval = 1;
356  } // end if
357  }
358  catch (...)
359  {
360  retval = 0;
361  }
362 
363  return retval;
364  }
365 
366  int32_t addEvent(void *p_report, const TimingReportEventC *p_event)
367  {
368  int32_t retval = 0;
369  try
370  {
371  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
372  if (!p || !p_event)
373  throw std::invalid_argument("");
374 
375  std::shared_ptr<TimingReportEventC> sp_event = std::make_shared<TimingReportEventC>();
376  if (!sp_event)
377  throw std::bad_alloc();
378  *sp_event = *p_event;
379  p->newEvent(sp_event);
380 
381  retval = 1;
382  }
383  catch (...)
384  {
385  retval = 0;
386  }
387 
388  return retval;
389  }
390 
391  int32_t getEvent(void *p_report, TimingReportEventC *p_event, uint64_t index)
392  {
393  int32_t retval = 0;
394  try
395  {
396  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
397  if (!p || !p_event || index >= p->getEvents().size())
398  throw std::invalid_argument("");
399 
400  *p_event = *p->getEvents()[index];
401 
402  retval = 1;
403  }
404  catch (...)
405  {
406  retval = 0;
407  }
408 
409  return retval;
410  }
411 
412  uint64_t getEventCount(void *p_report)
413  {
414  uint64_t retval = 0;
415  try
416  {
417  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
418  if (!p)
419  throw std::invalid_argument("");
420 
421  retval = p->getEvents().size();
422  }
423  catch (...)
424  {
425  retval = 0;
426  }
427 
428  return retval;
429  }
430 
431  uint64_t getEventCapacity(void *p_report)
432  {
433  uint64_t retval = 0;
434  try
435  {
436  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
437  if (!p)
438  throw std::invalid_argument("");
439 
440  retval = p->getEvents().capacity();
441  }
442  catch (...)
443  {
444  retval = 0;
445  }
446 
447  return retval;
448  }
449 
450  int32_t setEventCapacity(void *p_report, uint64_t new_capacity)
451  {
452  int32_t retval = 0;
453  try
454  {
455  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
456  if (!p)
457  throw std::invalid_argument("");
458 
459  p->reserveCapacityForEvents(new_capacity);
460 
461  retval = 1;
462  }
463  catch (...)
464  {
465  retval = 0;
466  }
467 
468  return retval;
469  }
470 
471  int32_t clearEvents(void *p_report)
472  {
473  int32_t retval = 0;
474  try
475  {
476  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
477  if (!p)
478  throw std::invalid_argument("");
479 
480  p->clear();
481 
482  retval = 1;
483  }
484  catch (...)
485  {
486  retval = 0;
487  }
488 
489  return retval;
490  }
491 
492  int32_t save2CSV(void *p_report, const char *filename)
493  {
494  int32_t retval = 0;
495  try
496  {
497  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
498  if (!p || !filename || filename[0] == '\0')
499  throw std::invalid_argument("");
500 
501  std::ofstream fnum;
502  fnum.open(filename, std::ios_base::out | std::ios_base::trunc);
503  if (!fnum.is_open())
504  throw std::ios_base::failure("Error opening file");
505 
506  p->convert2CSV(fnum);
507 
508  retval = 1;
509  }
510  catch (...)
511  {
512  retval = 0;
513  }
514 
515  return retval;
516  }
517 
518  int32_t convert2CSV(void *p_report, char **pp_csv_content)
519  {
520  int32_t retval = 0;
521  char *p_csv_content = nullptr;
522  try
523  {
524  TimingReportImpl *p = reinterpret_cast<TimingReportImpl *>(p_report);
525  if (!p || !pp_csv_content)
526  throw std::invalid_argument("");
527 
528  std::stringstream ss;
529  std::string s_csv_content;
530 
531  p->convert2CSV(ss);
532  s_csv_content = ss.str();
533  ss = std::stringstream();
534 
535  p_csv_content = new char[s_csv_content.length() + 1];
536  if (!p_csv_content)
537  throw std::bad_alloc();
538  std::strcpy(p_csv_content, s_csv_content.c_str());
539  *pp_csv_content = p_csv_content;
540 
541  retval = 1;
542  }
543  catch (...)
544  {
545  if (p_csv_content)
546  delete[] p_csv_content;
547  retval = 0;
548  }
549 
550  return retval;
551  }
552 
553  void freeCSVContent(char *p_csv_content)
554  {
555  if (p_csv_content)
556  delete[] p_csv_content;
557  }
558 
559  void *loadReportFromCSV(const char *p_csv_content, char error_description[MAX_DESCRIPTION_BUFFER_SIZE])
560  {
561  TimingReportImpl *p_retval = nullptr;
562  try
563  {
564  p_retval = new TimingReportImpl(TimingReportImpl::loadCSV(p_csv_content));
565  }
566  catch (std::exception &ex)
567  {
568  if (p_retval)
569  {
570  delete p_retval;
571  p_retval = nullptr;
572  }
573  hebench::Utilities::copyString(error_description, MAX_DESCRIPTION_BUFFER_SIZE, ex.what());
574  }
575  catch (...)
576  {
577  if (p_retval)
578  {
579  delete p_retval;
580  p_retval = nullptr;
581  }
582  hebench::Utilities::copyString(error_description, MAX_DESCRIPTION_BUFFER_SIZE, "Unknown error.");
583  }
584  return p_retval;
585  }
586 
587  void *loadReportFromCSVFile(const char *filename, char error_description[MAX_DESCRIPTION_BUFFER_SIZE])
588  {
589  TimingReportImpl *p_retval = nullptr;
590  try
591  {
592  std::ifstream fnum;
593  if (!filename || filename[0] == '\0')
594  throw std::invalid_argument("Invalid empty filename.");
595  fnum.open(filename, std::ios_base::in);
596  if (!fnum.is_open())
597  throw std::ios_base::failure("Could not open file \"" + std::string(filename) + "\"");
598  p_retval = new TimingReportImpl(TimingReportImpl::loadCSV(fnum));
599  }
600  catch (std::exception &ex)
601  {
602  if (p_retval)
603  {
604  delete p_retval;
605  p_retval = nullptr;
606  }
607  hebench::Utilities::copyString(error_description, MAX_DESCRIPTION_BUFFER_SIZE, ex.what());
608  }
609  catch (...)
610  {
611  if (p_retval)
612  {
613  delete p_retval;
614  p_retval = nullptr;
615  }
616  hebench::Utilities::copyString(error_description, MAX_DESCRIPTION_BUFFER_SIZE, "Unknown error.");
617  }
618  return p_retval;
619  }
620 }
621 
622 int32_t setTimingPrefix(TimingPrefixedSeconds *p_prefix, double seconds, char prefix)
623 {
624  int32_t retval = 1;
625 
626  try
627  {
628  if (!retval)
629  throw std::invalid_argument("p_prefix");
630  TimingReportImpl::setTimingPrefix(*p_prefix, seconds, prefix);
631  }
632  catch (...)
633  {
634  retval = 0;
635  }
636 
637  return retval;
638 }
639 
640 int32_t computeTimingPrefix(TimingPrefixedSeconds *p_prefix, double seconds)
641 {
642  int32_t retval = 1;
643 
644  try
645  {
646  if (!retval)
647  throw std::invalid_argument("p_prefix");
648  TimingReportImpl::computeTimingPrefix(*p_prefix, seconds);
649  }
650  catch (...)
651  {
652  retval = 0;
653  }
654 
655  return retval;
656 }
657 
658 } // namespace ReportGen
659 } // namespace hebench
void appendHeader(const std::string &header, bool new_line)
void prependHeader(const std::string &header, bool new_line)
std::ostream & convert2CSV(std::ostream &os) const
static void setTimingPrefix(TimingPrefixedSeconds &prefix, double seconds, char ch_prefix)
void setHeader(const std::string &header)
void setFooter(const std::string &footer)
const std::vector< std::uint32_t > & getEventTypeIDs() const
const std::unordered_map< std::uint32_t, std::string > & getEventTypes() const
void prependFooter(const std::string &footer, bool new_line)
const std::vector< std::shared_ptr< TimingReportEventC > > & getEvents() const
void appendFooter(const std::string &footer, bool new_line)
const std::string & getHeader() const
void newEventType(std::uint32_t set_id, const std::string &set_header, bool is_main_event=false)
void reserveCapacityForEvents(std::size_t new_capacity)
static void computeTimingPrefix(TimingPrefixedSeconds &prefix, double seconds)
const std::string & getFooter() const
static TimingReportImpl loadCSV(std::istream &is)
void newEvent(std::shared_ptr< TimingReportEventC > p_event, const std::string &set_header=std::string())
#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)
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.
std::uint64_t copyString(char *dst, std::uint64_t size, const std::string &src)
Copies a C++ string object into a C-style string.
Definition: utilities.cpp:13