blob: 3528d95b5db194f3885b74e1320ae52e5ab139f9 [file] [log] [blame]
Craig Tiller93d802b2016-10-25 21:05:49 -07001/*
2 *
3 * Copyright 2016, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34/* Benchmark gRPC end2end in various configurations */
35
36#include <sstream>
37
38#include <grpc++/channel.h>
39#include <grpc++/create_channel.h>
Craig Tiller1d0fce92016-10-26 08:26:22 -070040#include <grpc++/impl/grpc_library.h>
Craig Tiller93d802b2016-10-25 21:05:49 -070041#include <grpc++/security/credentials.h>
42#include <grpc++/security/server_credentials.h>
43#include <grpc++/server.h>
44#include <grpc++/server_builder.h>
45#include <grpc/support/log.h>
46
Craig Tiller1d0fce92016-10-26 08:26:22 -070047extern "C" {
48#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
49#include "src/core/lib/channel/channel_args.h"
50#include "src/core/lib/iomgr/endpoint.h"
51#include "src/core/lib/iomgr/endpoint_pair.h"
52#include "src/core/lib/iomgr/exec_ctx.h"
53#include "src/core/lib/iomgr/tcp_posix.h"
54#include "src/core/lib/surface/channel.h"
55#include "src/core/lib/surface/completion_queue.h"
56#include "src/core/lib/surface/server.h"
57#include "test/core/util/passthru_endpoint.h"
Craig Tiller93d802b2016-10-25 21:05:49 -070058#include "test/core/util/port.h"
Craig Tiller1d0fce92016-10-26 08:26:22 -070059}
60#include "src/cpp/client/create_channel_internal.h"
61#include "src/proto/grpc/testing/echo.grpc.pb.h"
Craig Tiller93d802b2016-10-25 21:05:49 -070062#include "third_party/google_benchmark/include/benchmark/benchmark.h"
63
64namespace grpc {
65namespace testing {
66
Craig Tiller1d0fce92016-10-26 08:26:22 -070067static class InitializeStuff {
68 public:
Craig Tiller63ec2932016-11-01 15:00:41 -070069 InitializeStuff() {
70 init_lib_.init();
71 rq_ = grpc_resource_quota_create("bm");
72 }
73
74 grpc_resource_quota* rq() { return rq_; }
Craig Tiller1d0fce92016-10-26 08:26:22 -070075
76 private:
Craig Tiller63ec2932016-11-01 15:00:41 -070077 internal::GrpcLibrary init_lib_;
78 grpc_resource_quota* rq_;
Craig Tiller1d0fce92016-10-26 08:26:22 -070079} initialize_stuff;
80
Craig Tiller93d802b2016-10-25 21:05:49 -070081/*******************************************************************************
82 * FIXTURES
83 */
84
Craig Tiller1d0fce92016-10-26 08:26:22 -070085class FullstackFixture {
Craig Tiller93d802b2016-10-25 21:05:49 -070086 public:
Craig Tiller1d0fce92016-10-26 08:26:22 -070087 FullstackFixture(Service* service, const grpc::string& address) {
Craig Tiller93d802b2016-10-25 21:05:49 -070088 ServerBuilder b;
Craig Tiller1d0fce92016-10-26 08:26:22 -070089 b.AddListeningPort(address, InsecureServerCredentials());
Craig Tiller93d802b2016-10-25 21:05:49 -070090 cq_ = b.AddCompletionQueue(true);
91 b.RegisterService(service);
92 server_ = b.BuildAndStart();
Craig Tiller1d0fce92016-10-26 08:26:22 -070093 channel_ = CreateChannel(address, InsecureChannelCredentials());
Craig Tiller93d802b2016-10-25 21:05:49 -070094 }
95
Craig Tillerb4d883b2016-11-01 15:10:22 -070096 virtual ~FullstackFixture() {
97 server_->Shutdown();
98 cq_->Shutdown();
99 void* tag;
100 bool ok;
101 while (cq_->Next(&tag, &ok)) {
102 }
103 }
104
Craig Tiller93d802b2016-10-25 21:05:49 -0700105 ServerCompletionQueue* cq() { return cq_.get(); }
Craig Tiller93d802b2016-10-25 21:05:49 -0700106 std::shared_ptr<Channel> channel() { return channel_; }
107
108 private:
109 std::unique_ptr<Server> server_;
110 std::unique_ptr<ServerCompletionQueue> cq_;
111 std::shared_ptr<Channel> channel_;
112};
113
Craig Tiller1d0fce92016-10-26 08:26:22 -0700114class TCP : public FullstackFixture {
115 public:
116 TCP(Service* service) : FullstackFixture(service, MakeAddress()) {}
117
118 private:
119 static grpc::string MakeAddress() {
120 int port = grpc_pick_unused_port_or_die();
121 std::stringstream addr;
122 addr << "localhost:" << port;
123 return addr.str();
124 }
125};
126
127class UDS : public FullstackFixture {
128 public:
129 UDS(Service* service) : FullstackFixture(service, "unix:bm_fullstack") {}
130};
131
132class EndpointPairFixture {
133 public:
134 EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints) {
135 ServerBuilder b;
136 cq_ = b.AddCompletionQueue(true);
137 b.RegisterService(service);
138 server_ = b.BuildAndStart();
139
140 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
141
142 /* add server endpoint to server_ */
143 {
144 const grpc_channel_args* server_args =
145 grpc_server_get_channel_args(server_->c_server());
146 grpc_transport* transport = grpc_create_chttp2_transport(
147 &exec_ctx, server_args, endpoints.server, 0 /* is_client */);
148
149 grpc_pollset** pollsets;
150 size_t num_pollsets = 0;
151 grpc_server_get_pollsets(server_->c_server(), &pollsets, &num_pollsets);
152
153 for (size_t i = 0; i < num_pollsets; i++) {
154 grpc_endpoint_add_to_pollset(&exec_ctx, endpoints.server, pollsets[i]);
155 }
156
157 grpc_server_setup_transport(&exec_ctx, server_->c_server(), transport,
158 NULL, server_args);
159 grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
160 }
161
162 /* create channel */
163 {
164 ChannelArguments args;
165 args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
166
Craig Tillerf6936972016-11-16 15:03:53 -0800167 grpc_channel_args c_args = args.c_channel_args();
Craig Tiller1d0fce92016-10-26 08:26:22 -0700168 grpc_transport* transport =
169 grpc_create_chttp2_transport(&exec_ctx, &c_args, endpoints.client, 1);
170 GPR_ASSERT(transport);
171 grpc_channel* channel = grpc_channel_create(
172 &exec_ctx, "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
173 grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
174
175 channel_ = CreateChannelInternal("", channel);
176 }
177
178 grpc_exec_ctx_finish(&exec_ctx);
179 }
180
Craig Tillerb4d883b2016-11-01 15:10:22 -0700181 virtual ~EndpointPairFixture() {
182 server_->Shutdown();
183 cq_->Shutdown();
184 void* tag;
185 bool ok;
186 while (cq_->Next(&tag, &ok)) {
187 }
188 }
189
Craig Tiller1d0fce92016-10-26 08:26:22 -0700190 ServerCompletionQueue* cq() { return cq_.get(); }
191 std::shared_ptr<Channel> channel() { return channel_; }
192
193 private:
194 std::unique_ptr<Server> server_;
195 std::unique_ptr<ServerCompletionQueue> cq_;
196 std::shared_ptr<Channel> channel_;
197};
198
199class SockPair : public EndpointPairFixture {
200 public:
201 SockPair(Service* service)
Craig Tiller63ec2932016-11-01 15:00:41 -0700202 : EndpointPairFixture(service, grpc_iomgr_create_endpoint_pair(
203 "test", initialize_stuff.rq(), 8192)) {
204 }
Craig Tiller1d0fce92016-10-26 08:26:22 -0700205};
206
207class InProcessCHTTP2 : public EndpointPairFixture {
208 public:
209 InProcessCHTTP2(Service* service)
210 : EndpointPairFixture(service, MakeEndpoints()) {}
211
212 private:
213 grpc_endpoint_pair MakeEndpoints() {
214 grpc_endpoint_pair p;
Craig Tiller63ec2932016-11-01 15:00:41 -0700215 grpc_passthru_endpoint_create(&p.client, &p.server, initialize_stuff.rq());
Craig Tiller1d0fce92016-10-26 08:26:22 -0700216 return p;
217 }
218};
219
Craig Tiller93d802b2016-10-25 21:05:49 -0700220/*******************************************************************************
Craig Tiller206efc72016-11-07 12:55:40 -0800221 * CONTEXT MUTATORS
222 */
223
Craig Tiller3b05e1d2016-11-21 13:46:31 -0800224static const int kPregenerateKeyCount = 1000000;
Craig Tiller206efc72016-11-07 12:55:40 -0800225
226template <class F>
227auto MakeVector(size_t length, F f) -> std::vector<decltype(f())> {
228 std::vector<decltype(f())> out;
229 out.reserve(length);
230 for (size_t i = 0; i < length; i++) {
231 out.push_back(f());
232 }
233 return out;
234}
235
236class NoOpMutator {
237 public:
238 template <class ContextType>
239 NoOpMutator(ContextType* context) {}
240};
241
242template <int length>
243class RandomBinaryMetadata {
244 public:
245 static const grpc::string& Key() { return kKey; }
246
247 static const grpc::string& Value() {
248 return kValues[rand() % kValues.size()];
249 }
250
251 private:
252 static const grpc::string kKey;
253 static const std::vector<grpc::string> kValues;
254
255 static grpc::string GenerateOneString() {
256 grpc::string s;
257 s.reserve(length + 1);
258 for (int i = 0; i < length; i++) {
259 s += (char)rand();
260 }
261 return s;
262 }
263};
264
265template <int length>
266const grpc::string RandomBinaryMetadata<length>::kKey = "foo-bin";
267
268template <int length>
269const std::vector<grpc::string> RandomBinaryMetadata<length>::kValues =
270 MakeVector(kPregenerateKeyCount, GenerateOneString);
271
272template <int length>
273class RandomAsciiMetadata {
274 public:
275 static const grpc::string& Key() { return kKey; }
276
277 static const grpc::string& Value() {
278 return kValues[rand() % kValues.size()];
279 }
280
281 private:
282 static const grpc::string kKey;
283 static const std::vector<grpc::string> kValues;
284
285 static grpc::string GenerateOneString() {
286 grpc::string s;
287 s.reserve(length + 1);
288 for (int i = 0; i < length; i++) {
289 s += (char)(rand() % 26 + 'a');
290 }
291 return s;
292 }
293};
294
295template <int length>
296const grpc::string RandomAsciiMetadata<length>::kKey = "foo";
297
298template <int length>
299const std::vector<grpc::string> RandomAsciiMetadata<length>::kValues =
300 MakeVector(kPregenerateKeyCount, GenerateOneString);
301
302template <class Generator, int kNumKeys>
303class Client_AddMetadata : public NoOpMutator {
304 public:
305 Client_AddMetadata(ClientContext* context) : NoOpMutator(context) {
306 for (int i = 0; i < kNumKeys; i++) {
307 context->AddMetadata(Generator::Key(), Generator::Value());
308 }
309 }
310};
311
312template <class Generator, int kNumKeys>
313class Server_AddInitialMetadata : public NoOpMutator {
314 public:
315 Server_AddInitialMetadata(ServerContext* context) : NoOpMutator(context) {
316 for (int i = 0; i < kNumKeys; i++) {
317 context->AddInitialMetadata(Generator::Key(), Generator::Value());
318 }
319 }
320};
321
322/*******************************************************************************
Craig Tiller93d802b2016-10-25 21:05:49 -0700323 * BENCHMARKING KERNELS
324 */
325
326static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
327
Craig Tiller206efc72016-11-07 12:55:40 -0800328template <class Fixture, class ClientContextMutator, class ServerContextMutator>
Craig Tiller93d802b2016-10-25 21:05:49 -0700329static void BM_UnaryPingPong(benchmark::State& state) {
330 EchoTestService::AsyncService service;
Craig Tillerff8e43a2016-11-01 15:13:31 -0700331 std::unique_ptr<Fixture> fixture(new Fixture(&service));
Craig Tiller93d802b2016-10-25 21:05:49 -0700332 EchoRequest send_request;
333 EchoResponse send_response;
334 EchoResponse recv_response;
335 Status recv_status;
336 struct ServerEnv {
337 ServerContext ctx;
338 EchoRequest recv_request;
339 grpc::ServerAsyncResponseWriter<EchoResponse> response_writer;
340 ServerEnv() : response_writer(&ctx) {}
341 };
342 uint8_t server_env_buffer[2 * sizeof(ServerEnv)];
343 ServerEnv* server_env[2] = {
344 reinterpret_cast<ServerEnv*>(server_env_buffer),
345 reinterpret_cast<ServerEnv*>(server_env_buffer + sizeof(ServerEnv))};
346 new (server_env[0]) ServerEnv;
347 new (server_env[1]) ServerEnv;
348 service.RequestEcho(&server_env[0]->ctx, &server_env[0]->recv_request,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700349 &server_env[0]->response_writer, fixture->cq(),
350 fixture->cq(), tag(0));
Craig Tiller93d802b2016-10-25 21:05:49 -0700351 service.RequestEcho(&server_env[1]->ctx, &server_env[1]->recv_request,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700352 &server_env[1]->response_writer, fixture->cq(),
353 fixture->cq(), tag(1));
Craig Tiller93d802b2016-10-25 21:05:49 -0700354 std::unique_ptr<EchoTestService::Stub> stub(
Craig Tillerff8e43a2016-11-01 15:13:31 -0700355 EchoTestService::NewStub(fixture->channel()));
Craig Tiller93d802b2016-10-25 21:05:49 -0700356 while (state.KeepRunning()) {
357 ClientContext cli_ctx;
Craig Tiller206efc72016-11-07 12:55:40 -0800358 ClientContextMutator cli_ctx_mut(&cli_ctx);
Craig Tiller93d802b2016-10-25 21:05:49 -0700359 std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
Craig Tillerff8e43a2016-11-01 15:13:31 -0700360 stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
Craig Tiller93d802b2016-10-25 21:05:49 -0700361 void* t;
362 bool ok;
Craig Tillerff8e43a2016-11-01 15:13:31 -0700363 GPR_ASSERT(fixture->cq()->Next(&t, &ok));
Craig Tiller93d802b2016-10-25 21:05:49 -0700364 GPR_ASSERT(ok);
365 GPR_ASSERT(t == tag(0) || t == tag(1));
366 intptr_t slot = reinterpret_cast<intptr_t>(t);
367 ServerEnv* senv = server_env[slot];
Craig Tiller206efc72016-11-07 12:55:40 -0800368 ServerContextMutator svr_ctx_mut(&senv->ctx);
Craig Tiller93d802b2016-10-25 21:05:49 -0700369 senv->response_writer.Finish(send_response, Status::OK, tag(3));
370 response_reader->Finish(&recv_response, &recv_status, tag(4));
371 for (int i = (1 << 3) | (1 << 4); i != 0;) {
Craig Tillerff8e43a2016-11-01 15:13:31 -0700372 GPR_ASSERT(fixture->cq()->Next(&t, &ok));
Craig Tiller93d802b2016-10-25 21:05:49 -0700373 GPR_ASSERT(ok);
374 int tagnum = (int)reinterpret_cast<intptr_t>(t);
375 GPR_ASSERT(i & (1 << tagnum));
376 i -= 1 << tagnum;
377 }
378 GPR_ASSERT(recv_status.ok());
379
380 senv->~ServerEnv();
381 senv = new (senv) ServerEnv();
382 service.RequestEcho(&senv->ctx, &senv->recv_request, &senv->response_writer,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700383 fixture->cq(), fixture->cq(), tag(slot));
Craig Tiller93d802b2016-10-25 21:05:49 -0700384 }
Craig Tillerff8e43a2016-11-01 15:13:31 -0700385 fixture.reset();
Craig Tillerb4d883b2016-11-01 15:10:22 -0700386 server_env[0]->~ServerEnv();
387 server_env[1]->~ServerEnv();
Craig Tiller93d802b2016-10-25 21:05:49 -0700388}
389
390/*******************************************************************************
391 * CONFIGURATIONS
392 */
393
Craig Tiller206efc72016-11-07 12:55:40 -0800394BENCHMARK_TEMPLATE(BM_UnaryPingPong, TCP, NoOpMutator, NoOpMutator);
395BENCHMARK_TEMPLATE(BM_UnaryPingPong, UDS, NoOpMutator, NoOpMutator);
396BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator);
397BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator, NoOpMutator);
398BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
399 Client_AddMetadata<RandomBinaryMetadata<10>, 1>,
400 NoOpMutator);
401BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
402 Client_AddMetadata<RandomBinaryMetadata<31>, 1>,
403 NoOpMutator);
404BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
405 Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
406 NoOpMutator);
407BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
408 Client_AddMetadata<RandomBinaryMetadata<10>, 2>,
409 NoOpMutator);
410BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
411 Client_AddMetadata<RandomBinaryMetadata<31>, 2>,
412 NoOpMutator);
413BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
414 Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
415 NoOpMutator);
416BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
417 Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>);
418BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
419 Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>);
420BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
421 Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>);
422BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
423 Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator);
424BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
425 Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator);
426BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
427 Client_AddMetadata<RandomAsciiMetadata<100>, 1>,
428 NoOpMutator);
429BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
430 Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>);
431BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
432 Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>);
433BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
434 Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>);
Craig Tiller93d802b2016-10-25 21:05:49 -0700435
436} // namespace testing
437} // namespace grpc
438
439BENCHMARK_MAIN();