Ocean
HighPerformanceTimer.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_BASE_HIGH_PERFORMANCE_TIMER_H
9 #define META_OCEAN_BASE_HIGH_PERFORMANCE_TIMER_H
10 
11 #include "ocean/base/Base.h"
12 #include "ocean/base/Messenger.h"
13 #include "ocean/base/Singleton.h"
14 #include "ocean/base/Value.h"
15 
16 #include <cfloat>
17 #include <numeric>
18 
19 namespace Ocean
20 {
21 
22 /**
23  * This class implements a high performance timer.
24  * Use this timer to measure time durations with high accuracy.<br>
25  * The measurement can be very helpful to detect performance bottlenecks.<br>
26  * Use the HighPerformanceTimer::precision() to retrieve the possible accuracy of this high performance timer.<br>
27  * The implementation is platform dependent.
28  * @ingroup base
29  */
30 class OCEAN_BASE_EXPORT HighPerformanceTimer
31 {
32  public:
33 
34  /**
35  * Definition of CPU ticks.
36  */
37  typedef int64_t Ticks;
38 
39  public:
40 
41  /**
42  * Creates a new timer and starts the time measurement.
43  */
45 
46  /**
47  * (Re-)starts the time measurement.
48  */
49  inline void start();
50 
51  /**
52  * Returns the measured time since the timer has been started in seconds.
53  * @return Measured seconds
54  */
55  double seconds() const;
56 
57  /**
58  * Returns the measured time since the timer has been started in milliseconds.
59  * @return Measured milliseconds
60  */
61  double mseconds() const;
62 
63  /**
64  * Returns the measured time since the timer has been started in microseconds.
65  * @return Measured microseconds
66  */
67  double yseconds() const;
68 
69  /**
70  * Returns the measured time since the timer has been started in nanoseconds.
71  * @return Measured nanoseconds
72  */
73  double nseconds() const;
74 
75  /**
76  * Returns the precision of the timer.
77  * @return Countable ticks per seconds
78  */
79  static Ticks precision();
80 
81  /**
82  * Returns the recent CPU ticks.
83  * @return Recent CPU ticks
84  */
85  static Ticks ticks();
86 
87  /**
88  * Converts a given CPU tick into seconds regarding the resolution of the timer.
89  * @param ticks The ticks to convert
90  * @return The Number of seconds matching with the given CPU ticks
91  */
92  static inline double ticks2seconds(const Ticks ticks);
93 
94  protected:
95 
96  /**
97  * Returns the resolution of the timer in ticks per second
98  * @return Ticks per second
99  */
101 
102  protected:
103 
104  /// The number of CPU ticks when starting the timer.
105  Ticks ticksStart_ = Ticks(0);
106 };
107 
108 #ifdef OCEAN_USE_EXTERNAL_PRIVACY_CONFIRM_TICKS
109 
110 /**
111  * Returns the recent CPU ticks which will contain a random offset which is constant through the execution of the process.
112  * @return Recent CPU ticks with random offset
113  */
115 
116 #endif // OCEAN_USE_EXTERNAL_PRIVACY_CONFIRM_TICKS
117 
118 /**
119  * This class implements a simple module gathering high performance timer statistics.
120  * The class is not thread-safe.
121  * @ingroup base
122  */
123 class OCEAN_BASE_EXPORT HighPerformanceStatistic
124 {
125  public:
126 
127  /**
128  * Definition of a vector storing performance measurements.
129  */
130  typedef std::vector<double> Measurements;
131 
132  /**
133  * This class defines a scoped high performance statistic module.
134  * Use this scoped module in combination with a high performance statistic object to add a new performance measurement during the existence of this module.
135  * @ingroup base
136  */
137  class OCEAN_BASE_EXPORT ScopedStatistic
138  {
139  public:
140 
141  /**
142  * Creates a new scoped statistic object and starts a new measurement.
143  * @param performance High performance statistic object receiving the scoped measurement.
144  */
145  inline explicit ScopedStatistic(HighPerformanceStatistic& performance);
146 
147  /**
148  * Destructs a scoped statistic object and stops the measurement.
149  */
150  inline ~ScopedStatistic();
151 
152  /**
153  * Explicitly releases the object and does not wait until the scope ends.
154  */
155  inline void release();
156 
157  private:
158 
159  /**
160  * Deleted copy constructor.
161  */
163 
164  /**
165  * Deleted copy operator.
166  * @return Reference to this object
167  */
169 
170  private:
171 
172  /// High performance statistic object receiving the measurement value.
173  HighPerformanceStatistic* statisticPerformance;
174  };
175 
176  public:
177 
178  /**
179  * Creates a new statistic module.
180  */
182 
183  /**
184  * Returns the first measurement time in seconds.
185  * @return First measurement time, in [sec]
186  */
187  inline double first() const;
188 
189  /**
190  * Returns the first measurement time in milliseconds.
191  * @return First measurement time, in [ms]
192  */
193  inline double firstMseconds() const;
194 
195  /**
196  * Returns the second measurement time in seconds.
197  * @return Second measurement time, in [sec]
198  */
199  inline double second() const;
200 
201  /**
202  * Returns the second measurement time in milliseconds.
203  * @return Second measurement time, in [ms]
204  */
205  inline double secondMseconds() const;
206 
207  /**
208  * Returns the best measurement time in seconds.
209  * @return Best measurement time, in [sec]
210  */
211  inline double best() const;
212 
213  /**
214  * Returns the best measurement time in milliseconds.
215  * @return Best measurement time, in [ms]
216  */
217  inline double bestMseconds() const;
218 
219  /**
220  * Returns the worst measurement time in seconds.
221  * @return Worst measurement time, in [sec]
222  */
223  inline double worst() const;
224 
225  /**
226  * Returns the worst measurement time in milliseconds.
227  * @return Worst measurement time, in [ms]
228  */
229  inline double worstMseconds() const;
230 
231  /**
232  * Returns the last measurement time in seconds.
233  * @return Last measurement time, in [sec]
234  */
235  inline double last() const;
236 
237  /**
238  * Returns the last (most recent measurement time in milliseconds.
239  * @return Last measurement time, in [ms]
240  */
241  inline double lastMseconds() const;
242 
243  /**
244  * Returns the average measurement time in seconds.
245  * @return Average measurement time, in [sec]
246  */
247  double average() const;
248 
249  /**
250  * Returns the average measurement time in milliseconds.
251  * @return Average measurement time, in [ms]
252  */
253  inline double averageMseconds() const;
254 
255  /**
256  * Returns the average number of CPU cycles needed for one operation.
257  * @param operations The number of operation that has been invoked during each measurement, with range [1, infinity)
258  * @param clockRate The number of clock cycles per second of the CPU, e.g., 3.8GHz, with range [1, infinity)
259  * @return The average number of CPU cycles needed, with range (0, infinity), -1 if no valid measurement exists
260  */
261  inline double averageCyclesPerOperation(const double operations, const double clockRate = 3800000000.0) const;
262 
263  /**
264  * Returns the median measurement time in seconds.
265  * @return Median measurement time, in [sec]
266  */
267  double median() const;
268 
269  /**
270  * Returns the median measurement time in milliseconds.
271  * @return Median measurement time, in [ms]
272  */
273  double medianMseconds() const;
274 
275  /**
276  * Returns a specific percentile (e.g., P50 = median, P90, P95, etc.) measurement time in seconds.
277  * @param value The percentile to be returned, with range [0, 1]
278  * @return The measurement for the specified percentile, in seconds
279  */
280  double percentile(double value) const;
281 
282  /**
283  * Returns a specific percentile (e.g., P50 = median, P90, P95, etc.) measurement time in milliseconds.
284  * @param value The percentile to be returned, with range [0, 1]
285  * @return The measurement for the specified percentile, in milliseconds
286  */
287  double percentileMseconds(double value) const;
288 
289  /**
290  * Returns the total measurement time in seconds.
291  * @return Total measurement time, in [sec]
292  */
293  inline double total() const;
294 
295  /**
296  * Returns the total measurement time in milliseconds.
297  * @return Total measurement time, in [ms]
298  */
299  inline double totalMseconds() const;
300 
301  /**
302  * Returns the current (still) running measurement time in seconds.
303  * @return Current still running measurement time, in [sec]
304  */
305  inline double running() const;
306 
307  /**
308  * Returns the current (still) running measurement time in milliseconds.
309  * @return Current still running measurement time, in [ms]
310  */
311  inline double runningMseconds() const;
312 
313  /**
314  * Returns the number of measurements.
315  * @return Measurement numbers
316  */
317  inline size_t measurements() const;
318 
319  /**
320  * Returns whether currently a measurement is running.
321  * @return True, if so
322  */
323  inline bool isRunning() const;
324 
325  /**
326  * Starts a new measurement.
327  */
328  void start();
329 
330  /**
331  * Starts a new measurement if the given value is True, otherwise nothing happens.
332  * @param value True; to start a new measurement; False, to ignore this call
333  */
334  void startIf(const bool value);
335 
336  /**
337  * Stops a measurement.
338  */
339  void stop();
340 
341  /**
342  * Stops a measurement.
343  * @param value True; to stop the measurement; False, to ignore this call
344  */
345  void stopIf(const bool value);
346 
347  /**
348  * Skips a started measurement.
349  * The measurement will not be voted.
350  */
351  void skip();
352 
353  /**
354  * Skips a started measurement.
355  * The measurement will not be voted.
356  * @param value True; to skip the measurement; False, to ignore this call
357  */
358  void skipIf(const bool value);
359 
360  /**
361  * Resets all gathered statistics.
362  */
363  void reset();
364 
365  /**
366  * Returns a string with the relevant performance information of this statistic object.
367  * @param precision The number of decimal places displayed, with range [1, infinity)
368  * @return The resulting string
369  */
370  std::string toString(const unsigned int precision = 2u) const;
371 
372  /**
373  * Returns whether at least one measurement has been done.
374  * @return True, if so
375  */
376  explicit inline operator bool() const;
377 
378  /**
379  * Adds measurements from another object to this statistic object.
380  * @param right The statistic object of which the measurements will be added to this object
381  * @return Reference to this object
382  */
384 
385  private:
386 
387  /// High performance timer.
389 
390  /// The individual measurements in order as measured.
392 
393  /// Best measurement time in seconds.
394  double best_ = DBL_MAX;
395 
396  /// Worst measurement time in seconds.
397  double worst_ = -DBL_MAX;
398 
399  /// Entire measurement time in seconds.
400  double total_ = 0.0;
401 
402  /// State determining whether one measurement is active currently.
403  bool started_ = false;
404 };
405 
406 /**
407  * The HighPerformanceBenchmark object allows to benchmark algorithms with individual categories.
408  * Benchmarking needs to be started before it can be used.<br>
409  * The class is thread-safe.
410  * This class creates flat and/or hierarchical reports. In the case of the former, the categories are sorted by their CPU time. For hierarchical
411  * reports, the category names can be expanded using a delimiter, for example `Foo::Bar` where `Bar` is a sub-category of `Foo`. In this report the
412  * top-level categories (like `Foo`) will be sorted by their total CPU time which is accumulated over all of their sub-categories (like `Foo::Bar`).
413  *
414  * Usage Example:
415  * <pre>
416  * void SomeClass::computeSomething(...)
417  * {
418  * HighPerformanceBenchmark::ScopedCategory scopedBenchmark("AlgorithmName");
419  * function0();
420  * function1();
421  * ...
422  * }
423  *
424  * void SomeClass::function0(...)
425  * {
426  * HighPerformanceBenchmark::ScopedCategory scopedBenchmark("AlgorithmName::Function0");
427  * ...
428  * }
429  *
430  * void SomeClass::function1(...)
431  * {
432  * HighPerformanceBenchmark::ScopedCategory scopedBenchmark("AlgorithmName::Function1");
433  * utilityFunction0();
434  * ...
435  * }
436  *
437  * void Utility::utilityFunction0(...)
438  * {
439  * HighPerformanceBenchmark::ScopedCategory scopedBenchmark("UtilityFunction0");
440  * ...
441  * }
442  *
443  * int main()
444  * {
445  * HighPerformanceBenchmark::get().start();
446  *
447  * while (keepLooping)
448  * {
449  * SomeClass::computeSomething();
450  * }
451  *
452  * HighPerformanceBenchmark::get().stop();
453  *
454  * // Get the normal or hierarchical performance report
455  * const std::vector<std::string> report = HighPerformanceBenchmark::get().report();
456  * const std::vector<std::string> reportWithHierarchies = HighPerformanceBenchmark::get().reportWithHierarchies();
457  * }
458  * </pre>
459  *
460  * which will result in something similar to the following for the normal report:
461  * <pre>
462  * Name | ...
463  * AlgorithmName | ...
464  * UtilityFunction0 | ...
465  * AlgorithmName::Function0 | ...
466  * AlgorithmName::Function1 | ...
467  * </pre>
468  * and for the hierarchical report the output will be similar to this (sub-categories will be appear indented):
469  * <pre>
470  * Name | ...
471  * AlgorithmName | ...
472  * Function0 | ...
473  * Function1 | ...
474  * UtilityFunction0 | ...
475  * </pre>
476  * Of course, the actual order of the categories depends on their proportional contribution to the overall measured CPU time
477  * @ingroup base
478  */
479 class OCEAN_BASE_EXPORT HighPerformanceBenchmark : public Singleton<HighPerformanceBenchmark>
480 {
481  friend class Singleton<HighPerformanceBenchmark>;
482 
483  public:
484 
485  /**
486  * Definition of a vector holding measurements in seconds.
487  */
488  typedef std::vector<double> MeasurementsSeconds;
489 
490  /**
491  * Definition of a map mapping category names to measurements.
492  */
493  typedef std::unordered_map<std::string, MeasurementsSeconds> MeasurementMap;
494 
495  /// Forward declaration
496  class Category;
497 
498  /// Typedef for a vector of categories
499  typedef std::vector<Category> Categories;
500 
501  /**
502  * This class defines a hierarchical category
503  * This class is used to group categories based on their names into a hierarchy. A hierarchy of categories is created by appending the name of a
504  * sub-category to the name of category, using a delimiter between both names, for example "Foo::Bar" is a sub-category of "Foo". This process can
505  * be repeated recursively ("Foo::Bar::Baz"). Categories without a delimiter in their name - or which cannot be matched otherwise - will be
506  * considered top-level categories ("Foo").
507  * @ingroup base
508  */
509  class Category
510  {
511  public:
512 
513  /**
514  * Deleted default constructor.
515  */
516  Category() = delete;
517 
518  /**
519  * Constructor
520  * @param categoryName The name of the category, must be valid
521  * @param measurementsSeconds The measurements in seconds that have been made by `HighPerformanceBenchmark` for this category, must be valid and non-empty
522  * @param categoryNameDelimiter The delimiter that separate the levels of hierarchy in the category names.
523  */
524  Category(const std::string& categoryName, const MeasurementsSeconds& measurementsSeconds, const std::string& categoryNameDelimiter);
525 
526  /**
527  * Adds a sub-category to this category
528  * @param subCategoryName The name of the category that will be added as a sub-category to this category, must be valid
529  * @param measurementsSeconds The measurements in seconds that have been made by `HighPerformanceBenchmark` for the new sub-category, must be valid and non-empty
530  */
531  bool addSubCategory(const std::string& subCategoryName, const MeasurementsSeconds& measurementsSeconds);
532 
533  /**
534  * Returns the sub-categories of this category
535  * @return The sub-categories
536  */
537  const Categories& subCategories() const;
538 
539  /**
540  * Returns the name of this category
541  * @return The name
542  */
543  const std::string& categoryName() const;
544 
545  /**
546  * Computes the sum of all measurements in this category and all of its sub-categories
547  * @return The sum
548  */
550 
551  /**
552  * Creates a performance report as a matrix of string tokens
553  * The token matrix is a means to determine the max. column widths in the final report. This alignment step does not happen here, cf. `HighPerformanceBenchmark::reportWithHierarchies()`
554  * @param tokenMatrix The resulting matrix of tokens.
555  * @param referenceSeconds The optional number of seconds that should be used to compute the percentage of CPU runtime of this categories (and it's sub-categories); for values <= 0.0 the percentage will be computed internally for this category only, range: (-infinity, infinity)
556  * @param numberIndentationSpace The optional number of spaces that should be prepended to the names of the categories in the final report (to visualize the hierarchy)
557  * @param categoryNameDelimiter The delimiter that separate the levels of hierarchy in the category names.
558  * @param addColumnDescriptions True, adds a row to the resulting token matrix that contains human-readable descriptions of the columns of the matrix, otherwise no descriptions will be added
559  * @param valuesAsStrings True, all cells will be of type string; False, column descriptions and category names will be reported as string and all other values as double or integer.
560  * @param includeSubCategories True, all sub-categories of the this category will be added to the token matrix as well; False, they will be ignored
561  * @return True, if the generation of the token matrix was successful, otherwise false
562  * @sa HighPerformanceBenchmark::reportWithHierarchies()
563  */
564  bool reportAsTokenMatrix(std::vector<std::vector<Value>>& tokenMatrix, const double referenceSeconds = 0.0, const unsigned numberIndentationSpace = 0u, const std::string& categoryNameDelimiter = "::", const bool addColumnDescriptions = false, const bool valuesAsStrings = true, const bool includeSubCategories = true) const;
565 
566  /**
567  * Recursively sorts a list of categories by their total CPU times in descending order
568  * @param categories The categories that will be sorted
569  */
570  static void sort(Categories& categories);
571 
572  /**
573  * Compares the recursive CPU times of two categories
574  * @param category0 The first category that will be used in this comparison, must be valid
575  * @param category1 The second category that will be used in this comparison, must be valid
576  * @return True if the CPU time of the first category is equal or larger than the second, otherwise false
577  */
578  static bool greaterCpuTime(const Category& category0, const Category& category1);
579 
580  protected:
581 
582  /// The human-readable name of this category, e.g., "Foo"
583  std::string categoryName_;
584 
585  /// The sorted measurements for this category
587 
588  /// The delimiter that is used to separate different levels of the hierarchy in the human-readable category name, e.g. "::"
590 
591  /// The list of sub-categories, e.g. "Foo::Bar", "Foo::Bar::Test", "Foo::Baz", etc.
592  std::vector<Category> subCategories_;
593  };
594 
595  public:
596 
597  /**
598  * This class implements a scoped benchmark category.
599  * There must not exist more than one object for each category at the same time.
600  */
601  class OCEAN_BASE_EXPORT ScopedCategory
602  {
603  public:
604 
605  /**
606  * Creates a new scoped category with specific name.
607  * Benchmarking will be active as long as the object exists (the execution time of the category will be increased as long as the object exists).
608  * @param name The name of the category, must be valid
609  */
610  explicit inline ScopedCategory(std::string name);
611 
612  /**
613  * Destructs the scoped category.
614  * Benchmarking for this category will end.
615  */
616  inline ~ScopedCategory();
617 
618  /**
619  * Explicitly skips benchmarking for this category before the actual scope ends, e.g., if a function did not finish due to an error.
620  */
621  inline void skip();
622 
623  /**
624  * Explicitly ends benchmarking for this category before the actual scope ends.
625  */
626  inline void release();
627 
628  /**
629  * Changes the benchmarking category, releases the current category and creates a new one.
630  * @param name The new name of the category, empty to release the current category without creating a new one
631  */
632  inline void change(std::string name);
633 
634  protected:
635 
636  /**
637  * Not existing copy constructor.
638  * @param scopedCategory The object that would be copied
639  */
640  ScopedCategory(const ScopedCategory& scopedCategory) = delete;
641 
642  /**
643  * Not existing copy constructor.
644  * @param scopedCategory The object that would be copied
645  */
646  ScopedCategory& operator=(const ScopedCategory& scopedCategory) = delete;
647 
648  protected:
649 
650  /// The name of the benchmark category.
651  std::string name_;
652 
653  /// The CPU ticks when the benchmark of this category started.
655  };
656 
657  public:
658 
659  /**
660  * Starts benchmarking.
661  * @return True, if succeeded
662  * @see stop(), isRunning().
663  */
664  bool start();
665 
666  /**
667  * Stops benchmarking.
668  * @return True, if succeeded
669  * @see start(), isRunning().
670  */
671  bool stop();
672 
673  /**
674  * Rests all benchmark categories and measurements.
675  */
676  void reset();
677 
678  /**
679  * Returns whether benchmarking is currently active; False by default.
680  * @return True, if so
681  */
682  bool isRunning() const;
683 
684  /**
685  * Returns the map with category names and measurement objects.
686  * @return The measurement map
687  */
689 
690  /**
691  * Creates a performance report as a readable string.
692  * @param referenceCategory Optional reference category for to add relative performance values to the report
693  * @return The report as readable string, one string for each line in the report
694  */
695  std::vector<std::string> report(const std::string& referenceCategory = std::string()) const;
696 
697  /**
698  * Creates a performance report for a hierarchy of categories as a human-readable string.
699  *
700  * A hierarchy of categories is created by appending the name of a sub-category to the name of category, using a delimiter between both names,
701  * for example "Foo::Bar" is a sub-category of "Foo". This process can be repeated recursively ("Foo::Bar::Baz"). Categories without a delimiter
702  * in their name - or which cannot be matched otherwise - will be considered top-level categories ("Foo").
703  *
704  * The final report will list either 1) all top-level categories with their subsumed sub-categories (which will be indented) or 2) a specific
705  * top-level category. All categories and sub-categories will be sorted by their total CPU-time in descending order.
706  * @param report The resulting report as a readable string, one string for each line in the report
707  * @param referenceCategory The optional reference category for to add relative performance values to the report
708  * @param categoryNameDelimiter The optional delimiter that is used to separate levels of categories in a hierarchy
709  * @return True, if the generation of the report was successful, otherwise false
710  */
711  bool reportWithHierarchies(std::vector<std::string>& report, const std::string& referenceCategory = std::string(), const std::string& categoryNameDelimiter = "::") const;
712 
713  /**
714  * Returns the number of measurements of a specific category.
715  * @param category The category for which the number of measurements will be returned
716  * @return The number of measurements, with range [0, infinity)
717  */
718  size_t measurements(const std::string& category);
719 
720  /**
721  * Creates a hierarchy of categories based on their names from a map of measurements
722  * @param measurementMap The map of measurements (category -> measurements) for which a hierarchy of categories will be created
723  * @param categoryNameDelimiter The delimiter that is used to separate levels of categories in a hierarchy
724  * @return The hierarchy
725  */
726  static Categories createCategoryHierarchy(const MeasurementMap& measurementMap, const std::string& categoryNameDelimiter);
727 
728  /**
729  * Given a hierarchy of categories with measurements, create a matrix with the performance information
730  * The output of this function is a matrix where each cell contains the information that the final report will contain. This intermediate container makes it easy to print the report with aligned columns.
731  * @param categories The hierarchy of categories for which a token matrix will created, must be valid and not empty.
732  * @param referenceCategory The optional reference category for to add relative performance values to the report
733  * @param categoryNameDelimiter The optional delimiter that is used to separate levels of categories in a hierarchy
734  * @param valuesAsStrings True, all cells will be of type string; False, column descriptions and category names will be reported as string and all other values as double or integer.
735  * @param tokenMatrix The resulting token matrix for all categories.
736  * @return True, if the generation of the token matrix was successful, otherwise false.
737  */
738  static bool createTokenMatrixFromCategoryHierarchy(const Categories& categories, const std::string referenceCategory, const std::string& categoryNameDelimiter, const bool valuesAsStrings, std::vector<std::vector<Value>>& tokenMatrix);
739 
740  protected:
741 
742  /**
743  * Adds a benchmark measurement for a specified category.
744  * @param name The name of the category
745  * @param measurement The benchmark measurement in seconds, with range [0, infinity)
746  */
747  void addMeasurement(const std::string& name, const double measurement);
748 
749  protected:
750 
751  /**
752  * Default constructor.
753  */
755 
756  /**
757  * Destructs an object.
758  */
760 
761  protected:
762 
763  /// The map mapping category names to their measurement objects.
765 
766  /// True, if benchmarking is running, false by default.
768 
769  /// The lock object.
770  mutable Lock lock_;
771 };
772 
774  statisticPerformance(&performance)
775 {
777 }
778 
780 {
781  release();
782 }
783 
785 {
786  if (statisticPerformance)
787  {
788  statisticPerformance->stop();
789  statisticPerformance = nullptr;
790  }
791 }
792 
794 {
795  ticksStart_ = ticks();
796 }
797 
798 inline double HighPerformanceTimer::ticks2seconds(const Ticks ticks)
799 {
800  ocean_assert(precision() != Ticks(0));
801  return double(ticks) / double(precision());
802 }
803 
804 inline double HighPerformanceStatistic::first() const
805 {
806  if (measurements_.empty())
807  {
808  return -1.0;
809  }
810 
811  return measurements_.front();
812 }
813 
815 {
816  if (measurements_.empty())
817  {
818  return -1.0;
819  }
820 
821  return measurements_.front() * 1000.0;
822 }
823 
824 inline double HighPerformanceStatistic::second() const
825 {
826  if (measurements_.size() < 2)
827  {
828  return -1.0;
829  }
830 
831  return measurements_[1];
832 }
833 
835 {
836  if (measurements_.size() < 2)
837  {
838  return -1.0;
839  }
840 
841  return measurements_[1] * 1000.0;
842 }
843 
844 inline double HighPerformanceStatistic::best() const
845 {
846  if (measurements_.empty())
847  {
848  return -1.0;
849  }
850 
851  return best_;
852 }
853 
855 {
856  if (measurements_.empty())
857  {
858  return -1.0;
859  }
860 
861  return best_ * 1000.0;
862 }
863 
864 inline double HighPerformanceStatistic::worst() const
865 {
866  if (measurements_.empty())
867  {
868  return -1.0;
869  }
870 
871  return worst_;
872 }
873 
875 {
876  if (measurements_.empty())
877  {
878  return -1.0;
879  }
880 
881  return worst_ * 1000.0;
882 }
883 
884 inline double HighPerformanceStatistic::last() const
885 {
886  if (measurements_.empty())
887  {
888  return -1.0;
889  }
890 
891  return measurements_.back();
892 }
893 
895 {
896  if (measurements_.empty())
897  {
898  return -1.0;
899  }
900 
901  return measurements_.back() * 1000.0;
902 }
903 
905 {
906  return average() * 1000.0;
907 }
908 
909 inline double HighPerformanceStatistic::averageCyclesPerOperation(const double operations, const double clockRate) const
910 {
911  ocean_assert(operations > 0.0 && clockRate > 0.0);
912 
913  const double seconds = average();
914  if (seconds <= 0)
915  {
916  return -1;
917  }
918 
919  const double operationsPerSecond = operations / seconds;
920  ocean_assert(operationsPerSecond > 0.0);
921 
922  const double cyclesPerOperation = clockRate / operationsPerSecond;
923 
924  return cyclesPerOperation;
925 }
926 
927 inline double HighPerformanceStatistic::total() const
928 {
929  return total_;
930 }
931 
933 {
934  return total() * 1000.0;
935 }
936 
938 {
939  return measurements_.size();
940 }
941 
943 {
944  return timer_.seconds();
945 }
946 
948 {
949  return running() * 1000.0;
950 }
951 
953 {
954  return started_;
955 }
956 
957 inline HighPerformanceStatistic::operator bool() const
958 {
959  return !measurements_.empty();
960 }
961 
962 
963 inline std::ostream& operator<<(std::ostream& stream, const HighPerformanceStatistic& highPerformanceStatistic)
964 {
965  stream << highPerformanceStatistic.toString();
966 
967  return stream;
968 }
969 
970 template <bool tActive>
971 MessageObject<tActive>& operator<<(MessageObject<tActive>& messageObject, const HighPerformanceStatistic& highPerformanceStatistic)
972 {
973  messageObject << highPerformanceStatistic.toString();
974 
975  return messageObject;
976 }
977 
978 template <bool tActive>
979 MessageObject<tActive>& operator<<(MessageObject<tActive>&& messageObject, const HighPerformanceStatistic& highPerformanceStatistic)
980 {
981  messageObject << highPerformanceStatistic.toString();
982 
983  return messageObject;
984 }
985 
987  name_(std::move(name)),
988  startTicks_(HighPerformanceTimer::ticks())
989 {
990  // nothing to do here
991 }
992 
994 {
995  release();
996 }
997 
999 {
1000  name_.clear();
1001 }
1002 
1004 {
1005  if (!name_.empty())
1006  {
1008  ocean_assert(startTicks_ <= stopTicks);
1009 
1010  const HighPerformanceTimer::Ticks ticks = stopTicks - startTicks_;
1011 
1012  const double measurement = HighPerformanceTimer::ticks2seconds(ticks);
1013  HighPerformanceBenchmark::get().addMeasurement(name_, measurement);
1014 
1015  name_.clear();
1016  }
1017 }
1018 
1020 {
1021  if (name_ == name)
1022  {
1023  return;
1024  }
1025 
1026  release();
1027 
1028  if (!name.empty())
1029  {
1030  name_ = std::move(name);
1031  startTicks_ = HighPerformanceTimer::ticks();
1032  }
1033 }
1034 
1036  isRunning_(false)
1037 {
1038  // nothing to do here
1039 }
1040 
1042 {
1043  // nothing to do here
1044 }
1045 
1046 }
1047 
1048 #endif // META_OCEAN_BASE_HIGH_PERFORMANCE_TIMER_H
This class defines a hierarchical category This class is used to group categories based on their name...
Definition: HighPerformanceTimer.h:510
double computeRecursiveSumSeconds() const
Computes the sum of all measurements in this category and all of its sub-categories.
Category(const std::string &categoryName, const MeasurementsSeconds &measurementsSeconds, const std::string &categoryNameDelimiter)
Constructor.
static void sort(Categories &categories)
Recursively sorts a list of categories by their total CPU times in descending order.
std::string categoryNameDelimiter_
The delimiter that is used to separate different levels of the hierarchy in the human-readable catego...
Definition: HighPerformanceTimer.h:589
bool addSubCategory(const std::string &subCategoryName, const MeasurementsSeconds &measurementsSeconds)
Adds a sub-category to this category.
bool reportAsTokenMatrix(std::vector< std::vector< Value >> &tokenMatrix, const double referenceSeconds=0.0, const unsigned numberIndentationSpace=0u, const std::string &categoryNameDelimiter="::", const bool addColumnDescriptions=false, const bool valuesAsStrings=true, const bool includeSubCategories=true) const
Creates a performance report as a matrix of string tokens The token matrix is a means to determine th...
const Categories & subCategories() const
Returns the sub-categories of this category.
MeasurementsSeconds sortedMeasurementsSeconds_
The sorted measurements for this category.
Definition: HighPerformanceTimer.h:586
std::vector< Category > subCategories_
The list of sub-categories, e.g. "Foo::Bar", "Foo::Bar::Test", "Foo::Baz", etc.
Definition: HighPerformanceTimer.h:592
static bool greaterCpuTime(const Category &category0, const Category &category1)
Compares the recursive CPU times of two categories.
Category()=delete
Deleted default constructor.
std::string categoryName_
The human-readable name of this category, e.g., "Foo".
Definition: HighPerformanceTimer.h:583
const std::string & categoryName() const
Returns the name of this category.
This class implements a scoped benchmark category.
Definition: HighPerformanceTimer.h:602
ScopedCategory & operator=(const ScopedCategory &scopedCategory)=delete
Not existing copy constructor.
std::string name_
The name of the benchmark category.
Definition: HighPerformanceTimer.h:651
void change(std::string name)
Changes the benchmarking category, releases the current category and creates a new one.
Definition: HighPerformanceTimer.h:1019
HighPerformanceTimer::Ticks startTicks_
The CPU ticks when the benchmark of this category started.
Definition: HighPerformanceTimer.h:654
ScopedCategory(std::string name)
Creates a new scoped category with specific name.
Definition: HighPerformanceTimer.h:986
void skip()
Explicitly skips benchmarking for this category before the actual scope ends, e.g....
Definition: HighPerformanceTimer.h:998
void release()
Explicitly ends benchmarking for this category before the actual scope ends.
Definition: HighPerformanceTimer.h:1003
ScopedCategory(const ScopedCategory &scopedCategory)=delete
Not existing copy constructor.
~ScopedCategory()
Destructs the scoped category.
Definition: HighPerformanceTimer.h:993
The HighPerformanceBenchmark object allows to benchmark algorithms with individual categories.
Definition: HighPerformanceTimer.h:480
size_t measurements(const std::string &category)
Returns the number of measurements of a specific category.
std::unordered_map< std::string, MeasurementsSeconds > MeasurementMap
Definition of a map mapping category names to measurements.
Definition: HighPerformanceTimer.h:493
bool isRunning() const
Returns whether benchmarking is currently active; False by default.
bool isRunning_
True, if benchmarking is running, false by default.
Definition: HighPerformanceTimer.h:767
bool reportWithHierarchies(std::vector< std::string > &report, const std::string &referenceCategory=std::string(), const std::string &categoryNameDelimiter="::") const
Creates a performance report for a hierarchy of categories as a human-readable string.
MeasurementMap measurementMap_
The map mapping category names to their measurement objects.
Definition: HighPerformanceTimer.h:764
~HighPerformanceBenchmark()
Destructs an object.
Definition: HighPerformanceTimer.h:1041
void reset()
Rests all benchmark categories and measurements.
static bool createTokenMatrixFromCategoryHierarchy(const Categories &categories, const std::string referenceCategory, const std::string &categoryNameDelimiter, const bool valuesAsStrings, std::vector< std::vector< Value >> &tokenMatrix)
Given a hierarchy of categories with measurements, create a matrix with the performance information T...
Lock lock_
The lock object.
Definition: HighPerformanceTimer.h:770
std::vector< std::string > report(const std::string &referenceCategory=std::string()) const
Creates a performance report as a readable string.
HighPerformanceBenchmark()
Default constructor.
Definition: HighPerformanceTimer.h:1035
void addMeasurement(const std::string &name, const double measurement)
Adds a benchmark measurement for a specified category.
std::vector< Category > Categories
Typedef for a vector of categories.
Definition: HighPerformanceTimer.h:496
static Categories createCategoryHierarchy(const MeasurementMap &measurementMap, const std::string &categoryNameDelimiter)
Creates a hierarchy of categories based on their names from a map of measurements.
std::vector< double > MeasurementsSeconds
Definition of a vector holding measurements in seconds.
Definition: HighPerformanceTimer.h:488
bool start()
Starts benchmarking.
MeasurementMap measurementMap() const
Returns the map with category names and measurement objects.
bool stop()
Stops benchmarking.
This class defines a scoped high performance statistic module.
Definition: HighPerformanceTimer.h:138
ScopedStatistic(HighPerformanceStatistic &performance)
Creates a new scoped statistic object and starts a new measurement.
Definition: HighPerformanceTimer.h:773
ScopedStatistic & operator=(const ScopedStatistic &)=delete
Deleted copy operator.
HighPerformanceStatistic * statisticPerformance
High performance statistic object receiving the measurement value.
Definition: HighPerformanceTimer.h:173
void release()
Explicitly releases the object and does not wait until the scope ends.
Definition: HighPerformanceTimer.h:784
~ScopedStatistic()
Destructs a scoped statistic object and stops the measurement.
Definition: HighPerformanceTimer.h:779
ScopedStatistic(const ScopedStatistic &)=delete
Deleted copy constructor.
This class implements a simple module gathering high performance timer statistics.
Definition: HighPerformanceTimer.h:124
double running() const
Returns the current (still) running measurement time in seconds.
Definition: HighPerformanceTimer.h:942
std::vector< double > Measurements
Definition of a vector storing performance measurements.
Definition: HighPerformanceTimer.h:130
HighPerformanceTimer timer_
High performance timer.
Definition: HighPerformanceTimer.h:388
std::string toString(const unsigned int precision=2u) const
Returns a string with the relevant performance information of this statistic object.
double percentileMseconds(double value) const
Returns a specific percentile (e.g., P50 = median, P90, P95, etc.) measurement time in milliseconds.
double totalMseconds() const
Returns the total measurement time in milliseconds.
Definition: HighPerformanceTimer.h:932
double medianMseconds() const
Returns the median measurement time in milliseconds.
bool isRunning() const
Returns whether currently a measurement is running.
Definition: HighPerformanceTimer.h:952
double worstMseconds() const
Returns the worst measurement time in milliseconds.
Definition: HighPerformanceTimer.h:874
Measurements measurements_
The individual measurements in order as measured.
Definition: HighPerformanceTimer.h:391
double worst() const
Returns the worst measurement time in seconds.
Definition: HighPerformanceTimer.h:864
double worst_
Worst measurement time in seconds.
Definition: HighPerformanceTimer.h:397
void startIf(const bool value)
Starts a new measurement if the given value is True, otherwise nothing happens.
double first() const
Returns the first measurement time in seconds.
Definition: HighPerformanceTimer.h:804
void stop()
Stops a measurement.
double best_
Best measurement time in seconds.
Definition: HighPerformanceTimer.h:394
void reset()
Resets all gathered statistics.
double best() const
Returns the best measurement time in seconds.
Definition: HighPerformanceTimer.h:844
HighPerformanceStatistic()
Creates a new statistic module.
double average() const
Returns the average measurement time in seconds.
double second() const
Returns the second measurement time in seconds.
Definition: HighPerformanceTimer.h:824
double total_
Entire measurement time in seconds.
Definition: HighPerformanceTimer.h:400
double secondMseconds() const
Returns the second measurement time in milliseconds.
Definition: HighPerformanceTimer.h:834
double runningMseconds() const
Returns the current (still) running measurement time in milliseconds.
Definition: HighPerformanceTimer.h:947
bool started_
State determining whether one measurement is active currently.
Definition: HighPerformanceTimer.h:403
double bestMseconds() const
Returns the best measurement time in milliseconds.
Definition: HighPerformanceTimer.h:854
void stopIf(const bool value)
Stops a measurement.
void skipIf(const bool value)
Skips a started measurement.
void start()
Starts a new measurement.
double averageCyclesPerOperation(const double operations, const double clockRate=3800000000.0) const
Returns the average number of CPU cycles needed for one operation.
Definition: HighPerformanceTimer.h:909
double last() const
Returns the last measurement time in seconds.
Definition: HighPerformanceTimer.h:884
double median() const
Returns the median measurement time in seconds.
double firstMseconds() const
Returns the first measurement time in milliseconds.
Definition: HighPerformanceTimer.h:814
HighPerformanceStatistic & operator+=(const HighPerformanceStatistic &right)
Adds measurements from another object to this statistic object.
double averageMseconds() const
Returns the average measurement time in milliseconds.
Definition: HighPerformanceTimer.h:904
double lastMseconds() const
Returns the last (most recent measurement time in milliseconds.
Definition: HighPerformanceTimer.h:894
double total() const
Returns the total measurement time in seconds.
Definition: HighPerformanceTimer.h:927
double percentile(double value) const
Returns a specific percentile (e.g., P50 = median, P90, P95, etc.) measurement time in seconds.
size_t measurements() const
Returns the number of measurements.
Definition: HighPerformanceTimer.h:937
void skip()
Skips a started measurement.
This class implements a high performance timer.
Definition: HighPerformanceTimer.h:31
int64_t Ticks
Definition of CPU ticks.
Definition: HighPerformanceTimer.h:37
double seconds() const
Returns the measured time since the timer has been started in seconds.
double mseconds() const
Returns the measured time since the timer has been started in milliseconds.
double nseconds() const
Returns the measured time since the timer has been started in nanoseconds.
static Ticks ticksPerSecond()
Returns the resolution of the timer in ticks per second.
static Ticks precision()
Returns the precision of the timer.
double yseconds() const
Returns the measured time since the timer has been started in microseconds.
static Ticks ticks()
Returns the recent CPU ticks.
static double ticks2seconds(const Ticks ticks)
Converts a given CPU tick into seconds regarding the resolution of the timer.
Definition: HighPerformanceTimer.h:798
HighPerformanceTimer()
Creates a new timer and starts the time measurement.
void start()
(Re-)starts the time measurement.
Definition: HighPerformanceTimer.h:793
This class implements a recursive lock object.
Definition: Lock.h:31
This template class is the base class for all singleton objects.
Definition: Singleton.h:71
static HighPerformanceBenchmark & get()
Returns a reference to the unique object.
Definition: Singleton.h:115
void release(T *object)
This functions allows to release a DirectShow object if it does exist.
Definition: DSObject.h:266
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15
std::ostream & operator<<(std::ostream &stream, const HighPerformanceStatistic &highPerformanceStatistic)
Definition: HighPerformanceTimer.h:963
uint64_t HighPerformanceTimer_externalPrivacyConfirmTicks()
Returns the recent CPU ticks which will contain a random offset which is constant through the executi...