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