1 /***************************************************************************
2 * include/stxxl/bits/io/iostats.h
3 *
4 * Part of the STXXL. See http://stxxl.sourceforge.net
5 *
6 * Copyright (C) 2002-2004 Roman Dementiev <dementiev@mpi-sb.mpg.de>
7 * Copyright (C) 2008-2010 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
8 * Copyright (C) 2009, 2010 Johannes Singler <singler@kit.edu>
9 *
10 * Distributed under the Boost Software License, Version 1.0.
11 * (See accompanying file LICENSE_1_0.txt or copy at
12 * http://www.boost.org/LICENSE_1_0.txt)
13 **************************************************************************/
14
15 #ifndef STXXL_IO_IOSTATS_HEADER
16 #define STXXL_IO_IOSTATS_HEADER
17
18 #ifndef STXXL_IO_STATS
19 #define STXXL_IO_STATS 1
20 #endif
21
22 #include <stxxl/bits/namespace.h>
23 #include <stxxl/bits/deprecated.h>
24 #include <stxxl/bits/common/mutex.h>
25 #include <stxxl/bits/common/timer.h>
26 #include <stxxl/bits/common/types.h>
27 #include <stxxl/bits/common/utils.h>
28 #include <stxxl/bits/unused.h>
29 #include <stxxl/bits/singleton.h>
30
31 #include <iostream>
32 #include <string>
33
34 STXXL_BEGIN_NAMESPACE
35
36 //! \addtogroup iolayer
37 //!
38 //! \{
39
40 //! Collects various I/O statistics.
41 //! \remarks is a singleton
42 class stats : public singleton<stats>
43 {
44 friend class singleton<stats>;
45
46 unsigned reads, writes; // number of operations
47 int64 volume_read, volume_written; // number of bytes read/written
48 unsigned c_reads, c_writes; // number of cached operations
49 int64 c_volume_read, c_volume_written; // number of bytes read/written from/to cache
50 double t_reads, t_writes; // seconds spent in operations
51 double p_reads, p_writes; // seconds spent in parallel operations
52 double p_begin_read, p_begin_write; // start time of parallel operation
53 double p_ios; // seconds spent in all parallel I/O operations (read and write)
54 double p_begin_io;
55 double t_waits, p_waits; // seconds spent waiting for completion of I/O operations
56 double p_begin_wait;
57 double t_wait_read, p_wait_read;
58 double p_begin_wait_read;
59 double t_wait_write, p_wait_write;
60 double p_begin_wait_write;
61 int acc_reads, acc_writes; // number of requests, participating in parallel operation
62 int acc_ios;
63 int acc_waits;
64 int acc_wait_read, acc_wait_write;
65 double last_reset;
66 mutex read_mutex, write_mutex, io_mutex, wait_mutex;
67
68 stats();
69
70 public:
71 enum wait_op_type {
72 WAIT_OP_ANY,
73 WAIT_OP_READ,
74 WAIT_OP_WRITE
75 };
76
77 class scoped_read_write_timer
78 {
79 typedef unsigned_type size_type;
80
81 bool is_write;
82 #if STXXL_IO_STATS
83 bool running;
84 #endif
85
86 public:
87 scoped_read_write_timer(size_type size, bool is_write = false)
is_write(is_write)88 : is_write(is_write)
89 #if STXXL_IO_STATS
90 , running(false)
91 #endif
92 {
93 start(size);
94 }
95
~scoped_read_write_timer()96 ~scoped_read_write_timer()
97 {
98 stop();
99 }
100
start(size_type size)101 void start(size_type size)
102 {
103 #if STXXL_IO_STATS
104 if (!running) {
105 running = true;
106 if (is_write)
107 stats::get_instance()->write_started(size);
108 else
109 stats::get_instance()->read_started(size);
110 }
111 #else
112 STXXL_UNUSED(size);
113 #endif
114 }
115
stop()116 void stop()
117 {
118 #if STXXL_IO_STATS
119 if (running) {
120 if (is_write)
121 stats::get_instance()->write_finished();
122 else
123 stats::get_instance()->read_finished();
124 running = false;
125 }
126 #endif
127 }
128 };
129
130 class scoped_write_timer
131 {
132 typedef unsigned_type size_type;
133
134 #if STXXL_IO_STATS
135 bool running;
136 #endif
137
138 public:
scoped_write_timer(size_type size)139 scoped_write_timer(size_type size)
140 #if STXXL_IO_STATS
141 : running(false)
142 #endif
143 {
144 start(size);
145 }
146
~scoped_write_timer()147 ~scoped_write_timer()
148 {
149 stop();
150 }
151
start(size_type size)152 void start(size_type size)
153 {
154 #if STXXL_IO_STATS
155 if (!running) {
156 running = true;
157 stats::get_instance()->write_started(size);
158 }
159 #else
160 STXXL_UNUSED(size);
161 #endif
162 }
163
stop()164 void stop()
165 {
166 #if STXXL_IO_STATS
167 if (running) {
168 stats::get_instance()->write_finished();
169 running = false;
170 }
171 #endif
172 }
173 };
174
175 class scoped_read_timer
176 {
177 typedef unsigned_type size_type;
178
179 #if STXXL_IO_STATS
180 bool running;
181 #endif
182
183 public:
scoped_read_timer(size_type size)184 scoped_read_timer(size_type size)
185 #if STXXL_IO_STATS
186 : running(false)
187 #endif
188 {
189 start(size);
190 }
191
~scoped_read_timer()192 ~scoped_read_timer()
193 {
194 stop();
195 }
196
start(size_type size)197 void start(size_type size)
198 {
199 #if STXXL_IO_STATS
200 if (!running) {
201 running = true;
202 stats::get_instance()->read_started(size);
203 }
204 #else
205 STXXL_UNUSED(size);
206 #endif
207 }
208
stop()209 void stop()
210 {
211 #if STXXL_IO_STATS
212 if (running) {
213 stats::get_instance()->read_finished();
214 running = false;
215 }
216 #endif
217 }
218 };
219
220 class scoped_wait_timer
221 {
222 #ifndef STXXL_DO_NOT_COUNT_WAIT_TIME
223 bool running;
224 wait_op_type wait_op;
225 #endif
226
227 public:
228 scoped_wait_timer(wait_op_type wait_op, bool measure_time = true)
229 #ifndef STXXL_DO_NOT_COUNT_WAIT_TIME
running(false)230 : running(false), wait_op(wait_op)
231 #endif
232 {
233 if (measure_time)
234 start();
235 }
236
~scoped_wait_timer()237 ~scoped_wait_timer()
238 {
239 stop();
240 }
241
start()242 void start()
243 {
244 #ifndef STXXL_DO_NOT_COUNT_WAIT_TIME
245 if (!running) {
246 running = true;
247 stats::get_instance()->wait_started(wait_op);
248 }
249 #endif
250 }
251
stop()252 void stop()
253 {
254 #ifndef STXXL_DO_NOT_COUNT_WAIT_TIME
255 if (running) {
256 stats::get_instance()->wait_finished(wait_op);
257 running = false;
258 }
259 #endif
260 }
261 };
262
263 public:
264 //! Returns total number of reads.
265 //! \return total number of reads
get_reads()266 unsigned get_reads() const
267 {
268 return reads;
269 }
270
271 //! Returns total number of writes.
272 //! \return total number of writes
get_writes()273 unsigned get_writes() const
274 {
275 return writes;
276 }
277
278 //! Returns number of bytes read from disks.
279 //! \return number of bytes read
get_read_volume()280 int64 get_read_volume() const
281 {
282 return volume_read;
283 }
284
285 //! Returns number of bytes written to the disks.
286 //! \return number of bytes written
get_written_volume()287 int64 get_written_volume() const
288 {
289 return volume_written;
290 }
291
292 //! Returns total number of reads served from cache.
293 //! \return total number of cached reads
get_cached_reads()294 unsigned get_cached_reads() const
295 {
296 return c_reads;
297 }
298
299 //! Returns total number of cached writes.
300 //! \return total number of cached writes
get_cached_writes()301 unsigned get_cached_writes() const
302 {
303 return c_writes;
304 }
305
306 //! Returns number of bytes read from cache.
307 //! \return number of bytes read from cache
get_cached_read_volume()308 int64 get_cached_read_volume() const
309 {
310 return c_volume_read;
311 }
312
313 //! Returns number of bytes written to the cache.
314 //! \return number of bytes written to cache
get_cached_written_volume()315 int64 get_cached_written_volume() const
316 {
317 return c_volume_written;
318 }
319
320 //! Time that would be spent in read syscalls if all parallel reads were serialized.
321 //! \return seconds spent in reading
get_read_time()322 double get_read_time() const
323 {
324 return t_reads;
325 }
326
327 //! Time that would be spent in write syscalls if all parallel writes were serialized.
328 //! \return seconds spent in writing
get_write_time()329 double get_write_time() const
330 {
331 return t_writes;
332 }
333
334 //! Period of time when at least one I/O thread was executing a read.
335 //! \return seconds spent in reading
get_pread_time()336 double get_pread_time() const
337 {
338 return p_reads;
339 }
340
341 //! Period of time when at least one I/O thread was executing a write.
342 //! \return seconds spent in writing
get_pwrite_time()343 double get_pwrite_time() const
344 {
345 return p_writes;
346 }
347
348 //! Period of time when at least one I/O thread was executing a read or a write.
349 //! \return seconds spent in I/O
get_pio_time()350 double get_pio_time() const
351 {
352 return p_ios;
353 }
354
355 //! I/O wait time counter.
356 //! \return number of seconds spent in I/O waiting functions \link
357 //! request::wait request::wait \endlink, \c wait_any and \c wait_all
get_io_wait_time()358 double get_io_wait_time() const
359 {
360 return t_waits;
361 }
362
get_wait_read_time()363 double get_wait_read_time() const
364 {
365 return t_wait_read;
366 }
367
get_wait_write_time()368 double get_wait_write_time() const
369 {
370 return t_wait_write;
371 }
372
373 //! Return time of the last reset.
374 //! \return seconds passed from the last reset()
get_last_reset_time()375 double get_last_reset_time() const
376 {
377 return last_reset;
378 }
379
380 #ifndef STXXL_IO_STATS_RESET_FORBIDDEN
381 //! Resets I/O time counters (including I/O wait counter).
382 STXXL_DEPRECATED(void reset());
383 #endif
384
385 //! Resets I/O wait time counter.
386 STXXL_DEPRECATED(void _reset_io_wait_time());
387
388 // for library use
389 void write_started(unsigned_type size_, double now = 0.0);
390 void write_canceled(unsigned_type size_);
391 void write_finished();
392 void write_cached(unsigned_type size_);
393 void read_started(unsigned_type size_, double now = 0.0);
394 void read_canceled(unsigned_type size_);
395 void read_finished();
396 void read_cached(unsigned_type size_);
397 void wait_started(wait_op_type wait_op);
398 void wait_finished(wait_op_type wait_op);
399 };
400
401 #if !STXXL_IO_STATS
write_started(unsigned_type size_,double now)402 inline void stats::write_started(unsigned_type size_, double now)
403 {
404 STXXL_UNUSED(size_);
405 STXXL_UNUSED(now);
406 }
write_cached(unsigned_type size_)407 inline void stats::write_cached(unsigned_type size_)
408 {
409 STXXL_UNUSED(size_);
410 }
write_finished()411 inline void stats::write_finished() { }
read_started(unsigned_type size_,double now)412 inline void stats::read_started(unsigned_type size_, double now)
413 {
414 STXXL_UNUSED(size_);
415 STXXL_UNUSED(now);
416 }
read_cached(unsigned_type size_)417 inline void stats::read_cached(unsigned_type size_)
418 {
419 STXXL_UNUSED(size_);
420 }
read_finished()421 inline void stats::read_finished() { }
422 #endif
423 #ifdef STXXL_DO_NOT_COUNT_WAIT_TIME
wait_started(wait_op_type)424 inline void stats::wait_started(wait_op_type) { }
wait_finished(wait_op_type)425 inline void stats::wait_finished(wait_op_type) { }
426 #endif
427
428 class stats_data
429 {
430 //! number of operations
431 unsigned reads, writes;
432 //! number of bytes read/written
433 int64 volume_read, volume_written;
434 //! number of cached operations
435 unsigned c_reads, c_writes;
436 //! number of bytes read/written from/to cache
437 int64 c_volume_read, c_volume_written;
438 //! seconds spent in operations
439 double t_reads, t_writes;
440 //! seconds spent in parallel operations
441 double p_reads, p_writes;
442 //! seconds spent in all parallel I/O operations (read and write)
443 double p_ios;
444 //! seconds spent waiting for completion of I/O operations
445 double t_wait;
446 double t_wait_read, t_wait_write;
447 double elapsed;
448
449 public:
stats_data()450 stats_data()
451 : reads(0),
452 writes(0),
453 volume_read(0),
454 volume_written(0),
455 c_reads(0),
456 c_writes(0),
457 c_volume_read(0),
458 c_volume_written(0),
459 t_reads(0.0),
460 t_writes(0.0),
461 p_reads(0.0),
462 p_writes(0.0),
463 p_ios(0.0),
464 t_wait(0.0),
465 t_wait_read(0.0),
466 t_wait_write(0.0),
467 elapsed(0.0)
468 { }
469
stats_data(const stats & s)470 stats_data(const stats& s)
471 : reads(s.get_reads()),
472 writes(s.get_writes()),
473 volume_read(s.get_read_volume()),
474 volume_written(s.get_written_volume()),
475 c_reads(s.get_cached_reads()),
476 c_writes(s.get_cached_writes()),
477 c_volume_read(s.get_cached_read_volume()),
478 c_volume_written(s.get_cached_written_volume()),
479 t_reads(s.get_read_time()),
480 t_writes(s.get_write_time()),
481 p_reads(s.get_pread_time()),
482 p_writes(s.get_pwrite_time()),
483 p_ios(s.get_pio_time()),
484 t_wait(s.get_io_wait_time()),
485 t_wait_read(s.get_wait_read_time()),
486 t_wait_write(s.get_wait_write_time()),
487 elapsed(timestamp() - s.get_last_reset_time())
488 { }
489
490 stats_data operator + (const stats_data& a) const
491 {
492 stats_data s;
493 s.reads = reads + a.reads;
494 s.writes = writes + a.writes;
495 s.volume_read = volume_read + a.volume_read;
496 s.volume_written = volume_written + a.volume_written;
497 s.c_reads = c_reads + a.c_reads;
498 s.c_writes = c_writes + a.c_writes;
499 s.c_volume_read = c_volume_read + a.c_volume_read;
500 s.c_volume_written = c_volume_written + a.c_volume_written;
501 s.t_reads = t_reads + a.t_reads;
502 s.t_writes = t_writes + a.t_writes;
503 s.p_reads = p_reads + a.p_reads;
504 s.p_writes = p_writes + a.p_writes;
505 s.p_ios = p_ios + a.p_ios;
506 s.t_wait = t_wait + a.t_wait;
507 s.t_wait_read = t_wait_read + a.t_wait_read;
508 s.t_wait_write = t_wait_write + a.t_wait_write;
509 s.elapsed = elapsed + a.elapsed;
510 return s;
511 }
512
513 stats_data operator - (const stats_data& a) const
514 {
515 stats_data s;
516 s.reads = reads - a.reads;
517 s.writes = writes - a.writes;
518 s.volume_read = volume_read - a.volume_read;
519 s.volume_written = volume_written - a.volume_written;
520 s.c_reads = c_reads - a.c_reads;
521 s.c_writes = c_writes - a.c_writes;
522 s.c_volume_read = c_volume_read - a.c_volume_read;
523 s.c_volume_written = c_volume_written - a.c_volume_written;
524 s.t_reads = t_reads - a.t_reads;
525 s.t_writes = t_writes - a.t_writes;
526 s.p_reads = p_reads - a.p_reads;
527 s.p_writes = p_writes - a.p_writes;
528 s.p_ios = p_ios - a.p_ios;
529 s.t_wait = t_wait - a.t_wait;
530 s.t_wait_read = t_wait_read - a.t_wait_read;
531 s.t_wait_write = t_wait_write - a.t_wait_write;
532 s.elapsed = elapsed - a.elapsed;
533 return s;
534 }
535
get_reads()536 unsigned get_reads() const
537 {
538 return reads;
539 }
540
get_writes()541 unsigned get_writes() const
542 {
543 return writes;
544 }
545
get_read_volume()546 int64 get_read_volume() const
547 {
548 return volume_read;
549 }
550
get_written_volume()551 int64 get_written_volume() const
552 {
553 return volume_written;
554 }
555
get_cached_reads()556 unsigned get_cached_reads() const
557 {
558 return c_reads;
559 }
560
get_cached_writes()561 unsigned get_cached_writes() const
562 {
563 return c_writes;
564 }
565
get_cached_read_volume()566 int64 get_cached_read_volume() const
567 {
568 return c_volume_read;
569 }
570
get_cached_written_volume()571 int64 get_cached_written_volume() const
572 {
573 return c_volume_written;
574 }
575
get_read_time()576 double get_read_time() const
577 {
578 return t_reads;
579 }
580
get_write_time()581 double get_write_time() const
582 {
583 return t_writes;
584 }
585
get_pread_time()586 double get_pread_time() const
587 {
588 return p_reads;
589 }
590
get_pwrite_time()591 double get_pwrite_time() const
592 {
593 return p_writes;
594 }
595
get_pio_time()596 double get_pio_time() const
597 {
598 return p_ios;
599 }
600
get_elapsed_time()601 double get_elapsed_time() const
602 {
603 return elapsed;
604 }
605
get_io_wait_time()606 double get_io_wait_time() const
607 {
608 return t_wait;
609 }
610
get_wait_read_time()611 double get_wait_read_time() const
612 {
613 return t_wait_read;
614 }
615
get_wait_write_time()616 double get_wait_write_time() const
617 {
618 return t_wait_write;
619 }
620 };
621
622 std::ostream& operator << (std::ostream& o, const stats_data& s);
623
624 inline std::ostream& operator << (std::ostream& o, const stats& s)
625 {
626 o << stxxl::stats_data(s);
627 return o;
628 }
629
630 std::string format_with_SI_IEC_unit_multiplier(uint64 number, const char* unit = "", int multiplier = 1000);
631
632 inline std::string add_IEC_binary_multiplier(uint64 number, const char* unit = "")
633 {
634 return format_with_SI_IEC_unit_multiplier(number, unit, 1024);
635 }
636
637 inline std::string add_SI_multiplier(uint64 number, const char* unit = "")
638 {
639 return format_with_SI_IEC_unit_multiplier(number, unit, 1000);
640 }
641
642 //! \}
643
644 STXXL_END_NAMESPACE
645
646 #endif // !STXXL_IO_IOSTATS_HEADER
647 // vim: et:ts=4:sw=4
648