1 // Copyright 2018 The Abseil Authors.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // https://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 #include "absl/time/time.h"
15
16 #if !defined(_WIN32)
17 #include <sys/time.h>
18 #endif // _WIN32
19 #include <algorithm>
20 #include <cmath>
21 #include <cstddef>
22 #include <cstring>
23 #include <ctime>
24 #include <memory>
25 #include <string>
26
27 #include "absl/time/clock.h"
28 #include "absl/time/internal/test_util.h"
29 #include "benchmark/benchmark.h"
30
31 namespace {
32
33 //
34 // Addition/Subtraction of a duration
35 //
36
BM_Time_Arithmetic(benchmark::State & state)37 void BM_Time_Arithmetic(benchmark::State& state) {
38 const absl::Duration nano = absl::Nanoseconds(1);
39 const absl::Duration sec = absl::Seconds(1);
40 absl::Time t = absl::UnixEpoch();
41 while (state.KeepRunning()) {
42 benchmark::DoNotOptimize(t += nano);
43 benchmark::DoNotOptimize(t -= sec);
44 }
45 }
46 BENCHMARK(BM_Time_Arithmetic);
47
48 //
49 // Time difference
50 //
51
BM_Time_Difference(benchmark::State & state)52 void BM_Time_Difference(benchmark::State& state) {
53 absl::Time start = absl::Now();
54 absl::Time end = start + absl::Nanoseconds(1);
55 absl::Duration diff;
56 while (state.KeepRunning()) {
57 benchmark::DoNotOptimize(diff += end - start);
58 }
59 }
60 BENCHMARK(BM_Time_Difference);
61
62 //
63 // ToDateTime
64 //
65 // In each "ToDateTime" benchmark we switch between two instants
66 // separated by at least one transition in order to defeat any
67 // internal caching of previous results (e.g., see local_time_hint_).
68 //
69 // The "UTC" variants use UTC instead of the Google/local time zone.
70 //
71
BM_Time_ToDateTime_Absl(benchmark::State & state)72 void BM_Time_ToDateTime_Absl(benchmark::State& state) {
73 const absl::TimeZone tz =
74 absl::time_internal::LoadTimeZone("America/Los_Angeles");
75 absl::Time t = absl::FromUnixSeconds(1384569027);
76 absl::Time t2 = absl::FromUnixSeconds(1418962578);
77 while (state.KeepRunning()) {
78 std::swap(t, t2);
79 t += absl::Seconds(1);
80 benchmark::DoNotOptimize(t.In(tz));
81 }
82 }
83 BENCHMARK(BM_Time_ToDateTime_Absl);
84
BM_Time_ToDateTime_Libc(benchmark::State & state)85 void BM_Time_ToDateTime_Libc(benchmark::State& state) {
86 // No timezone support, so just use localtime.
87 time_t t = 1384569027;
88 time_t t2 = 1418962578;
89 while (state.KeepRunning()) {
90 std::swap(t, t2);
91 t += 1;
92 struct tm tm;
93 #if !defined(_WIN32)
94 benchmark::DoNotOptimize(localtime_r(&t, &tm));
95 #else // _WIN32
96 benchmark::DoNotOptimize(localtime_s(&tm, &t));
97 #endif // _WIN32
98 }
99 }
100 BENCHMARK(BM_Time_ToDateTime_Libc);
101
BM_Time_ToDateTimeUTC_Absl(benchmark::State & state)102 void BM_Time_ToDateTimeUTC_Absl(benchmark::State& state) {
103 const absl::TimeZone tz = absl::UTCTimeZone();
104 absl::Time t = absl::FromUnixSeconds(1384569027);
105 while (state.KeepRunning()) {
106 t += absl::Seconds(1);
107 benchmark::DoNotOptimize(t.In(tz));
108 }
109 }
110 BENCHMARK(BM_Time_ToDateTimeUTC_Absl);
111
BM_Time_ToDateTimeUTC_Libc(benchmark::State & state)112 void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) {
113 time_t t = 1384569027;
114 while (state.KeepRunning()) {
115 t += 1;
116 struct tm tm;
117 #if !defined(_WIN32)
118 benchmark::DoNotOptimize(gmtime_r(&t, &tm));
119 #else // _WIN32
120 benchmark::DoNotOptimize(gmtime_s(&tm, &t));
121 #endif // _WIN32
122 }
123 }
124 BENCHMARK(BM_Time_ToDateTimeUTC_Libc);
125
126 //
127 // FromUnixMicros
128 //
129
BM_Time_FromUnixMicros(benchmark::State & state)130 void BM_Time_FromUnixMicros(benchmark::State& state) {
131 int i = 0;
132 while (state.KeepRunning()) {
133 benchmark::DoNotOptimize(absl::FromUnixMicros(i));
134 ++i;
135 }
136 }
137 BENCHMARK(BM_Time_FromUnixMicros);
138
BM_Time_ToUnixNanos(benchmark::State & state)139 void BM_Time_ToUnixNanos(benchmark::State& state) {
140 const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
141 while (state.KeepRunning()) {
142 benchmark::DoNotOptimize(ToUnixNanos(t));
143 }
144 }
145 BENCHMARK(BM_Time_ToUnixNanos);
146
BM_Time_ToUnixMicros(benchmark::State & state)147 void BM_Time_ToUnixMicros(benchmark::State& state) {
148 const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
149 while (state.KeepRunning()) {
150 benchmark::DoNotOptimize(ToUnixMicros(t));
151 }
152 }
153 BENCHMARK(BM_Time_ToUnixMicros);
154
BM_Time_ToUnixMillis(benchmark::State & state)155 void BM_Time_ToUnixMillis(benchmark::State& state) {
156 const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
157 while (state.KeepRunning()) {
158 benchmark::DoNotOptimize(ToUnixMillis(t));
159 }
160 }
161 BENCHMARK(BM_Time_ToUnixMillis);
162
BM_Time_ToUnixSeconds(benchmark::State & state)163 void BM_Time_ToUnixSeconds(benchmark::State& state) {
164 const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
165 while (state.KeepRunning()) {
166 benchmark::DoNotOptimize(absl::ToUnixSeconds(t));
167 }
168 }
169 BENCHMARK(BM_Time_ToUnixSeconds);
170
171 //
172 // FromCivil
173 //
174 // In each "FromCivil" benchmark we switch between two YMDhms values
175 // separated by at least one transition in order to defeat any internal
176 // caching of previous results (e.g., see time_local_hint_).
177 //
178 // The "UTC" variants use UTC instead of the Google/local time zone.
179 // The "Day0" variants require normalization of the day of month.
180 //
181
BM_Time_FromCivil_Absl(benchmark::State & state)182 void BM_Time_FromCivil_Absl(benchmark::State& state) {
183 const absl::TimeZone tz =
184 absl::time_internal::LoadTimeZone("America/Los_Angeles");
185 int i = 0;
186 while (state.KeepRunning()) {
187 if ((i & 1) == 0) {
188 benchmark::DoNotOptimize(
189 absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz));
190 } else {
191 benchmark::DoNotOptimize(
192 absl::FromCivil(absl::CivilSecond(2013, 11, 15, 18, 30, 27), tz));
193 }
194 ++i;
195 }
196 }
197 BENCHMARK(BM_Time_FromCivil_Absl);
198
BM_Time_FromCivil_Libc(benchmark::State & state)199 void BM_Time_FromCivil_Libc(benchmark::State& state) {
200 // No timezone support, so just use localtime.
201 int i = 0;
202 while (state.KeepRunning()) {
203 struct tm tm;
204 if ((i & 1) == 0) {
205 tm.tm_year = 2014 - 1900;
206 tm.tm_mon = 12 - 1;
207 tm.tm_mday = 18;
208 tm.tm_hour = 20;
209 tm.tm_min = 16;
210 tm.tm_sec = 18;
211 } else {
212 tm.tm_year = 2013 - 1900;
213 tm.tm_mon = 11 - 1;
214 tm.tm_mday = 15;
215 tm.tm_hour = 18;
216 tm.tm_min = 30;
217 tm.tm_sec = 27;
218 }
219 tm.tm_isdst = -1;
220 mktime(&tm);
221 ++i;
222 }
223 }
224 BENCHMARK(BM_Time_FromCivil_Libc);
225
BM_Time_FromCivilUTC_Absl(benchmark::State & state)226 void BM_Time_FromCivilUTC_Absl(benchmark::State& state) {
227 const absl::TimeZone tz = absl::UTCTimeZone();
228 while (state.KeepRunning()) {
229 benchmark::DoNotOptimize(
230 absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz));
231 }
232 }
233 BENCHMARK(BM_Time_FromCivilUTC_Absl);
234
BM_Time_FromCivilDay0_Absl(benchmark::State & state)235 void BM_Time_FromCivilDay0_Absl(benchmark::State& state) {
236 const absl::TimeZone tz =
237 absl::time_internal::LoadTimeZone("America/Los_Angeles");
238 int i = 0;
239 while (state.KeepRunning()) {
240 if ((i & 1) == 0) {
241 benchmark::DoNotOptimize(
242 absl::FromCivil(absl::CivilSecond(2014, 12, 0, 20, 16, 18), tz));
243 } else {
244 benchmark::DoNotOptimize(
245 absl::FromCivil(absl::CivilSecond(2013, 11, 0, 18, 30, 27), tz));
246 }
247 ++i;
248 }
249 }
250 BENCHMARK(BM_Time_FromCivilDay0_Absl);
251
BM_Time_FromCivilDay0_Libc(benchmark::State & state)252 void BM_Time_FromCivilDay0_Libc(benchmark::State& state) {
253 // No timezone support, so just use localtime.
254 int i = 0;
255 while (state.KeepRunning()) {
256 struct tm tm;
257 if ((i & 1) == 0) {
258 tm.tm_year = 2014 - 1900;
259 tm.tm_mon = 12 - 1;
260 tm.tm_mday = 0;
261 tm.tm_hour = 20;
262 tm.tm_min = 16;
263 tm.tm_sec = 18;
264 } else {
265 tm.tm_year = 2013 - 1900;
266 tm.tm_mon = 11 - 1;
267 tm.tm_mday = 0;
268 tm.tm_hour = 18;
269 tm.tm_min = 30;
270 tm.tm_sec = 27;
271 }
272 tm.tm_isdst = -1;
273 mktime(&tm);
274 ++i;
275 }
276 }
277 BENCHMARK(BM_Time_FromCivilDay0_Libc);
278
279 //
280 // To/FromTimespec
281 //
282
BM_Time_ToTimespec(benchmark::State & state)283 void BM_Time_ToTimespec(benchmark::State& state) {
284 absl::Time now = absl::Now();
285 while (state.KeepRunning()) {
286 benchmark::DoNotOptimize(absl::ToTimespec(now));
287 }
288 }
289 BENCHMARK(BM_Time_ToTimespec);
290
BM_Time_FromTimespec(benchmark::State & state)291 void BM_Time_FromTimespec(benchmark::State& state) {
292 timespec ts = absl::ToTimespec(absl::Now());
293 while (state.KeepRunning()) {
294 if (++ts.tv_nsec == 1000 * 1000 * 1000) {
295 ++ts.tv_sec;
296 ts.tv_nsec = 0;
297 }
298 benchmark::DoNotOptimize(absl::TimeFromTimespec(ts));
299 }
300 }
301 BENCHMARK(BM_Time_FromTimespec);
302
303 //
304 // Comparison with InfiniteFuture/Past
305 //
306
BM_Time_InfiniteFuture(benchmark::State & state)307 void BM_Time_InfiniteFuture(benchmark::State& state) {
308 while (state.KeepRunning()) {
309 benchmark::DoNotOptimize(absl::InfiniteFuture());
310 }
311 }
312 BENCHMARK(BM_Time_InfiniteFuture);
313
BM_Time_InfinitePast(benchmark::State & state)314 void BM_Time_InfinitePast(benchmark::State& state) {
315 while (state.KeepRunning()) {
316 benchmark::DoNotOptimize(absl::InfinitePast());
317 }
318 }
319 BENCHMARK(BM_Time_InfinitePast);
320
321 } // namespace
322