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/core/util/test_config.h"
28 #include "test/cpp/microbenchmarks/helpers.h"
29 #include "test/cpp/util/test_config.h"
30
31 class ErrorDeleter {
32 public:
operator ()(grpc_error * error)33 void operator()(grpc_error* error) { GRPC_ERROR_UNREF(error); }
34 };
35 typedef std::unique_ptr<grpc_error, ErrorDeleter> ErrorPtr;
36
BM_ErrorCreateFromStatic(benchmark::State & state)37 static void BM_ErrorCreateFromStatic(benchmark::State& state) {
38 TrackCounters track_counters;
39 for (auto _ : state) {
40 GRPC_ERROR_UNREF(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"));
41 }
42 track_counters.Finish(state);
43 }
44 BENCHMARK(BM_ErrorCreateFromStatic);
45
BM_ErrorCreateFromCopied(benchmark::State & state)46 static void BM_ErrorCreateFromCopied(benchmark::State& state) {
47 TrackCounters track_counters;
48 for (auto _ : state) {
49 GRPC_ERROR_UNREF(GRPC_ERROR_CREATE_FROM_COPIED_STRING("Error not inline"));
50 }
51 track_counters.Finish(state);
52 }
53 BENCHMARK(BM_ErrorCreateFromCopied);
54
BM_ErrorCreateAndSetStatus(benchmark::State & state)55 static void BM_ErrorCreateAndSetStatus(benchmark::State& state) {
56 TrackCounters track_counters;
57 for (auto _ : state) {
58 GRPC_ERROR_UNREF(
59 grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"),
60 GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_ABORTED));
61 }
62 track_counters.Finish(state);
63 }
64 BENCHMARK(BM_ErrorCreateAndSetStatus);
65
BM_ErrorCreateAndSetIntAndStr(benchmark::State & state)66 static void BM_ErrorCreateAndSetIntAndStr(benchmark::State& state) {
67 TrackCounters track_counters;
68 for (auto _ : state) {
69 GRPC_ERROR_UNREF(grpc_error_set_str(
70 grpc_error_set_int(
71 GRPC_ERROR_CREATE_FROM_STATIC_STRING("GOAWAY received"),
72 GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)0),
73 GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_static_string("raw bytes")));
74 }
75 track_counters.Finish(state);
76 }
77 BENCHMARK(BM_ErrorCreateAndSetIntAndStr);
78
BM_ErrorCreateAndSetIntLoop(benchmark::State & state)79 static void BM_ErrorCreateAndSetIntLoop(benchmark::State& state) {
80 TrackCounters track_counters;
81 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
82 int n = 0;
83 for (auto _ : state) {
84 error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, n++);
85 }
86 GRPC_ERROR_UNREF(error);
87 track_counters.Finish(state);
88 }
89 BENCHMARK(BM_ErrorCreateAndSetIntLoop);
90
BM_ErrorCreateAndSetStrLoop(benchmark::State & state)91 static void BM_ErrorCreateAndSetStrLoop(benchmark::State& state) {
92 TrackCounters track_counters;
93 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
94 const char* str = "hello";
95 for (auto _ : state) {
96 error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
97 grpc_slice_from_static_string(str));
98 }
99 GRPC_ERROR_UNREF(error);
100 track_counters.Finish(state);
101 }
102 BENCHMARK(BM_ErrorCreateAndSetStrLoop);
103
BM_ErrorRefUnref(benchmark::State & state)104 static void BM_ErrorRefUnref(benchmark::State& state) {
105 TrackCounters track_counters;
106 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
107 for (auto _ : state) {
108 GRPC_ERROR_UNREF(GRPC_ERROR_REF(error));
109 }
110 GRPC_ERROR_UNREF(error);
111 track_counters.Finish(state);
112 }
113 BENCHMARK(BM_ErrorRefUnref);
114
BM_ErrorUnrefNone(benchmark::State & state)115 static void BM_ErrorUnrefNone(benchmark::State& state) {
116 TrackCounters track_counters;
117 for (auto _ : state) {
118 GRPC_ERROR_UNREF(GRPC_ERROR_NONE);
119 }
120 }
121 BENCHMARK(BM_ErrorUnrefNone);
122
BM_ErrorGetIntFromNoError(benchmark::State & state)123 static void BM_ErrorGetIntFromNoError(benchmark::State& state) {
124 TrackCounters track_counters;
125 for (auto _ : state) {
126 intptr_t value;
127 grpc_error_get_int(GRPC_ERROR_NONE, GRPC_ERROR_INT_GRPC_STATUS, &value);
128 }
129 track_counters.Finish(state);
130 }
131 BENCHMARK(BM_ErrorGetIntFromNoError);
132
BM_ErrorGetMissingInt(benchmark::State & state)133 static void BM_ErrorGetMissingInt(benchmark::State& state) {
134 TrackCounters track_counters;
135 ErrorPtr error(grpc_error_set_int(
136 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_INDEX, 1));
137 for (auto _ : state) {
138 intptr_t value;
139 grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
140 }
141 track_counters.Finish(state);
142 }
143 BENCHMARK(BM_ErrorGetMissingInt);
144
BM_ErrorGetPresentInt(benchmark::State & state)145 static void BM_ErrorGetPresentInt(benchmark::State& state) {
146 TrackCounters track_counters;
147 ErrorPtr error(grpc_error_set_int(
148 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_OFFSET, 1));
149 for (auto _ : state) {
150 intptr_t value;
151 grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
152 }
153 track_counters.Finish(state);
154 }
155 BENCHMARK(BM_ErrorGetPresentInt);
156
157 // Fixtures for tests: generate different kinds of errors
158 class ErrorNone {
159 public:
deadline() const160 grpc_millis deadline() const { return deadline_; }
error() const161 grpc_error* error() const { return GRPC_ERROR_NONE; }
162
163 private:
164 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
165 };
166
167 class ErrorCancelled {
168 public:
deadline() const169 grpc_millis deadline() const { return deadline_; }
error() const170 grpc_error* error() const { return GRPC_ERROR_CANCELLED; }
171
172 private:
173 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
174 };
175
176 class SimpleError {
177 public:
deadline() const178 grpc_millis deadline() const { return deadline_; }
error() const179 grpc_error* error() const { return error_.get(); }
180
181 private:
182 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
183 ErrorPtr error_{GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error")};
184 };
185
186 class ErrorWithGrpcStatus {
187 public:
deadline() const188 grpc_millis deadline() const { return deadline_; }
error() const189 grpc_error* error() const { return error_.get(); }
190
191 private:
192 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
193 ErrorPtr error_{grpc_error_set_int(
194 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
195 GRPC_STATUS_UNIMPLEMENTED)};
196 };
197
198 class ErrorWithHttpError {
199 public:
deadline() const200 grpc_millis deadline() const { return deadline_; }
error() const201 grpc_error* error() const { return error_.get(); }
202
203 private:
204 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
205 ErrorPtr error_{grpc_error_set_int(
206 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_HTTP2_ERROR,
207 GRPC_HTTP2_COMPRESSION_ERROR)};
208 };
209
210 class ErrorWithNestedGrpcStatus {
211 public:
deadline() const212 grpc_millis deadline() const { return deadline_; }
error() const213 grpc_error* error() const { return error_.get(); }
214
215 private:
216 const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
217 ErrorPtr nested_error_{grpc_error_set_int(
218 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
219 GRPC_STATUS_UNIMPLEMENTED)};
220 grpc_error* nested_errors_[1] = {nested_error_.get()};
221 ErrorPtr error_{GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
222 "Error", nested_errors_, 1)};
223 };
224
225 template <class Fixture>
BM_ErrorStringOnNewError(benchmark::State & state)226 static void BM_ErrorStringOnNewError(benchmark::State& state) {
227 TrackCounters track_counters;
228 for (auto _ : state) {
229 Fixture fixture;
230 grpc_error_string(fixture.error());
231 }
232 track_counters.Finish(state);
233 }
234
235 template <class Fixture>
BM_ErrorStringRepeatedly(benchmark::State & state)236 static void BM_ErrorStringRepeatedly(benchmark::State& state) {
237 TrackCounters track_counters;
238 Fixture fixture;
239 for (auto _ : state) {
240 grpc_error_string(fixture.error());
241 }
242 track_counters.Finish(state);
243 }
244
245 template <class Fixture>
BM_ErrorGetStatus(benchmark::State & state)246 static void BM_ErrorGetStatus(benchmark::State& state) {
247 TrackCounters track_counters;
248 Fixture fixture;
249 grpc_core::ExecCtx exec_ctx;
250 for (auto _ : state) {
251 grpc_status_code status;
252 grpc_slice slice;
253 grpc_error_get_status(fixture.error(), fixture.deadline(), &status, &slice,
254 nullptr, nullptr);
255 }
256
257 track_counters.Finish(state);
258 }
259
260 template <class Fixture>
BM_ErrorGetStatusCode(benchmark::State & state)261 static void BM_ErrorGetStatusCode(benchmark::State& state) {
262 TrackCounters track_counters;
263 Fixture fixture;
264 grpc_core::ExecCtx exec_ctx;
265 for (auto _ : state) {
266 grpc_status_code status;
267 grpc_error_get_status(fixture.error(), fixture.deadline(), &status, nullptr,
268 nullptr, nullptr);
269 }
270
271 track_counters.Finish(state);
272 }
273
274 template <class Fixture>
BM_ErrorHttpError(benchmark::State & state)275 static void BM_ErrorHttpError(benchmark::State& state) {
276 TrackCounters track_counters;
277 Fixture fixture;
278 grpc_core::ExecCtx exec_ctx;
279 for (auto _ : state) {
280 grpc_http2_error_code error;
281 grpc_error_get_status(fixture.error(), fixture.deadline(), nullptr, nullptr,
282 &error, nullptr);
283 }
284
285 track_counters.Finish(state);
286 }
287
288 template <class Fixture>
BM_HasClearGrpcStatus(benchmark::State & state)289 static void BM_HasClearGrpcStatus(benchmark::State& state) {
290 TrackCounters track_counters;
291 Fixture fixture;
292 for (auto _ : state) {
293 grpc_error_has_clear_grpc_status(fixture.error());
294 }
295 track_counters.Finish(state);
296 }
297
298 #define BENCHMARK_SUITE(fixture) \
299 BENCHMARK_TEMPLATE(BM_ErrorStringOnNewError, fixture); \
300 BENCHMARK_TEMPLATE(BM_ErrorStringRepeatedly, fixture); \
301 BENCHMARK_TEMPLATE(BM_ErrorGetStatus, fixture); \
302 BENCHMARK_TEMPLATE(BM_ErrorGetStatusCode, fixture); \
303 BENCHMARK_TEMPLATE(BM_ErrorHttpError, fixture); \
304 BENCHMARK_TEMPLATE(BM_HasClearGrpcStatus, fixture)
305
306 BENCHMARK_SUITE(ErrorNone);
307 BENCHMARK_SUITE(ErrorCancelled);
308 BENCHMARK_SUITE(SimpleError);
309 BENCHMARK_SUITE(ErrorWithGrpcStatus);
310 BENCHMARK_SUITE(ErrorWithHttpError);
311 BENCHMARK_SUITE(ErrorWithNestedGrpcStatus);
312
313 // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
314 // and others do not. This allows us to support both modes.
315 namespace benchmark {
RunTheBenchmarksNamespaced()316 void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
317 } // namespace benchmark
318
main(int argc,char ** argv)319 int main(int argc, char** argv) {
320 grpc::testing::TestEnvironment env(argc, argv);
321 LibraryInitializer libInit;
322 ::benchmark::Initialize(&argc, argv);
323 ::grpc::testing::InitTest(&argc, &argv, false);
324 benchmark::RunTheBenchmarksNamespaced();
325 return 0;
326 }
327