| 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 |