5 #include "error_util.hpp"
11 #include <spdlog/spdlog.h>
22 static inline std::chrono::nanoseconds cpp_clock_gettime(clockid_t clock_id) {
29 struct timespec ts { };
31 RAC_ERRNO_MSG(
"cpu_timer before clock_gettime");
33 if (clock_gettime(clock_id, &ts)) {
34 throw std::runtime_error{std::string{
"clock_gettime returned "} + strerror(errno)};
36 RAC_ERRNO_MSG(
"cpu_timer after clock_gettime");
42 return std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec};
48 static inline std::chrono::nanoseconds thread_cpu_time() {
49 RAC_ERRNO_MSG(
"cpu_timer before cpp_clock_gettime");
50 return cpp_clock_gettime(CLOCK_THREAD_CPUTIME_ID);
78 template<typename now_fn, typename time_point = decltype(std::declval<now_fn>()()),
79 typename durationt = decltype(std::declval<time_point>() - std::declval<time_point>())>
82 timer(
const now_fn& now, durationt& _duration)
84 , _p_duration{_duration} {
89 _p_duration = _p_now() - _p_start;
94 durationt& _p_duration;
98 template<typename Duration, typename Out = decltype(std::declval<Duration>().count())>
99 typename std::enable_if<std::is_integral<Out>::value, Out>::type count_duration(Duration t) {
100 return std::chrono::duration_cast<std::chrono::nanoseconds, typename Duration::rep, typename Duration::period>(t).count();
103 template<
typename Duration>
104 typename std::enable_if<std::is_integral<Duration>::value, Duration>::type count_duration(Duration t) {
114 template<typename now_fn, typename time_point = decltype(std::declval<now_fn>()()),
115 typename duration = decltype(std::declval<time_point>() - std::declval<time_point>())>
118 class print_in_destructor {
120 print_in_destructor(std::string account_name,
const duration& _duration)
121 : _p_account_name{std::move(account_name)}
122 , _p_duration{_duration} { }
124 ~print_in_destructor() {
127 if (rand() % 100 == 0) {
129 spdlog::get(
"illixr")->info(
"cpu_timer.hpp is DEPRECATED. See logging.hpp.");
135 const std::string _p_account_name;
136 const duration& _p_duration;
143 duration _p_duration;
144 const print_in_destructor _p_print_in_destructor;
148 print_timer(
const std::string& name,
const now_fn& now)
149 : _p_print_in_destructor{name, _p_duration}
150 , _p_timer{now, _p_duration} { }
153 static std::size_t gen_serial_no() {
154 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch())
158 class should_profile_class {
160 should_profile_class() {
161 const char* ILLIXR_STDOUT_METRICS = getenv(
"ILLIXR_STDOUT_METRICS");
162 actually_should_profile = ILLIXR_STDOUT_METRICS && (strcmp(ILLIXR_STDOUT_METRICS,
"y") == 0);
165 bool operator()()
const {
166 return actually_should_profile;
170 bool actually_should_profile;
173 static should_profile_class should_profile;
177 const std::string name;
178 const std::size_t serial_no;
179 std::size_t wall_time_start;
180 std::size_t cpu_time_start;
183 explicit print_timer2(std::string name_)
184 : name{std::move(name_)}
185 , serial_no{should_profile() ? gen_serial_no() : std::size_t{0}}
186 , wall_time_start{should_profile() ? std::chrono::duration_cast<std::chrono::nanoseconds>(
187 std::chrono::high_resolution_clock::now().time_since_epoch())
190 , cpu_time_start{should_profile() ? thread_cpu_time().count() : std::size_t{0}} { }
193 if (should_profile()) {
194 auto cpu_time_stop = thread_cpu_time().count();
195 auto wall_time_stop = std::chrono::duration_cast<std::chrono::nanoseconds>(
196 std::chrono::high_resolution_clock::now().time_since_epoch())
199 spdlog::get(
"illixr")->info(
"[cpu_timer] cpu_timer,{},{},{},{},{},{}", name, serial_no, wall_time_start,
200 wall_time_stop, cpu_time_start, cpu_time_stop);
205 #define PRINT_CPU_TIME_FOR_THIS_BLOCK(name) \
206 print_timer<decltype((thread_cpu_time))> PRINT_CPU_TIME_FOR_THIS_BLOCK{name, thread_cpu_time};
208 #define PRINT_WALL_TIME_FOR_THIS_BLOCK(name) \
209 print_timer<decltype((std::chrono::high_resolution_clock::now))> PRINT_WALL_TIME_FOR_THIS_BLOCK{ \
210 name, std::chrono::high_resolution_clock::now};
212 #define PRINT_RECORD_FOR_THIS_BLOCK(name) print_timer2 PRINT_RECORD_FOR_THIS_BLOCK_timer{name};
217 template<
class Function,
class... Args>
218 std::thread timed_thread(
const std::string& account_name, Function&& f, Args&&... args) {
222 return std::thread([=] {
224 PRINT_RECORD_FOR_THIS_BLOCK(account_name)
225 std::invoke(f, args...);
Like timer, but prints the output.
Definition: cpu_timer.hpp:116
a timer that times until the end of the code block ([RAII]).
Definition: cpu_timer.hpp:80