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       absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz);
189     } else {
190       absl::FromCivil(absl::CivilSecond(2013, 11, 15, 18, 30, 27), tz);
191     }
192     ++i;
193   }
194 }
195 BENCHMARK(BM_Time_FromCivil_Absl);
196 
BM_Time_FromCivil_Libc(benchmark::State & state)197 void BM_Time_FromCivil_Libc(benchmark::State& state) {
198   // No timezone support, so just use localtime.
199   int i = 0;
200   while (state.KeepRunning()) {
201     struct tm tm;
202     if ((i & 1) == 0) {
203       tm.tm_year = 2014 - 1900;
204       tm.tm_mon = 12 - 1;
205       tm.tm_mday = 18;
206       tm.tm_hour = 20;
207       tm.tm_min = 16;
208       tm.tm_sec = 18;
209     } else {
210       tm.tm_year = 2013 - 1900;
211       tm.tm_mon = 11 - 1;
212       tm.tm_mday = 15;
213       tm.tm_hour = 18;
214       tm.tm_min = 30;
215       tm.tm_sec = 27;
216     }
217     tm.tm_isdst = -1;
218     mktime(&tm);
219     ++i;
220   }
221 }
222 BENCHMARK(BM_Time_FromCivil_Libc);
223 
BM_Time_FromCivilUTC_Absl(benchmark::State & state)224 void BM_Time_FromCivilUTC_Absl(benchmark::State& state) {
225   const absl::TimeZone tz = absl::UTCTimeZone();
226   while (state.KeepRunning()) {
227     absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz);
228   }
229 }
230 BENCHMARK(BM_Time_FromCivilUTC_Absl);
231 
BM_Time_FromCivilDay0_Absl(benchmark::State & state)232 void BM_Time_FromCivilDay0_Absl(benchmark::State& state) {
233   const absl::TimeZone tz =
234       absl::time_internal::LoadTimeZone("America/Los_Angeles");
235   int i = 0;
236   while (state.KeepRunning()) {
237     if ((i & 1) == 0) {
238       absl::FromCivil(absl::CivilSecond(2014, 12, 0, 20, 16, 18), tz);
239     } else {
240       absl::FromCivil(absl::CivilSecond(2013, 11, 0, 18, 30, 27), tz);
241     }
242     ++i;
243   }
244 }
245 BENCHMARK(BM_Time_FromCivilDay0_Absl);
246 
BM_Time_FromCivilDay0_Libc(benchmark::State & state)247 void BM_Time_FromCivilDay0_Libc(benchmark::State& state) {
248   // No timezone support, so just use localtime.
249   int i = 0;
250   while (state.KeepRunning()) {
251     struct tm tm;
252     if ((i & 1) == 0) {
253       tm.tm_year = 2014 - 1900;
254       tm.tm_mon = 12 - 1;
255       tm.tm_mday = 0;
256       tm.tm_hour = 20;
257       tm.tm_min = 16;
258       tm.tm_sec = 18;
259     } else {
260       tm.tm_year = 2013 - 1900;
261       tm.tm_mon = 11 - 1;
262       tm.tm_mday = 0;
263       tm.tm_hour = 18;
264       tm.tm_min = 30;
265       tm.tm_sec = 27;
266     }
267     tm.tm_isdst = -1;
268     mktime(&tm);
269     ++i;
270   }
271 }
272 BENCHMARK(BM_Time_FromCivilDay0_Libc);
273 
274 //
275 // To/FromTimespec
276 //
277 
BM_Time_ToTimespec(benchmark::State & state)278 void BM_Time_ToTimespec(benchmark::State& state) {
279   absl::Time now = absl::Now();
280   while (state.KeepRunning()) {
281     benchmark::DoNotOptimize(absl::ToTimespec(now));
282   }
283 }
284 BENCHMARK(BM_Time_ToTimespec);
285 
BM_Time_FromTimespec(benchmark::State & state)286 void BM_Time_FromTimespec(benchmark::State& state) {
287   timespec ts = absl::ToTimespec(absl::Now());
288   while (state.KeepRunning()) {
289     if (++ts.tv_nsec == 1000 * 1000 * 1000) {
290       ++ts.tv_sec;
291       ts.tv_nsec = 0;
292     }
293     benchmark::DoNotOptimize(absl::TimeFromTimespec(ts));
294   }
295 }
296 BENCHMARK(BM_Time_FromTimespec);
297 
298 //
299 // Comparison with InfiniteFuture/Past
300 //
301 
BM_Time_InfiniteFuture(benchmark::State & state)302 void BM_Time_InfiniteFuture(benchmark::State& state) {
303   while (state.KeepRunning()) {
304     benchmark::DoNotOptimize(absl::InfiniteFuture());
305   }
306 }
307 BENCHMARK(BM_Time_InfiniteFuture);
308 
BM_Time_InfinitePast(benchmark::State & state)309 void BM_Time_InfinitePast(benchmark::State& state) {
310   while (state.KeepRunning()) {
311     benchmark::DoNotOptimize(absl::InfinitePast());
312   }
313 }
314 BENCHMARK(BM_Time_InfinitePast);
315 
316 }  // namespace
317