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