1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 /* Test various operations on grpc_error */
20
21 #include <benchmark/benchmark.h>
22 #include <memory>
23
24 #include "src/core/lib/iomgr/error.h"
25 #include "src/core/lib/transport/error_utils.h"
26
27 #include "test/cpp/microbenchmarks/helpers.h"
28 #include "test/cpp/util/test_config.h"
29
30 auto& force_library_initialization = Library::get();
31
32 class ErrorDeleter {
33 public:
operator ()(grpc_error * error)34 void operator()(grpc_error* error) { GRPC_ERROR_UNREF(error); }
35 };
36 typedef std::unique_ptr<grpc_error, ErrorDeleter> ErrorPtr;
37
BM_ErrorCreateFromStatic(benchmark::State & state)38 static void BM_ErrorCreateFromStatic(benchmark::State& state) {
39 TrackCounters track_counters;
40 while (state.KeepRunning()) {
41 GRPC_ERROR_UNREF(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"));
42 }
43 track_counters.Finish(state);
44 }
45 BENCHMARK(BM_ErrorCreateFromStatic);
46
BM_ErrorCreateFromCopied(benchmark::State & state)47 static void BM_ErrorCreateFromCopied(benchmark::State& state) {
48 TrackCounters track_counters;
49 while (state.KeepRunning()) {
50 GRPC_ERROR_UNREF(GRPC_ERROR_CREATE_FROM_COPIED_STRING("Error not inline"));
51 }
52 track_counters.Finish(state);
53 }
54 BENCHMARK(BM_ErrorCreateFromCopied);
55
BM_ErrorCreateAndSetStatus(benchmark::State & state)56 static void BM_ErrorCreateAndSetStatus(benchmark::State& state) {
57 TrackCounters track_counters;
58 while (state.KeepRunning()) {
59 GRPC_ERROR_UNREF(
60 grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"),
61 GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_ABORTED));
62 }
63 track_counters.Finish(state);
64 }
65 BENCHMARK(BM_ErrorCreateAndSetStatus);
66
BM_ErrorCreateAndSetIntAndStr(benchmark::State & state)67 static void BM_ErrorCreateAndSetIntAndStr(benchmark::State& state) {
68 TrackCounters track_counters;
69 while (state.KeepRunning()) {
70 GRPC_ERROR_UNREF(grpc_error_set_str(
71 grpc_error_set_int(
72 GRPC_ERROR_CREATE_FROM_STATIC_STRING("GOAWAY received"),
73 GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)0),
74 GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_static_string("raw bytes")));
75 }
76 track_counters.Finish(state);
77 }
78 BENCHMARK(BM_ErrorCreateAndSetIntAndStr);
79
BM_ErrorCreateAndSetIntLoop(benchmark::State & state)80 static void BM_ErrorCreateAndSetIntLoop(benchmark::State& state) {
81 TrackCounters track_counters;
82 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
83 int n = 0;
84 while (state.KeepRunning()) {
85 error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, n++);
86 }
87 GRPC_ERROR_UNREF(error);
88 track_counters.Finish(state);
89 }
90 BENCHMARK(BM_ErrorCreateAndSetIntLoop);
91
BM_ErrorCreateAndSetStrLoop(benchmark::State & state)92 static void BM_ErrorCreateAndSetStrLoop(benchmark::State& state) {
93 TrackCounters track_counters;
94 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
95 const char* str = "hello";
96 while (state.KeepRunning()) {
97 error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
98 grpc_slice_from_static_string(str));
99 }
100 GRPC_ERROR_UNREF(error);
101 track_counters.Finish(state);
102 }
103 BENCHMARK(BM_ErrorCreateAndSetStrLoop);
104
BM_ErrorRefUnref(benchmark::State & state)105 static void BM_ErrorRefUnref(benchmark::State& state) {
106 TrackCounters track_counters;
107 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
108 while (state.KeepRunning()) {
109 GRPC_ERROR_UNREF(GRPC_ERROR_REF(error));
110 }
111 GRPC_ERROR_UNREF(error);
112 track_counters.Finish(state);
113 }
114 BENCHMARK(BM_ErrorRefUnref);
115
BM_ErrorUnrefNone(benchmark::State & state)116 static void BM_ErrorUnrefNone(benchmark::State& state) {
117 TrackCounters track_counters;
118 while (state.KeepRunning()) {
119 GRPC_ERROR_UNREF(GRPC_ERROR_NONE);
120 }
121 }
122 BENCHMARK(BM_ErrorUnrefNone);
123
BM_ErrorGetIntFromNoError(benchmark::State & state)124 static void BM_ErrorGetIntFromNoError(benchmark::State& state) {
125 TrackCounters track_counters;
126 while (state.KeepRunning()) {
127 intptr_t value;
128 grpc_error_get_int(GRPC_ERROR_NONE, GRPC_ERROR_INT_GRPC_STATUS, &value);
129 }
130 track_counters.Finish(state);
131 }
132 BENCHMARK(BM_ErrorGetIntFromNoError);
133
BM_ErrorGetMissingInt(benchmark::State & state)134 static void BM_ErrorGetMissingInt(benchmark::State& state) {
135 TrackCounters track_counters;
136 ErrorPtr error(grpc_error_set_int(
137 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_INDEX, 1));
138 while (state.KeepRunning()) {
139 intptr_t value;
140 grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
141 }
142 track_counters.Finish(state);
143 }
144 BENCHMARK(BM_ErrorGetMissingInt);
145
BM_ErrorGetPresentInt(benchmark::State & state)146 static void BM_ErrorGetPresentInt(benchmark::State& state) {
147 TrackCounters track_counters;
148 ErrorPtr error(grpc_error_set_int(
149 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_OFFSET, 1));
150 while (state.KeepRunning()) {
151 intptr_t value;
152 grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
153 }
154 track_counters.Finish(state);
155 }
156 BENCHMARK(BM_ErrorGetPresentInt);
157
158 // Fixtures for tests: generate different kinds of errors
159 class ErrorNone {
160 public:
deadline() const161 grpc_millis deadline() const { return deadline_; }
error() const162 grpc_error* error() const { return GRPC_ERROR_NONE; }
163
164 private:
165 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
166 };
167
168 class ErrorCancelled {
169 public:
deadline() const170 grpc_millis deadline() const { return deadline_; }
error() const171 grpc_error* error() const { return GRPC_ERROR_CANCELLED; }
172
173 private:
174 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
175 };
176
177 class SimpleError {
178 public:
deadline() const179 grpc_millis deadline() const { return deadline_; }
error() const180 grpc_error* error() const { return error_.get(); }
181
182 private:
183 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
184 ErrorPtr error_{GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error")};
185 };
186
187 class ErrorWithGrpcStatus {
188 public:
deadline() const189 grpc_millis deadline() const { return deadline_; }
error() const190 grpc_error* error() const { return error_.get(); }
191
192 private:
193 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
194 ErrorPtr error_{grpc_error_set_int(
195 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
196 GRPC_STATUS_UNIMPLEMENTED)};
197 };
198
199 class ErrorWithHttpError {
200 public:
deadline() const201 grpc_millis deadline() const { return deadline_; }
error() const202 grpc_error* error() const { return error_.get(); }
203
204 private:
205 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
206 ErrorPtr error_{grpc_error_set_int(
207 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_HTTP2_ERROR,
208 GRPC_HTTP2_COMPRESSION_ERROR)};
209 };
210
211 class ErrorWithNestedGrpcStatus {
212 public:
deadline() const213 grpc_millis deadline() const { return deadline_; }
error() const214 grpc_error* error() const { return error_.get(); }
215
216 private:
217 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
218 ErrorPtr nested_error_{grpc_error_set_int(
219 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
220 GRPC_STATUS_UNIMPLEMENTED)};
221 grpc_error* nested_errors_[1] = {nested_error_.get()};
222 ErrorPtr error_{GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
223 "Error", nested_errors_, 1)};
224 };
225
226 template <class Fixture>
BM_ErrorStringOnNewError(benchmark::State & state)227 static void BM_ErrorStringOnNewError(benchmark::State& state) {
228 TrackCounters track_counters;
229 while (state.KeepRunning()) {
230 Fixture fixture;
231 grpc_error_string(fixture.error());
232 }
233 track_counters.Finish(state);
234 }
235
236 template <class Fixture>
BM_ErrorStringRepeatedly(benchmark::State & state)237 static void BM_ErrorStringRepeatedly(benchmark::State& state) {
238 TrackCounters track_counters;
239 Fixture fixture;
240 while (state.KeepRunning()) {
241 grpc_error_string(fixture.error());
242 }
243 track_counters.Finish(state);
244 }
245
246 template <class Fixture>
BM_ErrorGetStatus(benchmark::State & state)247 static void BM_ErrorGetStatus(benchmark::State& state) {
248 TrackCounters track_counters;
249 Fixture fixture;
250 grpc_core::ExecCtx exec_ctx;
251 while (state.KeepRunning()) {
252 grpc_status_code status;
253 grpc_slice slice;
254 grpc_error_get_status(fixture.error(), fixture.deadline(), &status, &slice,
255 nullptr, nullptr);
256 }
257
258 track_counters.Finish(state);
259 }
260
261 template <class Fixture>
BM_ErrorGetStatusCode(benchmark::State & state)262 static void BM_ErrorGetStatusCode(benchmark::State& state) {
263 TrackCounters track_counters;
264 Fixture fixture;
265 grpc_core::ExecCtx exec_ctx;
266 while (state.KeepRunning()) {
267 grpc_status_code status;
268 grpc_error_get_status(fixture.error(), fixture.deadline(), &status, nullptr,
269 nullptr, nullptr);
270 }
271
272 track_counters.Finish(state);
273 }
274
275 template <class Fixture>
BM_ErrorHttpError(benchmark::State & state)276 static void BM_ErrorHttpError(benchmark::State& state) {
277 TrackCounters track_counters;
278 Fixture fixture;
279 grpc_core::ExecCtx exec_ctx;
280 while (state.KeepRunning()) {
281 grpc_http2_error_code error;
282 grpc_error_get_status(fixture.error(), fixture.deadline(), nullptr, nullptr,
283 &error, nullptr);
284 }
285
286 track_counters.Finish(state);
287 }
288
289 template <class Fixture>
BM_HasClearGrpcStatus(benchmark::State & state)290 static void BM_HasClearGrpcStatus(benchmark::State& state) {
291 TrackCounters track_counters;
292 Fixture fixture;
293 while (state.KeepRunning()) {
294 grpc_error_has_clear_grpc_status(fixture.error());
295 }
296 track_counters.Finish(state);
297 }
298
299 #define BENCHMARK_SUITE(fixture) \
300 BENCHMARK_TEMPLATE(BM_ErrorStringOnNewError, fixture); \
301 BENCHMARK_TEMPLATE(BM_ErrorStringRepeatedly, fixture); \
302 BENCHMARK_TEMPLATE(BM_ErrorGetStatus, fixture); \
303 BENCHMARK_TEMPLATE(BM_ErrorGetStatusCode, fixture); \
304 BENCHMARK_TEMPLATE(BM_ErrorHttpError, fixture); \
305 BENCHMARK_TEMPLATE(BM_HasClearGrpcStatus, fixture)
306
307 BENCHMARK_SUITE(ErrorNone);
308 BENCHMARK_SUITE(ErrorCancelled);
309 BENCHMARK_SUITE(SimpleError);
310 BENCHMARK_SUITE(ErrorWithGrpcStatus);
311 BENCHMARK_SUITE(ErrorWithHttpError);
312 BENCHMARK_SUITE(ErrorWithNestedGrpcStatus);
313
314 // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
315 // and others do not. This allows us to support both modes.
316 namespace benchmark {
RunTheBenchmarksNamespaced()317 void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
318 } // namespace benchmark
319
main(int argc,char ** argv)320 int main(int argc, char** argv) {
321 ::benchmark::Initialize(&argc, argv);
322 ::grpc::testing::InitTest(&argc, &argv, false);
323 benchmark::RunTheBenchmarksNamespaced();
324 return 0;
325 }
326