]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* |
2 | * This file is open source software, licensed to you under the terms | |
3 | * of the Apache License, Version 2.0 (the "License"). See the NOTICE file | |
4 | * distributed with this work for additional information regarding copyright | |
5 | * ownership. You may not use this file except in compliance with the License. | |
6 | * | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, | |
12 | * software distributed under the License is distributed on an | |
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | * KIND, either express or implied. See the License for the | |
15 | * specific language governing permissions and limitations | |
16 | * under the License. | |
17 | */ | |
18 | /* | |
19 | * Copyright (C) 2016 ScyllaDB | |
20 | */ | |
21 | ||
22 | #pragma once | |
23 | ||
24 | #include <seastar/core/cacheline.hh> | |
25 | #include <seastar/core/timer.hh> | |
26 | ||
27 | #include <cstdint> | |
28 | ||
29 | #include <atomic> | |
30 | #include <chrono> | |
31 | ||
32 | namespace seastar { | |
33 | ||
34 | // | |
35 | // Forward declarations. | |
36 | // | |
37 | ||
38 | class lowres_clock; | |
39 | class lowres_system_clock; | |
40 | ||
41 | /// \cond internal | |
42 | ||
43 | class lowres_clock_impl final { | |
44 | public: | |
45 | using base_steady_clock = std::chrono::steady_clock; | |
46 | using base_system_clock = std::chrono::system_clock; | |
47 | ||
48 | // The clocks' resolutions are 10 ms. However, to make it is easier to do calculations with | |
49 | // `std::chrono::milliseconds`, we make the clock period 1 ms instead of 10 ms. | |
50 | using period = std::ratio<1, 1000>; | |
51 | ||
52 | using steady_rep = base_steady_clock::rep; | |
53 | using steady_duration = std::chrono::duration<steady_rep, period>; | |
54 | using steady_time_point = std::chrono::time_point<lowres_clock, steady_duration>; | |
55 | ||
56 | using system_rep = base_system_clock::rep; | |
57 | using system_duration = std::chrono::duration<system_rep, period>; | |
58 | using system_time_point = std::chrono::time_point<lowres_system_clock, system_duration>; | |
59 | ||
f67539c2 | 60 | static steady_time_point steady_now() noexcept { |
11fdf7f2 TL |
61 | auto const nr = counters::_steady_now.load(std::memory_order_relaxed); |
62 | return steady_time_point(steady_duration(nr)); | |
63 | } | |
64 | ||
f67539c2 | 65 | static system_time_point system_now() noexcept { |
11fdf7f2 TL |
66 | auto const nr = counters::_system_now.load(std::memory_order_relaxed); |
67 | return system_time_point(system_duration(nr)); | |
68 | } | |
69 | ||
70 | // For construction. | |
71 | friend class smp; | |
72 | private: | |
73 | // Both counters are updated by cpu0 and read by other cpus. Place them on their own cache line to avoid false | |
74 | // sharing. | |
75 | struct alignas(seastar::cache_line_size) counters final { | |
76 | static std::atomic<steady_rep> _steady_now; | |
77 | static std::atomic<system_rep> _system_now; | |
78 | }; | |
79 | ||
80 | // The timer expires every 10 ms. | |
81 | static constexpr std::chrono::milliseconds _granularity{10}; | |
82 | ||
83 | // High-resolution timer to drive these low-resolution clocks. | |
84 | timer<> _timer{}; | |
85 | ||
f67539c2 | 86 | static void update() noexcept; |
11fdf7f2 TL |
87 | |
88 | // Private to ensure that static variables are only initialized once. | |
f67539c2 | 89 | // might throw when arming timer. |
11fdf7f2 TL |
90 | lowres_clock_impl(); |
91 | }; | |
92 | ||
93 | /// \endcond | |
94 | ||
95 | // | |
96 | /// \brief Low-resolution and efficient steady clock. | |
97 | /// | |
98 | /// This is a monotonic clock with a granularity of 10 ms. Time points from this clock do not correspond to system | |
99 | /// time. | |
100 | /// | |
101 | /// The primary benefit of this clock is that invoking \c now() is inexpensive compared to | |
102 | /// \c std::chrono::steady_clock::now(). | |
103 | /// | |
104 | /// \see \c lowres_system_clock for a low-resolution clock which produces time points corresponding to system time. | |
105 | /// | |
106 | class lowres_clock final { | |
107 | public: | |
108 | using rep = lowres_clock_impl::steady_rep; | |
109 | using period = lowres_clock_impl::period; | |
110 | using duration = lowres_clock_impl::steady_duration; | |
111 | using time_point = lowres_clock_impl::steady_time_point; | |
112 | ||
113 | static constexpr bool is_steady = true; | |
114 | ||
115 | /// | |
116 | /// \note Outside of a Seastar application, the result is undefined. | |
117 | /// | |
f67539c2 | 118 | static time_point now() noexcept { |
11fdf7f2 TL |
119 | return lowres_clock_impl::steady_now(); |
120 | } | |
121 | }; | |
122 | ||
123 | /// | |
124 | /// \brief Low-resolution and efficient system clock. | |
125 | /// | |
126 | /// This clock has the same granularity as \c lowres_clock, but it is not required to be monotonic and its time points | |
127 | /// correspond to system time. | |
128 | /// | |
129 | /// The primary benefit of this clock is that invoking \c now() is inexpensive compared to | |
130 | /// \c std::chrono::system_clock::now(). | |
131 | /// | |
132 | class lowres_system_clock final { | |
133 | public: | |
134 | using rep = lowres_clock_impl::system_rep; | |
135 | using period = lowres_clock_impl::period; | |
136 | using duration = lowres_clock_impl::system_duration; | |
137 | using time_point = lowres_clock_impl::system_time_point; | |
138 | ||
139 | static constexpr bool is_steady = lowres_clock_impl::base_system_clock::is_steady; | |
140 | ||
141 | /// | |
142 | /// \note Outside of a Seastar application, the result is undefined. | |
143 | /// | |
f67539c2 | 144 | static time_point now() noexcept { |
11fdf7f2 TL |
145 | return lowres_clock_impl::system_now(); |
146 | } | |
147 | ||
f67539c2 | 148 | static std::time_t to_time_t(time_point t) noexcept { |
11fdf7f2 TL |
149 | return std::chrono::duration_cast<std::chrono::seconds>(t.time_since_epoch()).count(); |
150 | } | |
151 | ||
f67539c2 | 152 | static time_point from_time_t(std::time_t t) noexcept { |
11fdf7f2 TL |
153 | return time_point(std::chrono::duration_cast<duration>(std::chrono::seconds(t))); |
154 | } | |
155 | }; | |
156 | ||
9f95a23c TL |
157 | extern template class timer<lowres_clock>; |
158 | ||
11fdf7f2 TL |
159 | } |
160 |