1 /*
2  * SObjectizer-5
3  */
4 /*!
5  * \since v.5.4.0
6  * \file
7  * \brief A simple helpers for building benchmarks.
8  */
9 #pragma once
10 
11 #include <chrono>
12 #include <iostream>
13 #include <string>
14 #include <stdexcept>
15 
16 namespace benchmarks_details {
17 
18 //! Helper class for changing and restoring ostream precision settings.
19 class precision_settings_t
20 	{
21 		std::ios_base & m_what;
22 		std::streamsize m_old_value;
23 
24 	public :
precision_settings_t(std::ios_base & what,std::streamsize new_value)25 		precision_settings_t(
26 			std::ios_base & what,
27 			std::streamsize new_value )
28 			:	m_what( what )
29 			,	m_old_value( what.precision( new_value ) )
30 			{}
~precision_settings_t()31 		~precision_settings_t()
32 			{
33 				m_what.precision( m_old_value );
34 			}
35 	};
36 
37 } /* namespace benchmarks_details */
38 
39 //! A helper for fixing starting and finishing time points and
40 //! calculate events processing time and events throughtput.
41 class benchmarker_t
42 	{
43 	public :
44 		//! Fix starting time.
45 		inline void
start()46 		start()
47 			{
48 				m_start = std::chrono::high_resolution_clock::now();
49 			}
50 
51 		//! Fix finish time and show stats.
52 		inline void
finish_and_show_stats(unsigned long long events,const std::string & title)53 		finish_and_show_stats(
54 			unsigned long long events,
55 			const std::string & title )
56 			{
57 				if( !events )
58 					throw std::invalid_argument( "events cannot be 0" );
59 
60 				auto finish_time = std::chrono::high_resolution_clock::now();
61 				const double duration =
62 						std::chrono::duration_cast< std::chrono::milliseconds >(
63 								finish_time - m_start ).count() / 1000.0;
64 				const double price = duration / events;
65 				const double throughtput = 1 / price;
66 
67 				benchmarks_details::precision_settings_t precision{ std::cout, 10 };
68 				std::cout << title << ": " << events
69 						<< ", total_time: " << duration << "s"
70 						<< "\n""price: " << price << "s"
71 						<< "\n""throughtput: " << throughtput << " " << title << "/s"
72 						<< std::endl;
73 			}
74 
75 	private :
76 		std::chrono::high_resolution_clock::time_point m_start;
77 	};
78 
79 //! A helper for showing duration between constructor and destructor calls.
80 /*!
81  * Usage example:
82 \code
83 {
84 	duration_meter_t meter( "creating some objects" );
85 	... // Some code here
86 } // Duration of the code above will be shown here.
87 \endcode
88 */
89 class duration_meter_t
90 	{
91 	public :
duration_meter_t(std::string name)92 		duration_meter_t( std::string name )
93 			:	m_name( std::move( name ) )
94 			,	m_start( std::chrono::high_resolution_clock::now() )
95 			{}
96 
~duration_meter_t()97 		~duration_meter_t()
98 			{
99 				auto finish = std::chrono::high_resolution_clock::now();
100 
101 				benchmarks_details::precision_settings_t precision{ std::cout, 10 };
102 				std::cout << m_name << ": "
103 					<< std::chrono::duration_cast< std::chrono::milliseconds >(
104 							finish - m_start ).count() / 1000.0 << "s"
105 					<< std::endl;
106 			}
107 
108 	private :
109 		const std::string m_name;
110 		const std::chrono::high_resolution_clock::time_point m_start;
111 	};
112 
113