initial commit
[camargo/libcamargoutils.git] / include / camargoutils / proctimer.h
1 /**
2  * @file proctimer.h
3  * @brief Simple utility class to time sections of an execution with minimum 
4  *        overhead and good precision, using monotonic system clock deltas
5  * @author Lucas Pires Camargo 
6  * @copyright Public domain.
7  */
8
9 #pragma once
10
11 #include <vector>
12 #include <utility>
13 #include <cstdio>
14
15 #include <stdint.h> // i`d use cstdint but that is c++11
16 #include <time.h> // not std::chrono::steady_clock cause thats also c++11
17
18 namespace camargo {
19
20 class proctimer
21 {
22 public:
23     static const int CLOCK_DEF = CLOCK_MONOTONIC;
24     
25     proctimer()
26     {
27         m_total = 0;
28         
29         struct timespec ts;
30         clock_getres(CLOCK_DEF, &ts);
31         
32         m_precision = timespec_to_micros(&ts);
33     }
34     
35     ~proctimer()
36     {
37         // nothing to do here for now
38     }
39     
40     typedef std::pair< const char*, uint64_t > section_timing;
41     typedef std::vector<section_timing> timings;
42     
43     void clear() 
44     { 
45         m_timings.clear(); 
46     }
47     
48     void begin_section(const char *sectionName)
49     {
50         uint64_t now = get_now();
51         
52         if(m_timings.size())
53         {
54             // finish up previous timing
55             section_timing &last = m_timings[m_timings.size() - 1];
56             last.second = now - last.second;
57         }
58         
59         m_timings.push_back(section_timing(sectionName, now));
60     }
61     
62     void finish()
63     {
64         if(!m_timings.size())
65         {
66             m_total = 0;
67             return;
68         }
69         
70         // finish up last item
71         uint64_t now = get_now();
72         section_timing &last = m_timings[m_timings.size() - 1];
73         last.second = now - last.second;
74         
75         // now, calculate total time
76         uint64_t total_micros = 0;
77         for(timings::iterator it =m_timings.begin(); it < m_timings.end(); it++)
78         {
79             total_micros += it->second;
80         }
81         
82         m_total = total_micros;
83     }
84     
85     uint64_t get_total_micros()
86     {
87         return m_total;
88     }
89     
90     timings get_timings() 
91     {
92         return m_timings;
93     }
94     
95     void output_report(int fd, bool detailed = true)
96     {
97         // fd is the file descriptor
98         dprintf(fd, "\n================\nproctimer report\n");
99         dprintf(fd, "total time: %f ms\n", m_total/1000.0f);
100         
101         if(!detailed) return;
102         
103         dprintf(fd, "clock precision: %f ms\n", m_precision/1000.0f);
104         
105         for(timings::iterator it =m_timings.begin(); it < m_timings.end(); it++)
106         {
107             
108             dprintf(fd, "section '%s': %f ms\n", it->first, (it->second)/1000.0f);
109         }
110         
111     }
112     
113 private:
114     static uint64_t timespec_to_micros( struct timespec *ts )
115     {
116         return ts->tv_sec * 1e6 + ts->tv_nsec/1000;
117     }
118     
119     uint64_t get_now()
120     {
121         struct timespec ts;
122         int ret = clock_gettime(CLOCK_DEF, &ts);
123         
124         if(!ret)
125         {
126             return timespec_to_micros(&ts);
127         }
128         else return -1;
129     }
130     
131     timings m_timings;
132     uint64_t m_total;
133     uint64_t m_precision;
134 };
135
136 }