time_benchmark.cc (8445B)
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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