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 | |
23 | namespace timer { |
24 | |
25 | double 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) |
32 | uint64_t ticks_now() { |
33 | return (uint64_t)0; |
34 | } |
35 | #else |
36 | uint64_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 | |
46 | void 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 | |
58 | void timer_t::start() { |
59 | ticks_start_ = ticks_now(); |
60 | ms_start_ = ms_now(); |
61 | } |
62 | |
63 | void 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 | |
91 | void timer_t::stamp(int add_times) { |
92 | stop(add_times, ticks_now() - ticks_start_, ms_now() - ms_start_); |
93 | } |
94 | |
95 | timer_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 | |
107 | timer_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 | |
115 | timer_t &timer_map_t::perf_timer() { |
116 | return get_timer(timer_t::perf_timer); |
117 | } |
118 | |
119 | // Initializing timers with fixed names. |
120 | const std::string timer_t::perf_timer = "perf_timer" ; |
121 | const std::string timer_t::ref_timer = "compute_ref_timer" ; |
122 | |
123 | } // namespace timer |
124 | |