blob: 559e66cdd706cff9256cd6b8f99ef58b7b73d2f6 [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:
131 UDS(Service* service) : FullstackFixture(service, "unix:bm_fullstack") {}
132};
133
134class EndpointPairFixture {
135 public:
136 EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints) {
137 ServerBuilder b;
138 cq_ = b.AddCompletionQueue(true);
139 b.RegisterService(service);
140 server_ = b.BuildAndStart();
141
142 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
143
144 /* add server endpoint to server_ */
145 {
146 const grpc_channel_args* server_args =
147 grpc_server_get_channel_args(server_->c_server());
148 grpc_transport* transport = grpc_create_chttp2_transport(
149 &exec_ctx, server_args, endpoints.server, 0 /* is_client */);
150
151 grpc_pollset** pollsets;
152 size_t num_pollsets = 0;
153 grpc_server_get_pollsets(server_->c_server(), &pollsets, &num_pollsets);
154
155 for (size_t i = 0; i < num_pollsets; i++) {
156 grpc_endpoint_add_to_pollset(&exec_ctx, endpoints.server, pollsets[i]);
157 }
158
159 grpc_server_setup_transport(&exec_ctx, server_->c_server(), transport,
160 NULL, server_args);
161 grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
162 }
163
164 /* create channel */
165 {
166 ChannelArguments args;
167 args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
168
Craig Tillerf6936972016-11-16 15:03:53 -0800169 grpc_channel_args c_args = args.c_channel_args();
Craig Tiller1d0fce92016-10-26 08:26:22 -0700170 grpc_transport* transport =
171 grpc_create_chttp2_transport(&exec_ctx, &c_args, endpoints.client, 1);
172 GPR_ASSERT(transport);
173 grpc_channel* channel = grpc_channel_create(
174 &exec_ctx, "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
175 grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
176
177 channel_ = CreateChannelInternal("", channel);
178 }
179
180 grpc_exec_ctx_finish(&exec_ctx);
181 }
182
Craig Tillerb4d883b2016-11-01 15:10:22 -0700183 virtual ~EndpointPairFixture() {
184 server_->Shutdown();
185 cq_->Shutdown();
186 void* tag;
187 bool ok;
188 while (cq_->Next(&tag, &ok)) {
189 }
190 }
191
Craig Tiller1d0fce92016-10-26 08:26:22 -0700192 ServerCompletionQueue* cq() { return cq_.get(); }
193 std::shared_ptr<Channel> channel() { return channel_; }
194
195 private:
196 std::unique_ptr<Server> server_;
197 std::unique_ptr<ServerCompletionQueue> cq_;
198 std::shared_ptr<Channel> channel_;
199};
200
201class SockPair : public EndpointPairFixture {
202 public:
203 SockPair(Service* service)
Craig Tiller63ec2932016-11-01 15:00:41 -0700204 : EndpointPairFixture(service, grpc_iomgr_create_endpoint_pair(
205 "test", initialize_stuff.rq(), 8192)) {
206 }
Craig Tiller1d0fce92016-10-26 08:26:22 -0700207};
208
209class InProcessCHTTP2 : public EndpointPairFixture {
210 public:
211 InProcessCHTTP2(Service* service)
212 : EndpointPairFixture(service, MakeEndpoints()) {}
213
214 private:
215 grpc_endpoint_pair MakeEndpoints() {
216 grpc_endpoint_pair p;
Craig Tiller63ec2932016-11-01 15:00:41 -0700217 grpc_passthru_endpoint_create(&p.client, &p.server, initialize_stuff.rq());
Craig Tiller1d0fce92016-10-26 08:26:22 -0700218 return p;
219 }
220};
221
Craig Tiller93d802b2016-10-25 21:05:49 -0700222/*******************************************************************************
Craig Tiller206efc72016-11-07 12:55:40 -0800223 * CONTEXT MUTATORS
224 */
225
226static const int kPregenerateKeyCount = 10000000;
227
228template <class F>
229auto MakeVector(size_t length, F f) -> std::vector<decltype(f())> {
230 std::vector<decltype(f())> out;
231 out.reserve(length);
232 for (size_t i = 0; i < length; i++) {
233 out.push_back(f());
234 }
235 return out;
236}
237
238class NoOpMutator {
239 public:
240 template <class ContextType>
241 NoOpMutator(ContextType* context) {}
242};
243
244template <int length>
245class RandomBinaryMetadata {
246 public:
247 static const grpc::string& Key() { return kKey; }
248
249 static const grpc::string& Value() {
250 return kValues[rand() % kValues.size()];
251 }
252
253 private:
254 static const grpc::string kKey;
255 static const std::vector<grpc::string> kValues;
256
257 static grpc::string GenerateOneString() {
258 grpc::string s;
259 s.reserve(length + 1);
260 for (int i = 0; i < length; i++) {
261 s += (char)rand();
262 }
263 return s;
264 }
265};
266
267template <int length>
268const grpc::string RandomBinaryMetadata<length>::kKey = "foo-bin";
269
270template <int length>
271const std::vector<grpc::string> RandomBinaryMetadata<length>::kValues =
272 MakeVector(kPregenerateKeyCount, GenerateOneString);
273
274template <int length>
275class RandomAsciiMetadata {
276 public:
277 static const grpc::string& Key() { return kKey; }
278
279 static const grpc::string& Value() {
280 return kValues[rand() % kValues.size()];
281 }
282
283 private:
284 static const grpc::string kKey;
285 static const std::vector<grpc::string> kValues;
286
287 static grpc::string GenerateOneString() {
288 grpc::string s;
289 s.reserve(length + 1);
290 for (int i = 0; i < length; i++) {
291 s += (char)(rand() % 26 + 'a');
292 }
293 return s;
294 }
295};
296
297template <int length>
298const grpc::string RandomAsciiMetadata<length>::kKey = "foo";
299
300template <int length>
301const std::vector<grpc::string> RandomAsciiMetadata<length>::kValues =
302 MakeVector(kPregenerateKeyCount, GenerateOneString);
303
304template <class Generator, int kNumKeys>
305class Client_AddMetadata : public NoOpMutator {
306 public:
307 Client_AddMetadata(ClientContext* context) : NoOpMutator(context) {
308 for (int i = 0; i < kNumKeys; i++) {
309 context->AddMetadata(Generator::Key(), Generator::Value());
310 }
311 }
312};
313
314template <class Generator, int kNumKeys>
315class Server_AddInitialMetadata : public NoOpMutator {
316 public:
317 Server_AddInitialMetadata(ServerContext* context) : NoOpMutator(context) {
318 for (int i = 0; i < kNumKeys; i++) {
319 context->AddInitialMetadata(Generator::Key(), Generator::Value());
320 }
321 }
322};
323
324/*******************************************************************************
Craig Tiller93d802b2016-10-25 21:05:49 -0700325 * BENCHMARKING KERNELS
326 */
327
328static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
329
Craig Tiller206efc72016-11-07 12:55:40 -0800330template <class Fixture, class ClientContextMutator, class ServerContextMutator>
Craig Tiller93d802b2016-10-25 21:05:49 -0700331static void BM_UnaryPingPong(benchmark::State& state) {
332 EchoTestService::AsyncService service;
Craig Tillerff8e43a2016-11-01 15:13:31 -0700333 std::unique_ptr<Fixture> fixture(new Fixture(&service));
Craig Tiller93d802b2016-10-25 21:05:49 -0700334 EchoRequest send_request;
335 EchoResponse send_response;
336 EchoResponse recv_response;
337 Status recv_status;
338 struct ServerEnv {
339 ServerContext ctx;
340 EchoRequest recv_request;
341 grpc::ServerAsyncResponseWriter<EchoResponse> response_writer;
342 ServerEnv() : response_writer(&ctx) {}
343 };
344 uint8_t server_env_buffer[2 * sizeof(ServerEnv)];
345 ServerEnv* server_env[2] = {
346 reinterpret_cast<ServerEnv*>(server_env_buffer),
347 reinterpret_cast<ServerEnv*>(server_env_buffer + sizeof(ServerEnv))};
348 new (server_env[0]) ServerEnv;
349 new (server_env[1]) ServerEnv;
350 service.RequestEcho(&server_env[0]->ctx, &server_env[0]->recv_request,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700351 &server_env[0]->response_writer, fixture->cq(),
352 fixture->cq(), tag(0));
Craig Tiller93d802b2016-10-25 21:05:49 -0700353 service.RequestEcho(&server_env[1]->ctx, &server_env[1]->recv_request,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700354 &server_env[1]->response_writer, fixture->cq(),
355 fixture->cq(), tag(1));
Craig Tiller93d802b2016-10-25 21:05:49 -0700356 std::unique_ptr<EchoTestService::Stub> stub(
Craig Tillerff8e43a2016-11-01 15:13:31 -0700357 EchoTestService::NewStub(fixture->channel()));
Craig Tiller93d802b2016-10-25 21:05:49 -0700358 while (state.KeepRunning()) {
359 ClientContext cli_ctx;
Craig Tiller206efc72016-11-07 12:55:40 -0800360 ClientContextMutator cli_ctx_mut(&cli_ctx);
Craig Tiller93d802b2016-10-25 21:05:49 -0700361 std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
Craig Tillerff8e43a2016-11-01 15:13:31 -0700362 stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
Craig Tiller93d802b2016-10-25 21:05:49 -0700363 void* t;
364 bool ok;
Craig Tillerff8e43a2016-11-01 15:13:31 -0700365 GPR_ASSERT(fixture->cq()->Next(&t, &ok));
Craig Tiller93d802b2016-10-25 21:05:49 -0700366 GPR_ASSERT(ok);
367 GPR_ASSERT(t == tag(0) || t == tag(1));
368 intptr_t slot = reinterpret_cast<intptr_t>(t);
369 ServerEnv* senv = server_env[slot];
Craig Tiller206efc72016-11-07 12:55:40 -0800370 ServerContextMutator svr_ctx_mut(&senv->ctx);
Craig Tiller93d802b2016-10-25 21:05:49 -0700371 senv->response_writer.Finish(send_response, Status::OK, tag(3));
372 response_reader->Finish(&recv_response, &recv_status, tag(4));
373 for (int i = (1 << 3) | (1 << 4); i != 0;) {
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 int tagnum = (int)reinterpret_cast<intptr_t>(t);
377 GPR_ASSERT(i & (1 << tagnum));
378 i -= 1 << tagnum;
379 }
380 GPR_ASSERT(recv_status.ok());
381
382 senv->~ServerEnv();
383 senv = new (senv) ServerEnv();
384 service.RequestEcho(&senv->ctx, &senv->recv_request, &senv->response_writer,
Craig Tillerff8e43a2016-11-01 15:13:31 -0700385 fixture->cq(), fixture->cq(), tag(slot));
Craig Tiller93d802b2016-10-25 21:05:49 -0700386 }
Craig Tillerff8e43a2016-11-01 15:13:31 -0700387 fixture.reset();
Craig Tillerb4d883b2016-11-01 15:10:22 -0700388 server_env[0]->~ServerEnv();
389 server_env[1]->~ServerEnv();
Craig Tiller93d802b2016-10-25 21:05:49 -0700390}
391
392/*******************************************************************************
393 * CONFIGURATIONS
394 */
395
Craig Tiller206efc72016-11-07 12:55:40 -0800396BENCHMARK_TEMPLATE(BM_UnaryPingPong, TCP, NoOpMutator, NoOpMutator);
397BENCHMARK_TEMPLATE(BM_UnaryPingPong, UDS, NoOpMutator, NoOpMutator);
398BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator);
399BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator, NoOpMutator);
400BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
401 Client_AddMetadata<RandomBinaryMetadata<10>, 1>,
402 NoOpMutator);
403BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
404 Client_AddMetadata<RandomBinaryMetadata<31>, 1>,
405 NoOpMutator);
406BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
407 Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
408 NoOpMutator);
409BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
410 Client_AddMetadata<RandomBinaryMetadata<10>, 2>,
411 NoOpMutator);
412BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
413 Client_AddMetadata<RandomBinaryMetadata<31>, 2>,
414 NoOpMutator);
415BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
416 Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
417 NoOpMutator);
418BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
419 Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>);
420BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
421 Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>);
422BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
423 Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>);
424BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
425 Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator);
426BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
427 Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator);
428BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
429 Client_AddMetadata<RandomAsciiMetadata<100>, 1>,
430 NoOpMutator);
431BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
432 Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>);
433BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
434 Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>);
435BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
436 Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>);
Craig Tiller93d802b2016-10-25 21:05:49 -0700437
438} // namespace testing
439} // namespace grpc
440
441BENCHMARK_MAIN();