xref: /aosp_15_r20/external/grpc-grpc/test/cpp/microbenchmarks/bm_exec_ctx.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2022 The gRPC 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 //     http://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 <atomic>
16 #include <memory>
17 
18 #include <benchmark/benchmark.h>
19 
20 #include <grpcpp/impl/grpc_library.h>
21 
22 #include "src/core/lib/gprpp/notification.h"
23 #include "src/core/lib/iomgr/exec_ctx.h"
24 #include "test/core/util/test_config.h"
25 #include "test/cpp/microbenchmarks/helpers.h"
26 #include "test/cpp/util/test_config.h"
27 
28 namespace {
NoOpCb(void *,grpc_error_handle)29 void NoOpCb(void* /* arg */, grpc_error_handle /* error */) {}
30 
BM_ExecCtx_Run(benchmark::State & state)31 void BM_ExecCtx_Run(benchmark::State& state) {
32   int cb_count = state.range(0);
33   grpc_closure cb;
34   GRPC_CLOSURE_INIT(&cb, NoOpCb, nullptr, nullptr);
35   grpc_core::ExecCtx exec_ctx;
36   for (auto _ : state) {
37     for (int i = 0; i < cb_count; i++) {
38       exec_ctx.Run(DEBUG_LOCATION, &cb, absl::OkStatus());
39       exec_ctx.Flush();
40     }
41   }
42   state.SetItemsProcessed(cb_count * state.iterations());
43 }
44 BENCHMARK(BM_ExecCtx_Run)
45     ->Range(100, 10000)
46     ->MeasureProcessCPUTime()
47     ->UseRealTime();
48 
49 struct CountingCbData {
50   std::atomic_int cnt{0};
51   grpc_core::Notification* signal;
52   int limit;
53 };
54 
CountingCb(void * arg,grpc_error_handle)55 void CountingCb(void* arg, grpc_error_handle) {
56   auto* data = static_cast<CountingCbData*>(arg);
57   if (++(data->cnt) == data->limit) data->signal->Notify();
58 }
59 
BM_ExecCtx_RunCounted(benchmark::State & state)60 void BM_ExecCtx_RunCounted(benchmark::State& state) {
61   // A more fair comparison with EventEngine::Run, which must wait for all
62   // executions to finish
63   int cb_count = state.range(0);
64   CountingCbData data;
65   data.limit = cb_count;
66   data.signal = new grpc_core::Notification();
67   grpc_closure cb;
68   GRPC_CLOSURE_INIT(&cb, CountingCb, &data, nullptr);
69   grpc_core::ExecCtx exec_ctx;
70   for (auto _ : state) {
71     for (int i = 0; i < cb_count; i++) {
72       exec_ctx.Run(DEBUG_LOCATION, &cb, absl::OkStatus());
73       exec_ctx.Flush();
74     }
75     data.signal->WaitForNotification();
76     state.PauseTiming();
77     delete data.signal;
78     data.signal = new grpc_core::Notification();
79     data.cnt = 0;
80     state.ResumeTiming();
81   }
82   delete data.signal;
83   state.SetItemsProcessed(cb_count * state.iterations());
84 }
85 BENCHMARK(BM_ExecCtx_RunCounted)
86     ->Range(100, 10000)
87     ->MeasureProcessCPUTime()
88     ->UseRealTime();
89 }  // namespace
90 
91 // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
92 // and others do not. This allows us to support both modes.
93 namespace benchmark {
RunTheBenchmarksNamespaced()94 void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
95 }  // namespace benchmark
96 
main(int argc,char ** argv)97 int main(int argc, char** argv) {
98   grpc::testing::TestEnvironment env(&argc, argv);
99   LibraryInitializer libInit;
100   benchmark::Initialize(&argc, argv);
101   grpc::testing::InitTest(&argc, &argv, false);
102 
103   benchmark::RunTheBenchmarksNamespaced();
104   return 0;
105 }
106