1/*******************************************************************************
2* Copyright 2021-2022 Intel Corporation
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*******************************************************************************/
16
17#include <algorithm>
18#include <chrono>
19
20#include "common.hpp"
21#include "utils/timer.hpp"
22
23namespace timer {
24
25double ms_now() {
26 auto timePointTmp
27 = std::chrono::high_resolution_clock::now().time_since_epoch();
28 return std::chrono::duration<double, std::milli>(timePointTmp).count();
29}
30
31#if !defined(BENCHDNN_USE_RDPMC) || defined(_WIN32)
32uint64_t ticks_now() {
33 return (uint64_t)0;
34}
35#else
36uint64_t ticks_now() {
37 uint32_t eax, edx, ecx;
38
39 ecx = (1 << 30) + 1;
40 __asm__ volatile("rdpmc" : "=a"(eax), "=d"(edx) : "c"(ecx));
41
42 return (uint64_t)eax | (uint64_t)edx << 32;
43}
44#endif
45
46void timer_t::reset() {
47 times_ = 0;
48 for (int i = 0; i < n_modes; ++i)
49 ticks_[i] = 0;
50 ticks_start_ = 0;
51 for (int i = 0; i < n_modes; ++i)
52 ms_[i] = 0;
53 ms_start_ = 0;
54
55 start();
56}
57
58void timer_t::start() {
59 ticks_start_ = ticks_now();
60 ms_start_ = ms_now();
61}
62
63void timer_t::stop(int add_times, int64_t add_ticks, double add_ms) {
64 if (add_times == 0) return;
65
66 uint64_t d_ticks = add_ticks;
67 double d_ms = add_ms;
68
69 ticks_start_ += d_ticks;
70 ms_start_ += d_ms;
71
72 ms_[mode_t::avg] += d_ms;
73 ms_[mode_t::sum] += d_ms;
74 ticks_[mode_t::avg] += d_ticks;
75 ticks_[mode_t::sum] += d_ticks;
76
77 d_ticks /= add_times;
78 d_ms /= add_times;
79
80 ms_[mode_t::min] = times_ ? std::min(ms_[mode_t::min], d_ms) : d_ms;
81 ms_[mode_t::max] = times_ ? std::max(ms_[mode_t::max], d_ms) : d_ms;
82
83 ticks_[mode_t::min]
84 = times_ ? std::min(ticks_[mode_t::min], d_ticks) : d_ticks;
85 ticks_[mode_t::max]
86 = times_ ? std::max(ticks_[mode_t::max], d_ticks) : d_ticks;
87
88 times_ += add_times;
89}
90
91void timer_t::stamp(int add_times) {
92 stop(add_times, ticks_now() - ticks_start_, ms_now() - ms_start_);
93}
94
95timer_t &timer_t::operator=(const timer_t &rhs) {
96 if (this == &rhs) return *this;
97 times_ = rhs.times_;
98 for (int i = 0; i < n_modes; ++i)
99 ticks_[i] = rhs.ticks_[i];
100 ticks_start_ = rhs.ticks_start_;
101 for (int i = 0; i < n_modes; ++i)
102 ms_[i] = rhs.ms_[i];
103 ms_start_ = rhs.ms_start_;
104 return *this;
105}
106
107timer_t &timer_map_t::get_timer(const std::string &name) {
108 auto it = timers.find(name);
109 if (it != timers.end()) return it->second;
110 // Set a new timer if requested one wasn't found
111 timers.insert(std::make_pair(std::string(name), timer_t()));
112 return timers.find(name)->second;
113}
114
115timer_t &timer_map_t::perf_timer() {
116 return get_timer(timer_t::perf_timer);
117}
118
119// Initializing timers with fixed names.
120const std::string timer_t::perf_timer = "perf_timer";
121const std::string timer_t::ref_timer = "compute_ref_timer";
122
123} // namespace timer
124