Directory: | ./ |
---|---|
File: | src/timer.cpp |
Date: | 2022-06-29 13:58:11 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 82 | 100 | 82.0% |
Branches: | 46 | 90 | 51.1% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * @file timer.cpp | ||
3 | * @author Maximilien Naveau (maximilien.naveau@gmail.com) | ||
4 | * license License BSD-3-Clause | ||
5 | * @copyright Copyright (c) 2019, New York University and Max Planck | ||
6 | * Gesellschaft. | ||
7 | * @date 2019-05-22 | ||
8 | * | ||
9 | * @brief This file implements tools to acquire the time, the date, | ||
10 | * and do timing measurement | ||
11 | */ | ||
12 | |||
13 | #include <time.h> | ||
14 | #include <fstream> | ||
15 | #include <iomanip> | ||
16 | #include <real_time_tools/iostream.hpp> | ||
17 | #include <real_time_tools/timer.hpp> | ||
18 | #include <sstream> | ||
19 | |||
20 | namespace real_time_tools | ||
21 | { | ||
22 | /** | ||
23 | * @brief Simple renaming to get the number of days passed out of the date. | ||
24 | */ | ||
25 | typedef std::chrono::duration< | ||
26 | int, | ||
27 | std::ratio_multiply<std::chrono::hours::period, std::ratio<24> >::type> | ||
28 | days; | ||
29 | |||
30 | 1 | std::string Timer::get_current_date_str() | |
31 | { | ||
32 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | std::ostringstream oss; |
33 | 1 | auto now = std::chrono::system_clock::now(); | |
34 | 1 | std::time_t now_c = std::chrono::system_clock::to_time_t(now); | |
35 | 1 | struct tm* parts = std::localtime(&now_c); | |
36 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | oss << (int)(1900 + parts->tm_year) << "-"; |
37 |
4/8✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
|
1 | oss << std::setfill('0') << std::setw(2) << 1 + parts->tm_mon << "-"; |
38 |
4/8✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
|
1 | oss << std::setfill('0') << std::setw(2) << parts->tm_mday << "_"; |
39 |
4/8✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
|
1 | oss << std::setfill('0') << std::setw(2) << parts->tm_hour << "-"; |
40 |
4/8✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
|
1 | oss << std::setfill('0') << std::setw(2) << parts->tm_min << "-"; |
41 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
|
1 | oss << std::setfill('0') << std::setw(2) << parts->tm_sec; |
42 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | return oss.str(); |
43 | } | ||
44 | |||
45 | 1006 | Timer::Timer() | |
46 | { | ||
47 | // initialize the tic and tac times by the current time | ||
48 | 1006 | tic_time_ = std::numeric_limits<double>::quiet_NaN(); | |
49 | // initialize the memory buffer size, allocate memory and set counter to | ||
50 | // zero. | ||
51 |
1/2✓ Branch 1 taken 1006 times.
✗ Branch 2 not taken.
|
1006 | set_memory_size(60000); |
52 | // default name | ||
53 |
1/2✓ Branch 1 taken 1006 times.
✗ Branch 2 not taken.
|
1006 | name_ = "timer"; |
54 | // reset all the statistic memebers | ||
55 | 1006 | min_elapsed_time_ = std::numeric_limits<double>::infinity(); | |
56 | 1006 | max_elapsed_time_ = -std::numeric_limits<double>::infinity(); | |
57 | 1006 | avg_elapsed_time_ = 0.0; | |
58 | 1006 | second_moment_elapsed_time_ = 0.0; | |
59 | 1006 | count_ = 0; | |
60 | 1006 | } | |
61 | |||
62 | 1005 | void Timer::tic() | |
63 | { | ||
64 | // get the current time | ||
65 | 1005 | tic_time_ = Timer::get_current_time_sec(); | |
66 | 1005 | } | |
67 | |||
68 | 1005 | double Timer::tac() | |
69 | { | ||
70 | 1005 | double tac_time = Timer::get_current_time_sec(); | |
71 | 1005 | double time_interval = tac_time - tic_time_; | |
72 | |||
73 | 1005 | log_time_interval(time_interval); | |
74 | |||
75 | 1005 | return time_interval; | |
76 | } | ||
77 | |||
78 | ✗ | double Timer::tac_tic() | |
79 | { | ||
80 | ✗ | double tac_time = Timer::get_current_time_sec(); | |
81 | ✗ | double time_interval = tac_time - tic_time_; | |
82 | |||
83 | ✗ | log_time_interval(time_interval); | |
84 | |||
85 | ✗ | tic_time_ = tac_time; | |
86 | |||
87 | ✗ | return time_interval; | |
88 | } | ||
89 | |||
90 | 1005 | void Timer::log_time_interval(double time_interval) | |
91 | { | ||
92 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1005 times.
|
1005 | if (std::isnan(time_interval)) return; |
93 | |||
94 | // Only store into the buffer if the buffer is non-zero. | ||
95 |
1/2✓ Branch 0 taken 1005 times.
✗ Branch 1 not taken.
|
1005 | if (memory_buffer_size_ != 0) |
96 | { | ||
97 | // check if the buffer is full | ||
98 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1005 times.
|
1005 | if (count_ >= time_measurement_buffer_.size()) |
99 | { | ||
100 | ✗ | time_measurement_buffer_.pop_front(); | |
101 | ✗ | time_measurement_buffer_.push_back(time_interval); | |
102 | } | ||
103 | else | ||
104 | { | ||
105 | // save the current time elapsed | ||
106 | 1005 | time_measurement_buffer_[count_] = time_interval; | |
107 | } | ||
108 | } | ||
109 | |||
110 | // increase the count | ||
111 | 1005 | ++count_; | |
112 | // compute some statistics | ||
113 | 1005 | min_elapsed_time_ = | |
114 |
2/2✓ Branch 0 taken 1004 times.
✓ Branch 1 taken 1 times.
|
1005 | time_interval < min_elapsed_time_ ? time_interval : min_elapsed_time_; |
115 | 1005 | max_elapsed_time_ = | |
116 |
1/2✓ Branch 0 taken 1005 times.
✗ Branch 1 not taken.
|
1005 | time_interval > max_elapsed_time_ ? time_interval : max_elapsed_time_; |
117 | 1005 | avg_elapsed_time_ = | |
118 | 2010 | (double(count_ - 1) * avg_elapsed_time_ + time_interval) / | |
119 | 1005 | double(count_); | |
120 | 1005 | second_moment_elapsed_time_ = | |
121 | 2010 | (double(count_ - 1) * second_moment_elapsed_time_ + | |
122 | 2010 | time_interval * time_interval) / | |
123 | 1005 | double(count_); | |
124 | } | ||
125 | |||
126 | 1000 | void Timer::dump_measurements(std::string file_name) const | |
127 | { | ||
128 | try | ||
129 | { | ||
130 |
1/2✓ Branch 2 taken 1000 times.
✗ Branch 3 not taken.
|
2000 | std::ofstream log_file(file_name, std::ios::binary | std::ios::out); |
131 | 1000 | log_file.precision(10); | |
132 | 2000 | for (unsigned i = 0; | |
133 |
2/2✓ Branch 1 taken 1000 times.
✓ Branch 2 taken 1000 times.
|
2000 | i < std::min(count_, (unsigned long)memory_buffer_size_); |
134 | ++i) | ||
135 | { | ||
136 |
4/8✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1000 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1000 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1000 times.
✗ Branch 12 not taken.
|
1000 | log_file << i << " " << time_measurement_buffer_[i] << std::endl; |
137 | } | ||
138 |
1/2✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
|
1000 | log_file.flush(); |
139 |
1/2✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
|
1000 | log_file.close(); |
140 | } | ||
141 | ✗ | catch (...) | |
142 | { | ||
143 | ✗ | rt_printf( | |
144 | "fstream Error in dump_tic_tac_measurements(): " | ||
145 | "no time measurment saved\n"); | ||
146 | } | ||
147 | 1000 | } | |
148 | |||
149 | ✗ | void Timer::print_statistics() const | |
150 | { | ||
151 | ✗ | rt_printf("%s --------------------------------\n", name_.c_str()); | |
152 | ✗ | rt_printf( | |
153 | "count: %ld\n" | ||
154 | "min_elapsed_sec: %f\n" | ||
155 | "max_elapsed_sec: %f\n" | ||
156 | "avg_elapsed_sec: %f\n" | ||
157 | "std_dev_elapsed_sec: %f\n", | ||
158 | ✗ | count_, | |
159 | get_min_elapsed_sec(), | ||
160 | get_max_elapsed_sec(), | ||
161 | get_avg_elapsed_sec(), | ||
162 | get_std_dev_elapsed_sec()); | ||
163 | ✗ | rt_printf("--------------------------------------------\n"); | |
164 | } | ||
165 | |||
166 | #ifndef MAC_OS | ||
167 | 1804 | void Timer::timespec_add_sec(struct timespec& date_spec, | |
168 | const double duration_sec) | ||
169 | { | ||
170 | 3608 | double total_time_sec = duration_sec + | |
171 | 1804 | static_cast<double>(date_spec.tv_nsec) / 1e9 + | |
172 | 1804 | static_cast<double>(date_spec.tv_sec); | |
173 | 1804 | sec_to_timespec(total_time_sec, date_spec); | |
174 | 1804 | } | |
175 | |||
176 | 1815 | void Timer::sec_to_timespec(double date_sec, struct timespec& date_spec) | |
177 | { | ||
178 | 1815 | date_sec += 0.5e-9; | |
179 | 1815 | date_spec.tv_sec = static_cast<long>(date_sec); | |
180 | 1815 | date_spec.tv_nsec = static_cast<long>( | |
181 | 1815 | (date_sec - static_cast<double>(date_spec.tv_sec)) * 1e9); | |
182 | 1815 | } | |
183 | |||
184 | #endif | ||
185 | |||
186 | 3222 | double Timer::get_current_time_sec() | |
187 | { | ||
188 | #ifdef MAC_OS | ||
189 | throw; | ||
190 | #else | ||
191 | struct timespec now; | ||
192 | 3222 | clock_gettime(CLOCK_REALTIME, &now); | |
193 | 3222 | return static_cast<double>(now.tv_sec) + | |
194 | 3222 | static_cast<double>(now.tv_nsec) / 1e9; | |
195 | #endif | ||
196 | } | ||
197 | |||
198 | ✗ | int Timer::sleep_microseconds(int sleep_duration_us) | |
199 | { | ||
200 | #ifdef MAC_OS | ||
201 | throw; | ||
202 | #elif XENOMAI | ||
203 | return rt_task_sleep(sleep_duration_us * 1e3); | ||
204 | #else | ||
205 | ✗ | usleep(sleep_duration_us); | |
206 | ✗ | return 0; | |
207 | #endif | ||
208 | } | ||
209 | |||
210 | 1803 | void Timer::sleep_sec(const double& sleep_duration_sec) | |
211 | { | ||
212 | #ifdef MAC_OS | ||
213 | throw; | ||
214 | #else | ||
215 | struct timespec abs_target_time; | ||
216 | 1803 | clock_gettime(CLOCK_REALTIME, &abs_target_time); | |
217 |
1/2✓ Branch 1 taken 1803 times.
✗ Branch 2 not taken.
|
1803 | timespec_add_sec(abs_target_time, sleep_duration_sec); |
218 |
1/2✓ Branch 1 taken 1803 times.
✗ Branch 2 not taken.
|
1803 | clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_target_time, nullptr); |
219 | #endif | ||
220 | 1803 | } | |
221 | |||
222 | 11 | void Timer::sleep_until_sec(const double& date_sec) | |
223 | { | ||
224 | #ifdef MAC_OS | ||
225 | throw; | ||
226 | #else | ||
227 | struct timespec abs_target_time; | ||
228 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | sec_to_timespec(date_sec, abs_target_time); |
229 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_target_time, nullptr); |
230 | #endif | ||
231 | 11 | } | |
232 | |||
233 |
2/4✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
42 | } // namespace real_time_tools |
234 |