LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
Loading...
Searching...
No Matches
timer.cc
1
9#include "timer.h"
10
11#include <fmt/format.h>
12
13#include <boost/config.hpp>
14#include <chrono>
15#include <iostream>
16
17#if defined(_WIN32) || defined(WIN32)
18#include <Windows.h>
19#else
20#include <sys/times.h>
21#include <unistd.h>
22#endif
23
24namespace /* anonymous */ {
25
26#if defined(_WIN32) || defined(WIN32)
27#else
28std::int_least64_t tick_factor() // multiplier to convert ticks
29 // to nanoseconds; -1 if unknown
30{
31 static std::int_least64_t tick_factor = 0;
32 if (tick_factor == 0) {
33 if (tick_factor = ::sysconf(_SC_CLK_TCK); tick_factor <= 0) {
34 tick_factor = -1;
35 } else {
36 tick_factor = INT64_C(1000000000) / tick_factor; // compute factor
37 if (tick_factor == 0) {
38 tick_factor = -1;
39 }
40 }
41 }
42 return tick_factor;
43}
44#endif
45
46void get_cpu_times(lf::base::Timer::cpu_times* const current) {
47 const std::chrono::nanoseconds x(
48 std::chrono::high_resolution_clock::now().time_since_epoch());
49 current->wall = std::chrono::nanoseconds(x.count());
50
51#if defined(_WIN32) || defined(WIN32)
52
53 FILETIME creation, exit;
54 if (::GetProcessTimes(::GetCurrentProcess(), &creation, &exit,
55 (LPFILETIME)&current->system,
56 (LPFILETIME)&current->user)) {
57 current->user *= 100; // Windows uses 100 nanosecond ticks
58 current->system *= 100;
59 } else
60
61 {
62 current->system = current->user = std::chrono::nanoseconds(-1);
63 }
64#else
65 tms tm; // NOLINT
66 const clock_t c = ::times(&tm);
67 if (c == static_cast<clock_t>(-1)) // error
68 {
69 current->system = current->user = std::chrono::nanoseconds(-1);
70 } else {
71 current->system = std::chrono::nanoseconds(tm.tms_stime + tm.tms_cstime);
72 current->user = std::chrono::nanoseconds(tm.tms_utime + tm.tms_cutime);
73 int_least64_t factor;
74 if (factor = tick_factor(); factor != -1) {
75 current->user *= factor;
76 current->system *= factor;
77 } else {
78 current->user = current->system = std::chrono::nanoseconds(-1);
79 }
80 }
81#endif
82}
83} // namespace
84
85namespace lf::base {
87 if (IsStopped()) {
88 return times_;
89 }
90
91 cpu_times current; // NOLINT
92 get_cpu_times(&current);
93 current.wall -= times_.wall;
94 current.user -= times_.user;
95 current.system -= times_.system;
96
97 return current;
98}
99
100std::string Timer::Format(std::string_view format) const {
101 const double sec = 1000000000.0L;
102 const double wall_sec = static_cast<double>(times_.wall.count()) / sec;
103 const auto total = times_.system.count() + times_.user.count();
104 const double total_sec = static_cast<double>(total) / sec;
105 const double percent = (total_sec / wall_sec) * 100.0;
106
107 return fmt::format(
108 fmt::runtime(format), fmt::arg("w", wall_sec),
109 fmt::arg("u", static_cast<double>(times_.user.count()) / sec),
110 fmt::arg("s", static_cast<double>(times_.system.count()) / sec),
111 fmt::arg("t", total_sec), fmt::arg("p", percent));
112}
113
114void Timer::Start() noexcept {
115 is_stopped_ = false;
116 get_cpu_times(&times_);
117}
118
119void Timer::Stop() noexcept {
120 if (IsStopped()) {
121 return;
122 }
123 is_stopped_ = true;
124
125 cpu_times current; // NOLINT
126 get_cpu_times(&current);
127 times_.wall = (current.wall - times_.wall);
128 times_.user = (current.user - times_.user);
129 times_.system = (current.system - times_.system);
130}
131
132void Timer::Resume() noexcept {
133 if (IsStopped()) {
134 const cpu_times current(times_);
135 Start();
136 times_.wall -= current.wall;
137 times_.user -= current.user;
138 times_.system -= current.system;
139 }
140}
141
142AutoTimer::AutoTimer(std::string format)
143 : format_(std::move(format)), output_(&std::cout) {}
144
145AutoTimer::AutoTimer(std::ostream& stream, std::string format)
146 : format_(std::move(format)), output_(&stream) {}
147
148AutoTimer::AutoTimer(std::shared_ptr<spdlog::logger> logger,
149 spdlog::level::level_enum level, std::string format)
150 : format_(std::move(format)),
151 output_(std::make_pair(std::move(logger), level)) {}
152
154 if (!timer_.IsStopped()) {
155 timer_.Stop();
156 try {
157 Report();
158
159 // NOLINTNEXTLINE(bugprone-empty-catch)
160 } catch (...) { // eat any exceptions
161 }
162 }
163}
164
165std::ostream& AutoTimer::ostream() const {
166 return *std::get<std::ostream*>(output_);
167}
168
169const std::shared_ptr<spdlog::logger>& AutoTimer::logger() const {
170 return std::get<std::pair<std::shared_ptr<spdlog::logger>,
171 spdlog::level::level_enum>>(output_)
172 .first;
173}
174
175const std::string& AutoTimer::FormatString() const { return format_; }
176
178 auto string = timer_.Format(format_);
179 if (auto* ostream = std::get_if<std::ostream*>(&output_)) {
180 (**ostream) << string << '\n';
181 } else {
182 std::get<1>(output_).first->log(std::get<1>(output_).second, string);
183 }
184}
185
187 return timer_.Elapsed();
188}
189
190std::string AutoTimer::Format(std::string_view format) const {
191 return timer_.Format(format);
192}
193
194} // namespace lf::base
std::variant< std::ostream *, std::pair< std::shared_ptr< spdlog::logger >, spdlog::level::level_enum > > output_
Definition timer.h:273
std::string Format(std::string_view format=Timer::kDefaultFormat) const
Return the number of elapsed seconds of the wall clock time, user time and system time as a formatted...
Definition timer.cc:190
Timer::cpu_times Elapsed() const noexcept
Retrieve the elapsed time since the construction.
Definition timer.cc:186
AutoTimer(std::string format=Timer::kDefaultFormat)
Create a new AutoTimer that will report time measurements to std::cout when destructed.
Definition timer.cc:142
const std::shared_ptr< spdlog::logger > & logger() const
Retrieve the logger that was passed in the constructor.
Definition timer.cc:169
~AutoTimer()
Destructor of AutoTimer, calls Report().
Definition timer.cc:153
const std::string & FormatString() const
Retrieve the format string that was passed in the constructor.
Definition timer.cc:175
std::ostream & ostream() const
Retrieve the output stream object that was passed in the constructor.
Definition timer.cc:165
void Report()
Report time (wall, user, system) since construction of AutoTimer() to either a std::ostream or spdlog...
Definition timer.cc:177
std::string format_
Definition timer.h:268
bool is_stopped_
Definition timer.h:169
std::string Format(std::string_view format=kDefaultFormat) const
Return the number of elapsed seconds of the wall clock time, user time and system time as a formatted...
Definition timer.cc:100
void Stop() noexcept
stop the timer, stop counting the elapsed time.
Definition timer.cc:119
void Resume() noexcept
Resume the timer, i.e. start counting from where we stopped the last time.
Definition timer.cc:132
cpu_times Elapsed() const noexcept
Elapsed time since timer start, doesn't stop the timer.
Definition timer.cc:86
bool IsStopped() const noexcept
Is the timer currently stopped?
Definition timer.h:115
cpu_times times_
Definition timer.h:168
void Start() noexcept
(Re)starts the timer, i.e. the timer starts counting from 0 when this method is called.
Definition timer.cc:114
Contains basic functionality that is used by other parts of LehrFEM++.
Definition base.h:15
Packages the elapsed wall clock time, user process CPU time, and system process CPU time.
Definition timer.h:70
std::chrono::nanoseconds system
Elapsed System time in nano-seconds.
Definition timer.h:93
std::chrono::nanoseconds user
Elapsed User time in nano-seconds.
Definition timer.h:85
std::chrono::nanoseconds wall
Elapsed WallClock time in nano-seconds.
Definition timer.h:77