xref: /aosp_15_r20/external/abseil-cpp/absl/time/time_benchmark.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
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