|
19 | 19 | * * |
20 | 20 | * Contact information: contact@sofa-framework.org * |
21 | 21 | ******************************************************************************/ |
22 | | -#ifndef SOFA_HELPER_SIMPLETIMER_H |
23 | | -#define SOFA_HELPER_SIMPLETIMER_H |
| 22 | +#pragma once |
24 | 23 |
|
25 | | -#include <sofa/helper/system/thread/CTime.h> |
| 24 | +#include <chrono> |
| 25 | +#include <string> |
| 26 | + |
| 27 | +#include <sofa/helper/logging/Messaging.h> |
26 | 28 |
|
27 | 29 | namespace sofa::helper |
28 | 30 | { |
| 31 | +template<class Unit> |
| 32 | +struct UnitInfo; |
29 | 33 |
|
30 | | -/** |
31 | | - Very simple timer |
32 | | -
|
33 | | - Usage example : |
34 | | -
|
35 | | - sofa::helper::SimpleTimer mytimer; |
36 | | -
|
37 | | - void myComputationCode() { |
38 | | -
|
39 | | - bool timer = true; // should I print performance stats |
40 | | - if (timer) mytimer.start("mystep1); |
41 | | -
|
42 | | - ... // step 1 code |
43 | | -
|
44 | | - if (timer) mytimer.step("mystep2"); |
| 34 | +template<> struct UnitInfo<std::chrono::nanoseconds> |
| 35 | +{ |
| 36 | + static constexpr std::string_view unit = "ns"; |
| 37 | +}; |
45 | 38 |
|
46 | | - ... // step 2 code |
| 39 | +template<> struct UnitInfo<std::chrono::microseconds> |
| 40 | +{ |
| 41 | + static constexpr std::string_view unit = "us"; |
| 42 | +}; |
47 | 43 |
|
48 | | - if (timer) mytimer.stop(); |
49 | | - } |
| 44 | +template<> struct UnitInfo<std::chrono::milliseconds> |
| 45 | +{ |
| 46 | + static constexpr std::string_view unit = "ms"; |
| 47 | +}; |
50 | 48 |
|
| 49 | +template<> struct UnitInfo<std::chrono::seconds> |
| 50 | +{ |
| 51 | + static constexpr std::string_view unit = "s"; |
| 52 | +}; |
51 | 53 |
|
| 54 | +/** |
| 55 | + * @class SimpleTimer |
| 56 | + * @brief A RAII utility class for measuring elapsed time in operations and log it. |
| 57 | + * |
| 58 | + * @code |
| 59 | + * // Measure a block of code |
| 60 | + * { |
| 61 | + * sofa::helper::SimpleTimer<std::chrono::milliseconds> timer("File I/O Simulation"); |
| 62 | + * // ... Simulate file reading/writing here ... |
| 63 | + * // The elapsed time is logged by the timer at the end of the scope |
| 64 | + * } |
| 65 | + * @endcode |
52 | 66 | */ |
53 | | - |
54 | | -template<int nIter=100, int nStep=100> |
55 | | -class TSimpleTimer |
| 67 | +template<class Unit = std::chrono::nanoseconds> |
| 68 | +struct SimpleTimer |
56 | 69 | { |
57 | | -public: |
58 | | - |
59 | | - enum {T_NSTEPS=nStep, T_NITERS=nIter}; |
60 | | - |
61 | | - typedef sofa::helper::system::thread::ctime_t ctime_t; |
62 | | - typedef sofa::helper::system::thread::CTime CTime; |
63 | | - |
64 | | - ctime_t timer_total; |
65 | | - ctime_t timer_current; |
66 | | - ctime_t timer_freq; |
67 | | - ctime_t timer_start; |
68 | | - ctime_t timers_start; |
69 | | - const char* timers_name[T_NSTEPS]; |
70 | | - ctime_t timers_total[T_NSTEPS]; |
71 | | - ctime_t timers_current[T_NSTEPS]; |
72 | | - int timer_niter; |
73 | | - int timer_nstep; |
74 | | - const char* timer_lastname; |
75 | | - |
76 | | - TSimpleTimer() |
77 | | - { |
78 | | - timer_total = 0; |
79 | | - timer_current = 0; |
80 | | - timer_freq = 1; |
81 | | - timer_start = 0; |
82 | | - timers_start = 0; |
83 | | - timer_niter = 0; |
84 | | - timer_nstep = 0; |
85 | | - timer_lastname = ""; |
86 | | - } |
| 70 | + std::string m_name; |
| 71 | + std::chrono::time_point<std::chrono::high_resolution_clock> m_start; |
| 72 | + bool hasEnded { false }; |
| 73 | + |
| 74 | + explicit SimpleTimer(const std::string& name) |
| 75 | + : m_name(name) |
| 76 | + , m_start(std::chrono::high_resolution_clock::now()) |
| 77 | + {} |
87 | 78 |
|
88 | | - void start(const char* name) |
| 79 | + ~SimpleTimer() |
89 | 80 | { |
90 | | - if (timer_niter == 0) |
91 | | - { |
92 | | - timer_total = 0; |
93 | | - timer_current = 0; |
94 | | - timer_freq = CTime::getTicksPerSec(); |
95 | | - for (int i=0; i<T_NSTEPS; ++i) timers_name[i] = ""; |
96 | | - for (int i=0; i<T_NSTEPS; ++i) timers_total[i] = 0; |
97 | | - for (int i=0; i<T_NSTEPS; ++i) timers_current[i] = 0; |
98 | | - } |
99 | | - const ctime_t t = CTime::getTime(); |
100 | | - timer_start = t; |
101 | | - timers_start = t; |
102 | | - timer_nstep = 0; |
103 | | - timer_lastname = name; |
| 81 | + stop(); |
104 | 82 | } |
105 | 83 |
|
106 | | - void step(const char* name = "") |
| 84 | + void restart() |
107 | 85 | { |
108 | | - if (timer_nstep >= T_NSTEPS) return; |
109 | | - int i = timer_nstep; |
110 | | - { |
111 | | - timers_name[i] = timer_lastname; |
112 | | - timer_lastname = name; |
113 | | - } |
114 | | - const ctime_t t = CTime::getTime(); |
115 | | - timers_current[i] = t - timers_start; |
116 | | - timers_start = t; |
117 | | - timers_total[i] += timers_current[i]; |
118 | | - ++timer_nstep; |
| 86 | + m_start = std::chrono::high_resolution_clock::now(); |
119 | 87 | } |
120 | 88 |
|
121 | 89 | void stop() |
122 | 90 | { |
123 | | - step(); |
124 | | - ++timer_niter; |
125 | | - const ctime_t t = CTime::getTime(); |
126 | | - timer_current = t - timer_start; |
127 | | - timer_total += timer_current; |
128 | | - timer_start = t; |
129 | | - timers_start = t; |
130 | | - if (timer_niter > 0 && (timer_niter % T_NITERS) == 0) |
| 91 | + if (!hasEnded) |
131 | 92 | { |
132 | | - std::stringstream tmpmsg ; |
133 | | - tmpmsg << "TIMER after " << timer_niter << " iterations :" << msgendl; |
134 | | - for (int i=0; i<T_NSTEPS; ++i) |
135 | | - { |
136 | | - if (timers_total[i]) |
137 | | - { |
138 | | - double tcur = 1000.0 * (double)timers_current[i] / (double) timer_freq; |
139 | | - double ttot = 1000.0 * (double)timers_total[i] / (double) (timer_niter * timer_freq); |
140 | | - tmpmsg << " " << i << ". " << timers_name[i] << "\t : " << std::fixed << (tcur < 10 ? " " : tcur < 100 ? " " : tcur < 1000 ? " " : "") << tcur << " \tms ( mean " << (ttot < 10 ? " " : ttot < 100 ? " " : ttot < 1000 ? " " : "") << ttot << " \tms ) " << msgendl; |
141 | | - } |
142 | | - } |
143 | | - double tcur = 1000.0 * (double)timer_current / (double) timer_freq; |
144 | | - double ttot = 1000.0 * (double)timer_total / (double) (timer_niter * timer_freq); |
145 | | - tmpmsg << "** TOTAL *********\t : " << std::fixed << (tcur < 10 ? " " : tcur < 100 ? " " : tcur < 1000 ? " " : "") << tcur << " \tms ( mean " << (ttot < 10 ? " " : ttot < 100 ? " " : ttot < 1000 ? " " : "") << ttot << " \tms ) " ; |
146 | | - msg_info("SimpleTimer") << tmpmsg.str() ; |
| 93 | + auto end = std::chrono::high_resolution_clock::now(); |
| 94 | + msg_info("Timer") << m_name << " took " << std::chrono::duration_cast<Unit>(end - m_start).count() << UnitInfo<Unit>::unit; |
| 95 | + hasEnded = true; |
147 | 96 | } |
148 | 97 | } |
149 | | -}; |
150 | 98 |
|
151 | | -typedef TSimpleTimer<> SimpleTimer; |
| 99 | + |
| 100 | +}; |
152 | 101 |
|
153 | 102 | } |
154 | 103 |
|
155 | | -#endif |
0 commit comments