xref: /aosp_15_r20/external/cronet/base/types/expected_macros_perftest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/types/expected_macros.h"
6 
7 #include <stddef.h>
8 
9 #include <string>
10 #include <utility>
11 
12 #include "base/types/expected.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/abseil-cpp/absl/base/attributes.h"
15 #include "third_party/google_benchmark/src/include/benchmark/benchmark.h"
16 
17 namespace base {
18 namespace {
19 
20 // Basis for `RETURN_IF_ERROR` and `ASSIGN_OR_RETURN` benchmarks.  Derived
21 // classes override `LoopAgain` with the macro invocation(s).
22 class ReturnLoop {
23  public:
24   using ReturnType = expected<int, std::string>;
25 
ReturnLoop(ReturnType return_value)26   explicit ReturnLoop(ReturnType return_value)
27       : value_(std::move(return_value)) {}
28   virtual ~ReturnLoop() = default;
29 
Loop(size_t * ops)30   ABSL_ATTRIBUTE_NO_TAIL_CALL ReturnType Loop(size_t* ops) {
31     if (!*ops) {
32       return value_;
33     }
34     return LoopAgain(ops);
35   }
36 
return_value() const37   ReturnType return_value() const { return value_; }
38 
39  private:
40   virtual ReturnType LoopAgain(size_t* ops) = 0;
41 
42   const ReturnType value_;
43 };
44 
45 class ReturnIfErrorLoop : public ReturnLoop {
46  public:
47   using ReturnLoop::ReturnLoop;
48 
49  private:
LoopAgain(size_t * ops)50   ReturnType LoopAgain(size_t* ops) override {
51     --*ops;
52     RETURN_IF_ERROR(Loop(ops));
53     return 0;
54   }
55 };
56 
57 class ReturnIfErrorWithAnnotateLoop : public ReturnLoop {
58  public:
59   using ReturnLoop::ReturnLoop;
60 
61  private:
LoopAgain(size_t * ops)62   ReturnType LoopAgain(size_t* ops) override {
63     --*ops;
64     RETURN_IF_ERROR(Loop(ops), [](std::string e) {
65       return e + "The quick brown fox jumped over the lazy dog.";
66     });
67     return 0;
68   }
69 };
70 
71 class AssignOrReturnLoop : public ReturnLoop {
72  public:
73   using ReturnLoop::ReturnLoop;
74 
75  private:
LoopAgain(size_t * ops)76   ReturnType LoopAgain(size_t* ops) override {
77     --*ops;
78     ASSIGN_OR_RETURN(const int result, Loop(ops));
79     return result;
80   }
81 };
82 
83 class AssignOrReturnAnnotateLoop : public ReturnLoop {
84  public:
85   using ReturnLoop::ReturnLoop;
86 
87  private:
LoopAgain(size_t * ops)88   ReturnType LoopAgain(size_t* ops) override {
89     --*ops;
90     ASSIGN_OR_RETURN(const int result, Loop(ops), [](std::string e) {
91       return e + "The quick brown fox jumped over the lazy dog.";
92     });
93     return result;
94   }
95 };
96 
BenchmarkError()97 std::string BenchmarkError() {
98   // This error message is intended to be long enough to guarantee external
99   // memory allocation in `std::string`.
100   return "The quick brown fox jumped over the lazy dog.";
101 }
102 
103 // Drive a benchmark loop.  `T` is intended to be a `ReturnLoop` (above).
104 template <class T>
BenchmarkLoop(T * driver,::benchmark::State * state)105 void BenchmarkLoop(T* driver, ::benchmark::State* state) {
106   // We benchmark 8 macro invocations (stack depth) per loop.  This
107   // amortizes one time costs (e.g. building the initial error value)
108   // across what we actually care about.
109   constexpr int kMaxOps = 8;
110   while (state->KeepRunningBatch(kMaxOps)) {
111     size_t ops = kMaxOps;
112     auto ret = driver->Loop(&ops);
113     ::benchmark::DoNotOptimize(ret);
114   }
115 }
116 
117 // TODO(https://crbug.com/40251982): Update test-driving scripts to control
118 // google_benchmark correctly and parse its output, so that these benchmarks'
119 // results are included in bot output.
120 
121 // Registers a benchmark as a GTest test. This allows using legacy
122 // --gtest_filter and --gtest_list_tests.
123 // TODO(https://crbug.com/40251982): Clean this up after transitioning to
124 // --benchmark_filter and --benchmark_list_tests.
125 #define BENCHMARK_WITH_TEST(benchmark_name)      \
126   TEST(ExpectedMacrosPerfTest, benchmark_name) { \
127     BENCHMARK(benchmark_name);                   \
128   }
129 
BM_ReturnIfError_Ok(::benchmark::State & state)130 void BM_ReturnIfError_Ok(::benchmark::State& state) {
131   ReturnIfErrorLoop loop(1);
132   BenchmarkLoop(&loop, &state);
133 }
BENCHMARK_WITH_TEST(BM_ReturnIfError_Ok)134 BENCHMARK_WITH_TEST(BM_ReturnIfError_Ok)
135 
136 void BM_ReturnIfError_Error(::benchmark::State& state) {
137   ReturnIfErrorLoop loop{unexpected(BenchmarkError())};
138   BenchmarkLoop(&loop, &state);
139 }
BENCHMARK_WITH_TEST(BM_ReturnIfError_Error)140 BENCHMARK_WITH_TEST(BM_ReturnIfError_Error)
141 
142 void BM_ReturnIfError_Annotate_Ok(::benchmark::State& state) {
143   ReturnIfErrorWithAnnotateLoop loop(1);
144   BenchmarkLoop(&loop, &state);
145 }
BENCHMARK_WITH_TEST(BM_ReturnIfError_Annotate_Ok)146 BENCHMARK_WITH_TEST(BM_ReturnIfError_Annotate_Ok)
147 
148 void BM_ReturnIfError_Annotate_Error(::benchmark::State& state) {
149   ReturnIfErrorWithAnnotateLoop loop{unexpected(BenchmarkError())};
150   BenchmarkLoop(&loop, &state);
151 }
BENCHMARK_WITH_TEST(BM_ReturnIfError_Annotate_Error)152 BENCHMARK_WITH_TEST(BM_ReturnIfError_Annotate_Error)
153 
154 void BM_AssignOrReturn_Ok(::benchmark::State& state) {
155   AssignOrReturnLoop loop(1);
156   BenchmarkLoop(&loop, &state);
157 }
BENCHMARK_WITH_TEST(BM_AssignOrReturn_Ok)158 BENCHMARK_WITH_TEST(BM_AssignOrReturn_Ok)
159 
160 void BM_AssignOrReturn_Error(::benchmark::State& state) {
161   AssignOrReturnLoop loop{unexpected(BenchmarkError())};
162   BenchmarkLoop(&loop, &state);
163 }
BENCHMARK_WITH_TEST(BM_AssignOrReturn_Error)164 BENCHMARK_WITH_TEST(BM_AssignOrReturn_Error)
165 
166 void BM_AssignOrReturn_Annotate_Ok(::benchmark::State& state) {
167   AssignOrReturnAnnotateLoop loop(1);
168   BenchmarkLoop(&loop, &state);
169 }
BENCHMARK_WITH_TEST(BM_AssignOrReturn_Annotate_Ok)170 BENCHMARK_WITH_TEST(BM_AssignOrReturn_Annotate_Ok)
171 
172 void BM_AssignOrReturn_Annotate_Error(::benchmark::State& state) {
173   AssignOrReturnAnnotateLoop loop{unexpected(BenchmarkError())};
174   BenchmarkLoop(&loop, &state);
175 }
176 BENCHMARK_WITH_TEST(BM_AssignOrReturn_Annotate_Error)
177 
178 }  // namespace
179 }  // namespace base
180