statusor_benchmark.cc (15191B)
1 // Copyright 2025 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <string> 16 17 #include "absl/status/status.h" 18 #include "absl/status/statusor.h" 19 #include "benchmark/benchmark.h" 20 21 namespace { 22 23 void BM_StatusOrInt_CtorStatus(benchmark::State& state) { 24 for (auto _ : state) { 25 absl::StatusOr<int> status(absl::CancelledError()); 26 benchmark::DoNotOptimize(status); 27 } 28 } 29 BENCHMARK(BM_StatusOrInt_CtorStatus); 30 31 void BM_StatusOrInt_CtorStatusWithMessage(benchmark::State& state) { 32 for (auto _ : state) { 33 absl::StatusOr<int> status( 34 absl::UnknownError("This string is 28 characters")); 35 benchmark::DoNotOptimize(status); 36 } 37 } 38 BENCHMARK(BM_StatusOrInt_CtorStatusWithMessage); 39 40 void BM_StatusOrInt_CopyCtor_Error(benchmark::State& state) { 41 for (auto _ : state) { 42 absl::StatusOr<int> original( 43 absl::UnknownError("This string is 28 characters")); 44 benchmark::DoNotOptimize(original); 45 absl::StatusOr<int> status(original); 46 benchmark::DoNotOptimize(status); 47 } 48 } 49 BENCHMARK(BM_StatusOrInt_CopyCtor_Error); 50 51 void BM_StatusOrInt_CopyCtor_Ok(benchmark::State& state) { 52 for (auto _ : state) { 53 absl::StatusOr<int> original(42); 54 benchmark::DoNotOptimize(original); 55 absl::StatusOr<int> status(original); 56 benchmark::DoNotOptimize(status); 57 } 58 } 59 BENCHMARK(BM_StatusOrInt_CopyCtor_Ok); 60 61 void BM_StatusOrInt_MoveCtor_Error(benchmark::State& state) { 62 for (auto _ : state) { 63 absl::StatusOr<int> original( 64 absl::UnknownError("This string is 28 characters")); 65 benchmark::DoNotOptimize(original); 66 absl::StatusOr<int> status(std::move(original)); 67 benchmark::DoNotOptimize(status); 68 } 69 } 70 BENCHMARK(BM_StatusOrInt_MoveCtor_Error); 71 72 void BM_StatusOrInt_MoveCtor_Ok(benchmark::State& state) { 73 for (auto _ : state) { 74 absl::StatusOr<int> original(42); 75 benchmark::DoNotOptimize(original); 76 absl::StatusOr<int> status(std::move(original)); 77 benchmark::DoNotOptimize(status); 78 } 79 } 80 BENCHMARK(BM_StatusOrInt_MoveCtor_Ok); 81 82 void BM_StatusOrInt_CopyAssign_Error(benchmark::State& state) { 83 for (auto _ : state) { 84 absl::StatusOr<int> original( 85 absl::UnknownError("This string is 28 characters")); 86 benchmark::DoNotOptimize(original); 87 absl::StatusOr<int> status(42); 88 benchmark::DoNotOptimize(status); 89 benchmark::DoNotOptimize(status = original); 90 benchmark::DoNotOptimize(status); 91 } 92 } 93 BENCHMARK(BM_StatusOrInt_CopyAssign_Error); 94 95 void BM_StatusOrInt_CopyAssign_Ok(benchmark::State& state) { 96 for (auto _ : state) { 97 absl::StatusOr<int> original(42); 98 benchmark::DoNotOptimize(original); 99 absl::StatusOr<int> status(42); 100 benchmark::DoNotOptimize(status); 101 benchmark::DoNotOptimize(status = original); 102 benchmark::DoNotOptimize(status); 103 } 104 } 105 BENCHMARK(BM_StatusOrInt_CopyAssign_Ok); 106 107 void BM_StatusOrInt_MoveAssign_Error(benchmark::State& state) { 108 for (auto _ : state) { 109 absl::StatusOr<int> original( 110 absl::UnknownError("This string is 28 characters")); 111 benchmark::DoNotOptimize(original); 112 absl::StatusOr<int> status(42); 113 benchmark::DoNotOptimize(status); 114 benchmark::DoNotOptimize(status = std::move(original)); 115 benchmark::DoNotOptimize(status); 116 } 117 } 118 BENCHMARK(BM_StatusOrInt_MoveAssign_Error); 119 120 void BM_StatusOrInt_MoveAssign_Ok(benchmark::State& state) { 121 for (auto _ : state) { 122 absl::StatusOr<int> original(42); 123 benchmark::DoNotOptimize(original); 124 absl::StatusOr<int> status(42); 125 benchmark::DoNotOptimize(status); 126 benchmark::DoNotOptimize(status = std::move(original)); 127 benchmark::DoNotOptimize(status); 128 } 129 } 130 BENCHMARK(BM_StatusOrInt_MoveAssign_Ok); 131 132 void BM_StatusOrInt_OkMethod_Error(benchmark::State& state) { 133 absl::StatusOr<int> status( 134 absl::UnknownError("This string is 28 characters")); 135 for (auto _ : state) { 136 benchmark::DoNotOptimize(status); 137 benchmark::DoNotOptimize(status.ok()); 138 } 139 } 140 BENCHMARK(BM_StatusOrInt_OkMethod_Error); 141 142 void BM_StatusOrInt_OkMethod_Ok(benchmark::State& state) { 143 absl::StatusOr<int> status(42); 144 for (auto _ : state) { 145 benchmark::DoNotOptimize(status); 146 benchmark::DoNotOptimize(status.ok()); 147 } 148 } 149 BENCHMARK(BM_StatusOrInt_OkMethod_Ok); 150 151 void BM_StatusOrInt_StatusMethod_Error(benchmark::State& state) { 152 for (auto _ : state) { 153 absl::StatusOr<int> status( 154 absl::UnknownError("This string is 28 characters")); 155 benchmark::DoNotOptimize(status); 156 benchmark::DoNotOptimize(status.status().ok()); 157 } 158 } 159 BENCHMARK(BM_StatusOrInt_StatusMethod_Error); 160 161 void BM_StatusOrInt_StatusMethod_Ok(benchmark::State& state) { 162 for (auto _ : state) { 163 absl::StatusOr<int> status(42); 164 benchmark::DoNotOptimize(status); 165 benchmark::DoNotOptimize(std::move(status).status().ok()); 166 } 167 } 168 BENCHMARK(BM_StatusOrInt_StatusMethod_Ok); 169 170 void BM_StatusOrInt_StatusMethodRvalue_Error(benchmark::State& state) { 171 for (auto _ : state) { 172 absl::StatusOr<int> status( 173 absl::UnknownError("This string is 28 characters")); 174 benchmark::DoNotOptimize(status); 175 benchmark::DoNotOptimize(std::move(status).status().ok()); 176 } 177 } 178 BENCHMARK(BM_StatusOrInt_StatusMethodRvalue_Error); 179 180 void BM_StatusOrInt_StatusMethodRvalue_Ok(benchmark::State& state) { 181 for (auto _ : state) { 182 absl::StatusOr<int> status(42); 183 benchmark::DoNotOptimize(status); 184 benchmark::DoNotOptimize(std::move(status).status()); 185 } 186 } 187 BENCHMARK(BM_StatusOrInt_StatusMethodRvalue_Ok); 188 189 void BM_StatusOrString_CtorStatus(benchmark::State& state) { 190 for (auto _ : state) { 191 absl::StatusOr<std::string> status(absl::CancelledError()); 192 benchmark::DoNotOptimize(status); 193 } 194 } 195 BENCHMARK(BM_StatusOrString_CtorStatus); 196 197 void BM_StatusOrString_CtorStatusWithMessage(benchmark::State& state) { 198 for (auto _ : state) { 199 absl::StatusOr<std::string> status( 200 absl::UnknownError("This string is 28 characters")); 201 benchmark::DoNotOptimize(status); 202 } 203 } 204 BENCHMARK(BM_StatusOrString_CtorStatusWithMessage); 205 206 void BM_StatusOrString_CopyCtor_Error(benchmark::State& state) { 207 for (auto _ : state) { 208 absl::StatusOr<std::string> original( 209 absl::UnknownError("This string is 28 characters")); 210 benchmark::DoNotOptimize(original); 211 absl::StatusOr<std::string> status(original); 212 benchmark::DoNotOptimize(status); 213 } 214 } 215 BENCHMARK(BM_StatusOrString_CopyCtor_Error); 216 217 void BM_StatusOrString_CopyCtor_Ok(benchmark::State& state) { 218 for (auto _ : state) { 219 absl::StatusOr<std::string> original("This string is 28 characters"); 220 benchmark::DoNotOptimize(original); 221 absl::StatusOr<std::string> status(original); 222 benchmark::DoNotOptimize(status); 223 } 224 } 225 BENCHMARK(BM_StatusOrString_CopyCtor_Ok); 226 227 void BM_StatusOrString_MoveCtor_Error(benchmark::State& state) { 228 for (auto _ : state) { 229 absl::StatusOr<std::string> original( 230 absl::UnknownError("This string is 28 characters")); 231 benchmark::DoNotOptimize(original); 232 absl::StatusOr<std::string> status(std::move(original)); 233 benchmark::DoNotOptimize(status); 234 } 235 } 236 BENCHMARK(BM_StatusOrString_MoveCtor_Error); 237 238 void BM_StatusOrString_MoveCtor_Ok(benchmark::State& state) { 239 for (auto _ : state) { 240 absl::StatusOr<std::string> original("This string is 28 characters"); 241 benchmark::DoNotOptimize(original); 242 absl::StatusOr<std::string> status(std::move(original)); 243 benchmark::DoNotOptimize(status); 244 } 245 } 246 BENCHMARK(BM_StatusOrString_MoveCtor_Ok); 247 248 void BM_StatusOrString_CopyAssign_Error(benchmark::State& state) { 249 for (auto _ : state) { 250 absl::StatusOr<std::string> original( 251 absl::UnknownError("This string is 28 characters")); 252 benchmark::DoNotOptimize(original); 253 absl::StatusOr<std::string> status("This string is 28 characters"); 254 benchmark::DoNotOptimize(status); 255 benchmark::DoNotOptimize(status = original); 256 benchmark::DoNotOptimize(status); 257 } 258 } 259 BENCHMARK(BM_StatusOrString_CopyAssign_Error); 260 261 void BM_StatusOrString_CopyAssign_Ok(benchmark::State& state) { 262 for (auto _ : state) { 263 absl::StatusOr<std::string> original("This string is 28 characters"); 264 benchmark::DoNotOptimize(original); 265 absl::StatusOr<std::string> status("This string is 28 characters"); 266 benchmark::DoNotOptimize(status); 267 benchmark::DoNotOptimize(status = original); 268 benchmark::DoNotOptimize(status); 269 } 270 } 271 BENCHMARK(BM_StatusOrString_CopyAssign_Ok); 272 273 void BM_StatusOrString_MoveAssign_Error(benchmark::State& state) { 274 for (auto _ : state) { 275 absl::StatusOr<std::string> original( 276 absl::UnknownError("This string is 28 characters")); 277 benchmark::DoNotOptimize(original); 278 absl::StatusOr<std::string> status("This string is 28 characters"); 279 benchmark::DoNotOptimize(status); 280 benchmark::DoNotOptimize(status = std::move(original)); 281 benchmark::DoNotOptimize(status); 282 } 283 } 284 BENCHMARK(BM_StatusOrString_MoveAssign_Error); 285 286 void BM_StatusOrString_MoveAssign_Ok(benchmark::State& state) { 287 for (auto _ : state) { 288 absl::StatusOr<std::string> original("This string is 28 characters"); 289 benchmark::DoNotOptimize(original); 290 absl::StatusOr<std::string> status("This string is 28 characters"); 291 benchmark::DoNotOptimize(status); 292 benchmark::DoNotOptimize(status = std::move(original)); 293 benchmark::DoNotOptimize(status); 294 } 295 } 296 BENCHMARK(BM_StatusOrString_MoveAssign_Ok); 297 298 void BM_StatusOrString_OkMethod_Error(benchmark::State& state) { 299 for (auto _ : state) { 300 absl::StatusOr<std::string> status( 301 absl::UnknownError("This string is 28 characters")); 302 benchmark::DoNotOptimize(status); 303 benchmark::DoNotOptimize(status.ok()); 304 } 305 } 306 BENCHMARK(BM_StatusOrString_OkMethod_Error); 307 308 void BM_StatusOrString_OkMethod_Ok(benchmark::State& state) { 309 for (auto _ : state) { 310 absl::StatusOr<std::string> status("This string is 28 characters"); 311 benchmark::DoNotOptimize(status); 312 benchmark::DoNotOptimize(status.ok()); 313 } 314 } 315 BENCHMARK(BM_StatusOrString_OkMethod_Ok); 316 317 void BM_StatusOrString_StatusMethod_Error(benchmark::State& state) { 318 for (auto _ : state) { 319 absl::StatusOr<std::string> status( 320 absl::UnknownError("This string is 28 characters")); 321 benchmark::DoNotOptimize(status); 322 benchmark::DoNotOptimize(status.status().ok()); 323 } 324 } 325 BENCHMARK(BM_StatusOrString_StatusMethod_Error); 326 327 void BM_StatusOrString_StatusMethod_Ok(benchmark::State& state) { 328 for (auto _ : state) { 329 absl::StatusOr<std::string> status("This string is 28 characters"); 330 benchmark::DoNotOptimize(status); 331 benchmark::DoNotOptimize(status.status().ok()); 332 } 333 } 334 BENCHMARK(BM_StatusOrString_StatusMethod_Ok); 335 336 void BM_StatusOrString_StatusMethodRvalue_Error(benchmark::State& state) { 337 for (auto _ : state) { 338 absl::StatusOr<std::string> status( 339 absl::UnknownError("This string is 28 characters")); 340 benchmark::DoNotOptimize(status); 341 benchmark::DoNotOptimize(std::move(status).status()); 342 } 343 } 344 BENCHMARK(BM_StatusOrString_StatusMethodRvalue_Error); 345 346 void BM_StatusOrString_StatusMethodRvalue_Ok(benchmark::State& state) { 347 for (auto _ : state) { 348 absl::StatusOr<std::string> status("This string is 28 characters"); 349 benchmark::DoNotOptimize(status); 350 benchmark::DoNotOptimize(std::move(status).status()); 351 } 352 } 353 BENCHMARK(BM_StatusOrString_StatusMethodRvalue_Ok); 354 355 // Benchmarks comparing a few alternative ways of structuring an interface 356 // for returning an int64 on success or an error. See (a), (b), (c), (d) 357 // below for the variants. 358 bool bm_cond = true; 359 360 bool SimpleIntInterface(int64_t* v) ABSL_ATTRIBUTE_NOINLINE; 361 bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg) 362 ABSL_ATTRIBUTE_NOINLINE; 363 absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v) 364 ABSL_ATTRIBUTE_NOINLINE; 365 absl::StatusOr<int64_t> SimpleIntStatusOrInterface() ABSL_ATTRIBUTE_NOINLINE; 366 367 // (a): Just a boolean return value with an out int64* parameter 368 bool SimpleIntInterface(int64_t* v) { 369 benchmark::DoNotOptimize(bm_cond); 370 if (bm_cond) { 371 *v = 42; 372 return true; 373 } else { 374 return false; 375 } 376 } 377 378 // (b): A boolean return value and a string error message filled in on failure 379 // and an out int64* parameter filled on success 380 bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg) { 381 benchmark::DoNotOptimize(bm_cond); 382 if (bm_cond) { 383 *v = 42; 384 return true; 385 } else { 386 *msg = "This is an error message"; 387 return false; 388 } 389 } 390 391 // (c): A Status return value with an out int64* parameter on success 392 absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v) { 393 benchmark::DoNotOptimize(bm_cond); 394 if (bm_cond) { 395 *v = 42; 396 return absl::OkStatus(); 397 } else { 398 return absl::UnknownError("This is an error message"); 399 } 400 } 401 402 // (d): A StatusOr<int64> return value 403 absl::StatusOr<int64_t> SimpleIntStatusOrInterface() { 404 benchmark::DoNotOptimize(bm_cond); 405 if (bm_cond) { 406 return 42; 407 } else { 408 return absl::StatusOr<int64_t>( 409 absl::UnknownError("This is an error message")); 410 } 411 } 412 413 void SetCondition(benchmark::State& state) { 414 bm_cond = (state.range(0) == 0); 415 state.SetLabel(bm_cond ? "Success" : "Failure"); 416 } 417 418 void BM_SimpleIntInterface(benchmark::State& state) { 419 SetCondition(state); 420 int64_t sum = 0; 421 for (auto s : state) { 422 int64_t v; 423 if (SimpleIntInterface(&v)) { 424 sum += v; 425 } 426 benchmark::DoNotOptimize(sum); 427 } 428 } 429 430 void BM_SimpleIntInterfaceMsg(benchmark::State& state) { 431 SetCondition(state); 432 int64_t sum = 0; 433 std::string msg; 434 for (auto s : state) { 435 int64_t v; 436 if (SimpleIntInterfaceWithErrorMessage(&v, &msg)) { 437 sum += v; 438 } 439 benchmark::DoNotOptimize(sum); 440 benchmark::DoNotOptimize(msg); 441 } 442 } 443 444 void BM_SimpleIntInterfaceStatus(benchmark::State& state) { 445 SetCondition(state); 446 int64_t sum = 0; 447 for (auto s : state) { 448 int64_t v; 449 auto result = SimpleIntInterfaceWithErrorStatus(&v); 450 if (result.ok()) { 451 sum += v; 452 } 453 benchmark::DoNotOptimize(sum); 454 } 455 } 456 457 void BM_SimpleIntStatusOrInterface(benchmark::State& state) { 458 SetCondition(state); 459 int64_t sum = 0; 460 for (auto s : state) { 461 auto v_s = SimpleIntStatusOrInterface(); 462 if (v_s.ok()) { 463 sum += *v_s; 464 } 465 benchmark::DoNotOptimize(sum); 466 } 467 } 468 469 // Ordered like this so all the success path benchmarks (Arg(0)) show up, 470 // then all the failure benchmarks (Arg(1)) 471 BENCHMARK(BM_SimpleIntInterface)->Arg(0); 472 BENCHMARK(BM_SimpleIntInterfaceMsg)->Arg(0); 473 BENCHMARK(BM_SimpleIntInterfaceStatus)->Arg(0); 474 BENCHMARK(BM_SimpleIntStatusOrInterface)->Arg(0); 475 BENCHMARK(BM_SimpleIntInterface)->Arg(1); 476 BENCHMARK(BM_SimpleIntInterfaceMsg)->Arg(1); 477 BENCHMARK(BM_SimpleIntInterfaceStatus)->Arg(1); 478 BENCHMARK(BM_SimpleIntStatusOrInterface)->Arg(1); 479 480 } // namespace