blob: 696b453fa312acb669828e53a320c0a3cfc4d48e [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
Craig Tillere89e54f2016-11-29 08:20:05 -080074 ~InitializeStuff() { init_lib_.shutdown(); }
David Garcia Quintasd4490032016-11-28 16:10:57 -080075
Craig Tiller63ec2932016-11-01 15:00:41 -070076 grpc_resource_quota* rq() { return rq_; }
Craig Tiller1d0fce92016-10-26 08:26:22 -070077
78 private:
Craig Tiller63ec2932016-11-01 15:00:41 -070079 internal::GrpcLibrary init_lib_;
80 grpc_resource_quota* rq_;
Craig Tiller1d0fce92016-10-26 08:26:22 -070081} initialize_stuff;
82
Craig Tiller93d802b2016-10-25 21:05:49 -070083/*******************************************************************************
84 * FIXTURES
85 */
86
Craig Tiller1d0fce92016-10-26 08:26:22 -070087class FullstackFixture {
Craig Tiller93d802b2016-10-25 21:05:49 -070088 public:
Craig Tiller1d0fce92016-10-26 08:26:22 -070089 FullstackFixture(Service* service, const grpc::string& address) {
Craig Tiller93d802b2016-10-25 21:05:49 -070090 ServerBuilder b;
Craig Tiller1d0fce92016-10-26 08:26:22 -070091 b.AddListeningPort(address, InsecureServerCredentials());
Craig Tiller93d802b2016-10-25 21:05:49 -070092 cq_ = b.AddCompletionQueue(true);
93 b.RegisterService(service);
94 server_ = b.BuildAndStart();
Craig Tiller1d0fce92016-10-26 08:26:22 -070095 channel_ = CreateChannel(address, InsecureChannelCredentials());
Craig Tiller93d802b2016-10-25 21:05:49 -070096 }
97
Craig Tillerb4d883b2016-11-01 15:10:22 -070098 virtual ~FullstackFixture() {
99 server_->Shutdown();
100 cq_->Shutdown();
101 void* tag;
102 bool ok;
103 while (cq_->Next(&tag, &ok)) {
104 }
105 }
106
Craig Tiller93d802b2016-10-25 21:05:49 -0700107 ServerCompletionQueue* cq() { return cq_.get(); }
Craig Tiller93d802b2016-10-25 21:05:49 -0700108 std::shared_ptr<Channel> channel() { return channel_; }
109
110 private:
111 std::unique_ptr<Server> server_;
112 std::unique_ptr<ServerCompletionQueue> cq_;
113 std::shared_ptr<Channel> channel_;
114};
115
Craig Tiller1d0fce92016-10-26 08:26:22 -0700116class TCP : public FullstackFixture {
117 public:
118 TCP(Service* service) : FullstackFixture(service, MakeAddress()) {}
119
120 private:
121 static grpc::string MakeAddress() {
122 int port = grpc_pick_unused_port_or_die();
123 std::stringstream addr;
124 addr << "localhost:" << port;
125 return addr.str();
126 }
127};
128
129class UDS : public FullstackFixture {
130 public:
Craig Tillerd04c8222016-11-29 08:54:36 -0800131 UDS(Service* service) : FullstackFixture(service, MakeAddress()) {}
132
133 private:
134 static grpc::string MakeAddress() {
135 int port = grpc_pick_unused_port_or_die(); // just for a unique id - not a
136 // real port
137 std::stringstream addr;
138 addr << "unix:/tmp/bm_fullstack." << port;
139 return addr.str();
140 }
Craig Tiller1d0fce92016-10-26 08:26:22 -0700141};
142
143class EndpointPairFixture {
144 public:
145 EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints) {
146 ServerBuilder b;
147 cq_ = b.AddCompletionQueue(true);
148 b.RegisterService(service);
149 server_ = b.BuildAndStart();
150
151 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
152
153 /* add server endpoint to server_ */
154 {
155 const grpc_channel_args* server_args =
156 grpc_server_get_channel_args(server_->c_server());
157 grpc_transport* transport = grpc_create_chttp2_transport(
158 &exec_ctx, server_args, endpoints.server, 0 /* is_client */);
159
160 grpc_pollset** pollsets;
161 size_t num_pollsets = 0;
162 grpc_server_get_pollsets(server_->c_server(), &pollsets, &num_pollsets);
163
164 for (size_t i = 0; i < num_pollsets; i++) {
165 grpc_endpoint_add_to_pollset(&exec_ctx, endpoints.server, pollsets[i]);
166 }
167
168 grpc_server_setup_transport(&exec_ctx, server_->c_server(), transport,
169 NULL, server_args);
170 grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
171 }
172
173 /* create channel */
174 {
175 ChannelArguments args;
176 args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
177
Craig Tillerf6936972016-11-16 15:03:53 -0800178 grpc_channel_args c_args = args.c_channel_args();
Craig Tiller1d0fce92016-10-26 08:26:22 -0700179 grpc_transport* transport =
180 grpc_create_chttp2_transport(&exec_ctx, &c_args, endpoints.client, 1);
181 GPR_ASSERT(transport);
182 grpc_channel* channel = grpc_channel_create(
183 &exec_ctx, "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
184 grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
185
186 channel_ = CreateChannelInternal("", channel);
187 }
188
189 grpc_exec_ctx_finish(&exec_ctx);
190 }
191
Craig Tillerb4d883b2016-11-01 15:10:22 -0700192 virtual ~EndpointPairFixture() {
193 server_->Shutdown();
194 cq_->Shutdown();
195 void* tag;
196 bool ok;
197 while (cq_->Next(&tag, &ok)) {
198 }
199 }
200
Craig Tiller1d0fce92016-10-26 08:26:22 -0700201 ServerCompletionQueue* cq() { return cq_.get(); }
202 std::shared_ptr<Channel> channel() { return channel_; }
203
204 private:
205 std::unique_ptr<Server> server_;
206 std::unique_ptr<ServerCompletionQueue> cq_;
207 std::shared_ptr<Channel> channel_;
208};
209
210class SockPair : public EndpointPairFixture {
211 public:
212 SockPair(Service* service)
Craig Tiller63ec2932016-11-01 15:00:41 -0700213 : EndpointPairFixture(service, grpc_iomgr_create_endpoint_pair(
214 "test", initialize_stuff.rq(), 8192)) {
215 }
Craig Tiller1d0fce92016-10-26 08:26:22 -0700216};
217
218class InProcessCHTTP2 : public EndpointPairFixture {
219 public:
220 InProcessCHTTP2(Service* service)
221 : EndpointPairFixture(service, MakeEndpoints()) {}
222
223 private:
224 grpc_endpoint_pair MakeEndpoints() {
225 grpc_endpoint_pair p;
Craig Tiller63ec2932016-11-01 15:00:41 -0700226 grpc_passthru_endpoint_create(&p.client, &p.server, initialize_stuff.rq());
Craig Tiller1d0fce92016-10-26 08:26:22 -0700227 return p;
228 }
229};
230
Craig Tiller93d802b2016-10-25 21:05:49 -0700231/*******************************************************************************
Craig Tiller206efc72016-11-07 12:55:40 -0800232 * CONTEXT MUTATORS
233 */
234
235static const int kPregenerateKeyCount = 10000000;
236
237template <class F>
238auto MakeVector(size_t length, F f) -> std::vector<decltype(f())> {
239 std::vector<decltype(f())> out;
240 out.reserve(length);
241 for (size_t i = 0; i < length; i++) {
242 out.push_back(f());
243 }
244 return out;
245}
246
247class NoOpMutator {
248 public:
249 template <class ContextType>
250 NoOpMutator(ContextType* context) {}
251};
252
253template <int length>
254class RandomBinaryMetadata {
255 public:
256 static const grpc::string& Key() { return kKey; }
257
258 static const grpc::string& Value() {
259 return kValues[rand() % kValues.size()];
260 }
261
262 private:
263 static const grpc::string kKey;
264 static const std::vector<grpc::string> kValues;
265
266 static grpc::string GenerateOneString() {
267 grpc::string s;
268 s.reserve(length + 1);
269 for (int i = 0; i < length; i++) {
270 s += (char)rand();
271 }
272 return s;
273 }
274};
275
276template <int length>
277const grpc::string RandomBinaryMetadata<length>::kKey = "foo-bin";
278
279template <int length>
280const std::vector<grpc::string> RandomBinaryMetadata<length>::kValues =
281 MakeVector(kPregenerateKeyCount, GenerateOneString);
282
283template <int length>
284class RandomAsciiMetadata {
285 public:
286 static const grpc::string& Key() { return kKey; }
287
288 static const grpc::string& Value() {
289 return kValues[rand() % kValues.size()];
290 }
291
292 private:
293 static const grpc::string kKey;
294 static const std::vector<grpc::string> kValues;
295
296 static grpc::string GenerateOneString() {
297 grpc::string s;
298 s.reserve(length + 1);
299 for (int i = 0; i < length; i++) {
300 s += (char)(rand() % 26 + 'a');
301 }
302 return s;
303 }
304};
305
306template <int length>
307const grpc::string RandomAsciiMetadata<length>::kKey = "foo";
308
309template <int length>
310const std::vector<grpc::string> RandomAsciiMetadata<length>::kValues =
311 MakeVector(kPregenerateKeyCount, GenerateOneString);
312
313template <class Generator, int kNumKeys>
314class Client_AddMetadata : public NoOpMutator {
315 public:
316 Client_AddMetadata(ClientContext* context) : NoOpMutator(context) {
317 for (int i = 0; i < kNumKeys; i++) {
318 context->AddMetadata(Generator::Key(), Generator::Value());
319 }
320 }
321};
322
323template <class Generator, int kNumKeys>
324class Server_AddInitialMetadata : public NoOpMutator {
325 public:
326 Server_AddInitialMetadata(ServerContext* context) : NoOpMutator(context) {
327 for (int i = 0; i < kNumKeys; i++) {
328 context->AddInitialMetadata(Generator::Key(), Generator::Value());
329 }
330 }
331};
332
333/*******************************************************************************
Craig Tiller93d802b2016-10-25 21:05:49 -0700334 * BENCHMARKING KERNELS
335 */
336
337static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
338
Craig Tiller206efc72016-11-07 12:55:40 -0800339template <class Fixture, class ClientContextMutator, class ServerContextMutator>
Craig Tiller93d802b2016-10-25 21:05:49 -0700340static void BM_UnaryPingPong(benchmark::State& state) {
341 EchoTestService::AsyncService service;
Craig Tillerff8e43a2016-11-01 15:13:31 -0700342 std::unique_ptr<Fixture> fixture(new Fixture(&service));
Craig Tiller93d802b2016-10-25 21:05:49 -0700343 EchoRequest send_request;
344 EchoResponse send_response;
345 EchoResponse recv_response;
346 Status recv_status;
347 struct ServerEnv {
348 ServerContext ctx;
349 EchoRequest recv_request;
350 grpc::ServerAsyncResponseWriter<EchoResponse> response_writer;
351 ServerEnv() : response_writer(&ctx) {}
352 };
353 uint8_t server_env_buffer[2 * sizeof(ServerEnv)];
354 ServerEnv* server_env[2] = {
355 reinterpret_cast<ServerEnv*>(server_env_buffer),
356 reinterpret_cast<ServerEnv*>(server_env_buffer + sizeof(ServerEnv))};
357 new (server_env[0]) ServerEnv;
358 new (server_env[1]) ServerEnv;
359 service.RequestEcho(&server_env[0]->ctx, &server_env[0]->recv_request,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700360 &server_env[0]->response_writer, fixture->cq(),
361 fixture->cq(), tag(0));
Craig Tiller93d802b2016-10-25 21:05:49 -0700362 service.RequestEcho(&server_env[1]->ctx, &server_env[1]->recv_request,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700363 &server_env[1]->response_writer, fixture->cq(),
364 fixture->cq(), tag(1));
Craig Tiller93d802b2016-10-25 21:05:49 -0700365 std::unique_ptr<EchoTestService::Stub> stub(
Craig Tillerff8e43a2016-11-01 15:13:31 -0700366 EchoTestService::NewStub(fixture->channel()));
Craig Tiller93d802b2016-10-25 21:05:49 -0700367 while (state.KeepRunning()) {
368 ClientContext cli_ctx;
Craig Tiller206efc72016-11-07 12:55:40 -0800369 ClientContextMutator cli_ctx_mut(&cli_ctx);
Craig Tiller93d802b2016-10-25 21:05:49 -0700370 std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
Craig Tillerff8e43a2016-11-01 15:13:31 -0700371 stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
Craig Tiller93d802b2016-10-25 21:05:49 -0700372 void* t;
373 bool ok;
Craig Tillerff8e43a2016-11-01 15:13:31 -0700374 GPR_ASSERT(fixture->cq()->Next(&t, &ok));
Craig Tiller93d802b2016-10-25 21:05:49 -0700375 GPR_ASSERT(ok);
376 GPR_ASSERT(t == tag(0) || t == tag(1));
377 intptr_t slot = reinterpret_cast<intptr_t>(t);
378 ServerEnv* senv = server_env[slot];
Craig Tiller206efc72016-11-07 12:55:40 -0800379 ServerContextMutator svr_ctx_mut(&senv->ctx);
Craig Tiller93d802b2016-10-25 21:05:49 -0700380 senv->response_writer.Finish(send_response, Status::OK, tag(3));
381 response_reader->Finish(&recv_response, &recv_status, tag(4));
382 for (int i = (1 << 3) | (1 << 4); i != 0;) {
Craig Tillerff8e43a2016-11-01 15:13:31 -0700383 GPR_ASSERT(fixture->cq()->Next(&t, &ok));
Craig Tiller93d802b2016-10-25 21:05:49 -0700384 GPR_ASSERT(ok);
385 int tagnum = (int)reinterpret_cast<intptr_t>(t);
386 GPR_ASSERT(i & (1 << tagnum));
387 i -= 1 << tagnum;
388 }
389 GPR_ASSERT(recv_status.ok());
390
391 senv->~ServerEnv();
392 senv = new (senv) ServerEnv();
393 service.RequestEcho(&senv->ctx, &senv->recv_request, &senv->response_writer,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700394 fixture->cq(), fixture->cq(), tag(slot));
Craig Tiller93d802b2016-10-25 21:05:49 -0700395 }
Craig Tillerff8e43a2016-11-01 15:13:31 -0700396 fixture.reset();
Craig Tillerb4d883b2016-11-01 15:10:22 -0700397 server_env[0]->~ServerEnv();
398 server_env[1]->~ServerEnv();
Craig Tiller93d802b2016-10-25 21:05:49 -0700399}
400
401/*******************************************************************************
402 * CONFIGURATIONS
403 */
404
Craig Tiller206efc72016-11-07 12:55:40 -0800405BENCHMARK_TEMPLATE(BM_UnaryPingPong, TCP, NoOpMutator, NoOpMutator);
406BENCHMARK_TEMPLATE(BM_UnaryPingPong, UDS, NoOpMutator, NoOpMutator);
407BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator);
408BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator, NoOpMutator);
409BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
410 Client_AddMetadata<RandomBinaryMetadata<10>, 1>,
411 NoOpMutator);
412BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
413 Client_AddMetadata<RandomBinaryMetadata<31>, 1>,
414 NoOpMutator);
415BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
416 Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
417 NoOpMutator);
418BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
419 Client_AddMetadata<RandomBinaryMetadata<10>, 2>,
420 NoOpMutator);
421BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
422 Client_AddMetadata<RandomBinaryMetadata<31>, 2>,
423 NoOpMutator);
424BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
425 Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
426 NoOpMutator);
427BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
428 Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>);
429BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
430 Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>);
431BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
432 Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>);
433BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
434 Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator);
435BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
436 Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator);
437BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
438 Client_AddMetadata<RandomAsciiMetadata<100>, 1>,
439 NoOpMutator);
440BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
441 Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>);
442BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
443 Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>);
444BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
445 Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>);
Craig Tiller93d802b2016-10-25 21:05:49 -0700446
447} // namespace testing
448} // namespace grpc
449
450BENCHMARK_MAIN();