]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/chrono/doc/stopwatches/tutorial.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / chrono / doc / stopwatches / tutorial.qbk
1 [/
2 / Copyright (c) 2009-20010 Vicente J. Botet Escriba
3 /
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)
6 /]
7
8
9 [/================]
10 [/section Tutorial]
11 [/================]
12
13 [/=================================]
14 [section Stopwatches and Stopclocks]
15 [/=================================]
16
17 At the user level, the main use case of measuring the elapsed time is to report these measures on the display. For example
18
19 using namespace boost::chrono;
20
21 int f1(long j) {
22 strict_stopwatch<> sw;
23
24 for ( long i = 0; i < j; ++i )
25 std::sqrt( 123.456L ); // burn some time
26
27 std::cout << sw.elapsed() << std::endl;
28 return 0;
29 }
30 int main() {
31 f1(100000);
32 f1(200000);
33 f1(300000);
34 return 0;
35 }
36
37 Could produce the following output
38
39 0.006s
40 0.011s
41 0.017s
42
43 __stopwatch is a template class with a Clock as template parameter. The default __Clock is the __high_resolution_clock.
44
45 We can replace the lines
46
47 strict_stopwatch <> sw;
48
49 ...
50 std::cout << sw.elapsed() << std::endl;
51
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
53
54 using namespace boost::chrono;
55
56 int f1(long j) {
57 __stopwatch_reporter<__strict_stopwatch <> > _;
58
59 for ( long i = 0; i < j; ++i )
60 std::sqrt( 123.456L ); // burn some time
61
62 return 0;
63 }
64 int main() {
65 f1(100000);
66 f1(200000);
67 f1(300000);
68 return 0;
69 }
70
71 Which produce the same kind of output.
72
73 __stopwatch_reporter is a template class with a __Stopwatch and a __Formatter as template parameter.
74
75 We can use even a shorter line using the __stopclock class, which allows to replace
76
77 __stopwatch_reporter<__strict_stopwatch<> > _;
78
79 by
80
81 __strict_stopclock<> _;
82
83 [section:accumulators Stopwatches accumulation and statistics]
84
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.
87
88 For example
89
90 using namespace boost::chrono;
91
92 int f1(long j) {
93 static __stopwatch_reporter<__laps_stopwatch<> > sw;
94 __stopwatch_reporter<__laps_stopwatch<> >::scoped_run _(sw);
95
96 for ( long i = 0; i < j; ++i )
97 std::sqrt( 123.456L ); // burn some time
98
99 return 0;
100 }
101 int main() {
102 f1(100000);
103 f1(200000);
104 f1(300000);
105 return 0;
106 }
107
108 Will produce the following output
109
110 3 times, sum=0.034s, min=0.006s, max=0.017s, mean=0.011s
111
112
113 [endsect]
114
115
116
117 [section:function How can I prefix each report with `BOOST_CURRENT_FUNCTION` function signature?]
118
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.
120
121 For example, for a __stopclock_accumulator the default formatter is __stopwatch_accumulator_formatter, you will need to do something like:
122
123 static __stopclock_accumulator<> acc(
124 std::string(BOOST_CURRENT_FUNCTION) + ": "
125 + __stopwatch_accumulator_formatter::default_format()
126 );
127 __stopclock_accumulator<>::scoped_run _(acc);
128
129
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
131
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() \
137 ); \
138 boost::stopwatches::__stopclock_accumulator<>::scoped_run \
139 BOOST_JOIN(_accumulator_run_, __LINE__) \
140 (BOOST_JOIN(_accumulator_, __LINE__))
141
142
143 With this macro you will just have to write
144
145 void foo()
146 {
147 REPORT_FUNCTION_ACCUMULATED_LIFETIME() ;
148 boost::this_thread::sleep(boost::posix_time::milliseconds(100));
149 // ...
150 }
151
152 [endsect]
153
154 [section:file_line How can I prefix each report with `__FILE__[__LINE__]` pattern?]
155
156 When you want to prefix with the `__FILE__[__LINE__]` pattern you can follow the same technique as described below:
157
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() \
163 ); \
164 __stopclock_accumulator<>::scoped_run \
165 BOOST_JOIN(_accumulator_run_, __LINE__)
166 (BOOST_JOIN(_accumulator_, __LINE__))
167
168 Now you can mix fcntion and line reports as follows
169
170 void foo()
171 {
172 REPORT_FUNCTION_ACCUMULATED_LIFETIME;
173 boost::this_thread::sleep(boost::posix_time::milliseconds(100));
174 {
175 REPORT_LINE_ACCUMULATED_LIFETIME;
176 boost::this_thread::sleep(boost::posix_time::milliseconds(200));
177 }
178
179 }
180
181 [endsect]
182
183 [section:non_static_acc Can I use an stopclock accumulator which is not static?]
184
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.
187
188 __stopclock_accumulator<> acc(
189 std::string(__FILE__) + "[" + BOOST_STRINGIZE(__LINE__) + "] "
190 + __stopwatch_accumulator_formatter::default_format()
191 );
192 for (int i=0; i<N; i++) {
193 __stopclock_accumulator<>::scoped_run _(acc);
194 // ...
195 }
196
197
198 [endsect]
199
200 [section:suspend How can I suspend a stopwatch?]
201
202 #include <boost/stopwatches/stopwatch.hpp>
203 #include <cmath>
204 #include <boost/thread.hpp>
205
206
207 using namespace boost::stopwatches;
208 double res;
209 void f1(long j)
210 {
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));
216 }
217
218 [endsect]
219
220 [section:stats How to get specific statistics from stopwatches accumulator?]
221
222 There are two use cases that coul need to change the statistics associated to a stopwatches accumulator:
223
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
226
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.
228
229 using namespace boost::accumulators;
230
231 typedef __stopwatch_reporter<__laps_stopwatch<__process_real_cpu_clock__,
232 accumulator_set<__process_real_cpu_clock__::rep,
233 features<
234 tag::count,
235 tag::sum,
236 tag::mean
237 >
238 >
239 > my_stopwatch_accumulator_reporter;
240
241 int f1(long j)
242 {
243 static my_stopwatch_accumulator_reporter acc("%c times, sum=%ss, mean=%as\n");
244 my_stopwatch_accumulator_reporter::scoped_run _(acc);
245
246 for ( long i = 0; i < j; ++i )
247 std::sqrt( 123.456L ); // burn some time
248
249 return 0;
250 }
251
252 But what would hapend if we haven't forced the format:
253
254 static my_stopwatch_accumulator_reporter acc;
255 my_stopwatch_accumulator_reporter::scoped_run _(acc);
256
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.
258
259
260 [endsect]
261
262 [section Formatting]
263
264 [section:other How can I make a specific formatter when the default do not satisfy my expectations]
265
266 Imagine then that we want to report the `tag::variance(lazy)`. We will need to include the specific accumulator file
267
268 ...
269 #include <boost/accumulators/statistics/variance.hpp>
270 ...
271 typedef __stopwatch_reporter<__laps_stopwatch<__process_real_cpu_clock__,
272 accumulator_set<__process_real_cpu_clock__::rep,
273 features<
274 tag::count,
275 tag::sum,
276 tag::mean,
277 tag::variance(lazy)
278 >
279 >
280 > my_stopwatch_accumulator_reporter;
281
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.
283
284 typedef __stopwatch_reporter<__laps_stopwatch<__process_real_cpu_clock__,
285 accumulator_set<__process_real_cpu_clock__::rep,
286 features<
287 tag::count,
288 tag::sum,
289 tag::mean,
290 tag::variance(lazy)
291 >
292 >,
293 my_stopwatch_accumulator_formatter
294 > my_stopwatch_accumulator_reporter;
295
296 Next follow the definition of a formatter taking care of count, sum, mean and variance
297
298 class my_stopwatch_accumulator_formatter {
299 public:
300 typedef std::string string_type;
301 typedef char char_type;
302 typedef std::ostream ostream_type;
303
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";
307 }
308 static int default_places() { return 3; }
309
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)
313 {
314 typedef typename Stopwatch::duration duration_t;
315 typename Stopwatch::accumulator accumulator& acc = stopwatch_.accumulated();
316
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 );
321
322 for ( ; *format; ++format ) {
323 if ( *format != '%' || !*(format+1) || !std::strchr("acsv", *(format+1)) ) {
324 os << *format;
325 } else {
326 ++format;
327 switch ( *format ) {
328 case 's':
329 os << boost::chrono::duration<double>(
330 duration_t(accumulators::sum(acc))).count();
331 break;
332 case 'a':
333 os << (accumulators::count(acc)>0)
334 ? boost::chrono::__duration__<double>(duration_t(
335 duration_t::rep(accumulators::mean(acc)))).count()
336 : 0;
337 break;
338 case 'c':
339 os << accumulators::count(acc);
340 break;
341 case 'v':
342 os << (accumulators::count(acc)>0)
343 ? boost::chrono::__duration__<double>(duration_t(
344 duration_t::rep(accumulators::variance(acc)))).count()
345 : 0;
346 break;
347 default:
348 assert(0 && "my_stopwatch_accumulator_formatter internal logic error");
349 }
350 }
351 }
352 }
353 };
354
355
356
357 [endsect]
358
359
360 [endsect]
361 [endsect]
362
363 [/===============]
364 [/section Examples]
365 [/===============]
366
367
368
369