2 / Copyright (c) 2009-20010 Vicente J. Botet Escriba
4 / Distributed under the Boost Software License, Version 1.0. (See accompanying
5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
13 [/=================================]
14 [section Stopwatches and Stopclocks]
15 [/=================================]
17 At the user level, the main use case of measuring the elapsed time is to report these measures on the display. For example
19 using namespace boost::chrono;
22 strict_stopwatch<> sw;
24 for ( long i = 0; i < j; ++i )
25 std::sqrt( 123.456L ); // burn some time
27 std::cout << sw.elapsed() << std::endl;
37 Could produce the following output
43 __stopwatch is a template class with a Clock as template parameter. The default __Clock is the __high_resolution_clock.
45 We can replace the lines
47 strict_stopwatch <> sw;
50 std::cout << sw.elapsed() << std::endl;
52 using the __stopwatch_reporter`<>` class. This class provides a run time reporting package that can be invoked in a single line of code to report the usage of a __Clock. For example
54 using namespace boost::chrono;
57 __stopwatch_reporter<__strict_stopwatch <> > _;
59 for ( long i = 0; i < j; ++i )
60 std::sqrt( 123.456L ); // burn some time
71 Which produce the same kind of output.
73 __stopwatch_reporter is a template class with a __Stopwatch and a __Formatter as template parameter.
75 We can use even a shorter line using the __stopclock class, which allows to replace
77 __stopwatch_reporter<__strict_stopwatch<> > _;
81 __strict_stopclock<> _;
83 [section:accumulators Stopwatches accumulation and statistics]
85 The preceding stopwatch manage only with a measure. It is also interesting to have an statisitical view of these times,
86 for example the sum, min, max and mean. __laps_stopwatch`<>` associates an accumulator with a __stopwatch__, so we are able to retrieve any statistical feature Boost.Accumulator provides.
90 using namespace boost::chrono;
93 static __stopwatch_reporter<__laps_stopwatch<> > sw;
94 __stopwatch_reporter<__laps_stopwatch<> >::scoped_run _(sw);
96 for ( long i = 0; i < j; ++i )
97 std::sqrt( 123.456L ); // burn some time
108 Will produce the following output
110 3 times, sum=0.034s, min=0.006s, max=0.017s, mean=0.011s
117 [section:function How can I prefix each report with `BOOST_CURRENT_FUNCTION` function signature?]
119 You will need to give a specific format to your __stopclock. You just need to concatenate your specific pattern to the default_format of the formatter.
121 For example, for a __stopclock_accumulator the default formatter is __stopwatch_accumulator_formatter, you will need to do something like:
123 static __stopclock_accumulator<> acc(
124 std::string(BOOST_CURRENT_FUNCTION) + ": "
125 + __stopwatch_accumulator_formatter::default_format()
127 __stopclock_accumulator<>::scoped_run _(acc);
130 Some of you will say that this is too long to type just to get the a report. You can of course define your own macro as
132 #define REPORT_FUNCTION_ACCUMULATED_LIFETIME\
133 static boost::stopwatches::__stopclock_accumulator<> \
134 BOOST_JOIN(_accumulator_, __LINE__)_
135 ( std::string(BOOST_CURRENT_FUNCTION) + ": " + \
136 boost::stopwatches::__stopwatch_accumulator_formatter::default_format() \
138 boost::stopwatches::__stopclock_accumulator<>::scoped_run \
139 BOOST_JOIN(_accumulator_run_, __LINE__) \
140 (BOOST_JOIN(_accumulator_, __LINE__))
143 With this macro you will just have to write
147 REPORT_FUNCTION_ACCUMULATED_LIFETIME() ;
148 boost::this_thread::sleep(boost::posix_time::milliseconds(100));
154 [section:file_line How can I prefix each report with `__FILE__[__LINE__]` pattern?]
156 When you want to prefix with the `__FILE__[__LINE__]` pattern you can follow the same technique as described below:
158 #define REPORT_LINE_ACCUMULATED_LIFETIME \
159 static __stopclock_accumulator<>
160 BOOST_JOIN(_accumulator_, __LINE__) \
161 ( std::string(__FILE__) + "[" + BOOST_STRINGIZE(__LINE__) + "] "
162 + __stopwatch_accumulator_formatter::default_format() \
164 __stopclock_accumulator<>::scoped_run \
165 BOOST_JOIN(_accumulator_run_, __LINE__)
166 (BOOST_JOIN(_accumulator_, __LINE__))
168 Now you can mix fcntion and line reports as follows
172 REPORT_FUNCTION_ACCUMULATED_LIFETIME;
173 boost::this_thread::sleep(boost::posix_time::milliseconds(100));
175 REPORT_LINE_ACCUMULATED_LIFETIME;
176 boost::this_thread::sleep(boost::posix_time::milliseconds(200));
183 [section:non_static_acc Can I use an stopclock accumulator which is not static?]
185 The typical example of stopclock_accumulator is to get statistical measures of the time a function takes for each one of its calls.
186 You can also use __stopclock_accumulator to get statistical measures of the time a given loop takes for each one of its laps.
188 __stopclock_accumulator<> acc(
189 std::string(__FILE__) + "[" + BOOST_STRINGIZE(__LINE__) + "] "
190 + __stopwatch_accumulator_formatter::default_format()
192 for (int i=0; i<N; i++) {
193 __stopclock_accumulator<>::scoped_run _(acc);
200 [section:suspend How can I suspend a stopwatch?]
202 #include <boost/stopwatches/stopwatch.hpp>
204 #include <boost/thread.hpp>
207 using namespace boost::stopwatches;
211 __stopwatch_reporter<__stopwatch__<> >:: _(BOOST_STOPWATCHES_STOPWATCH_FUNCTION_FORMAT);
212 for (long i =0; i< j; i+=1)
213 res+=std::sqrt( res+123.456L+i ); // burn some time
214 __stopwatch_reporter<__stopwatch__<> >::scoped_suspend s(_);
215 boost::this_thread::sleep(boost::posix_time::milliseconds(200));
220 [section:stats How to get specific statistics from stopwatches accumulator?]
222 There are two use cases that coul need to change the statistics associated to a stopwatches accumulator:
224 # We want to reduce the default reporting and we preffer to adapt the statistics to the reporting
225 # We want to report other statistics of the samples
227 For the first case we just need to change the accumulator_set and the format we want to get. Imagin we want to get only the count, sam and mean statistics, no need to calculate the min neither the max.
229 using namespace boost::accumulators;
231 typedef __stopwatch_reporter<__laps_stopwatch<__process_real_cpu_clock__,
232 accumulator_set<__process_real_cpu_clock__::rep,
239 > my_stopwatch_accumulator_reporter;
243 static my_stopwatch_accumulator_reporter acc("%c times, sum=%ss, mean=%as\n");
244 my_stopwatch_accumulator_reporter::scoped_run _(acc);
246 for ( long i = 0; i < j; ++i )
247 std::sqrt( 123.456L ); // burn some time
252 But what would hapend if we haven't forced the format:
254 static my_stopwatch_accumulator_reporter acc;
255 my_stopwatch_accumulator_reporter::scoped_run _(acc);
257 Unfortunately there is no error at compile time. Fortunately, the run-time execution is not undefined and will return 0 for the missing statistics.
264 [section:other How can I make a specific formatter when the default do not satisfy my expectations]
266 Imagine then that we want to report the `tag::variance(lazy)`. We will need to include the specific accumulator file
269 #include <boost/accumulators/statistics/variance.hpp>
271 typedef __stopwatch_reporter<__laps_stopwatch<__process_real_cpu_clock__,
272 accumulator_set<__process_real_cpu_clock__::rep,
280 > my_stopwatch_accumulator_reporter;
282 But what happens if we add new statistics to the accumulator_set that are not taken in account by the default formatter? These statistics will simply be ignored. So we will need to define our own accumulator formatter.
284 typedef __stopwatch_reporter<__laps_stopwatch<__process_real_cpu_clock__,
285 accumulator_set<__process_real_cpu_clock__::rep,
293 my_stopwatch_accumulator_formatter
294 > my_stopwatch_accumulator_reporter;
296 Next follow the definition of a formatter taking care of count, sum, mean and variance
298 class my_stopwatch_accumulator_formatter {
300 typedef std::string string_type;
301 typedef char char_type;
302 typedef std::ostream ostream_type;
304 static ostream_type & default_os() {return std::cout;}
305 static const char_type* default_format() {
306 return "%c times, sum=%ss, mean=%as, variance=%vs\n";
308 static int default_places() { return 3; }
310 template <class Stopwatch >
311 static void show_time( Stopwatch & stopwatch_, const char_type* format,
312 int places, ostream_type & os, system::error_code & ec)
314 typedef typename Stopwatch::duration duration_t;
315 typename Stopwatch::accumulator accumulator& acc = stopwatch_.accumulated();
317 boost::io::ios_flags_saver ifs( os );
318 os.setf( std::ios_base::fixed, std::ios_base::floatfield );
319 boost::io::ios_precision_saver ips( os );
320 os.precision( places );
322 for ( ; *format; ++format ) {
323 if ( *format != '%' || !*(format+1) || !std::strchr("acsv", *(format+1)) ) {
329 os << boost::chrono::duration<double>(
330 duration_t(accumulators::sum(acc))).count();
333 os << (accumulators::count(acc)>0)
334 ? boost::chrono::__duration__<double>(duration_t(
335 duration_t::rep(accumulators::mean(acc)))).count()
339 os << accumulators::count(acc);
342 os << (accumulators::count(acc)>0)
343 ? boost::chrono::__duration__<double>(duration_t(
344 duration_t::rep(accumulators::variance(acc)))).count()
348 assert(0 && "my_stopwatch_accumulator_formatter internal logic error");