3 * Copyright 2017 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_FIXTURES_H
20 #define TEST_CPP_MICROBENCHMARKS_FULLSTACK_FIXTURES_H
22 #include <grpc/support/atm.h>
23 #include <grpc/support/log.h>
24 #include <grpcpp/channel.h>
25 #include <grpcpp/create_channel.h>
26 #include <grpcpp/security/credentials.h>
27 #include <grpcpp/security/server_credentials.h>
28 #include <grpcpp/server.h>
29 #include <grpcpp/server_builder.h>
31 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
32 #include "src/core/lib/channel/channel_args.h"
33 #include "src/core/lib/iomgr/endpoint.h"
34 #include "src/core/lib/iomgr/endpoint_pair.h"
35 #include "src/core/lib/iomgr/exec_ctx.h"
36 #include "src/core/lib/iomgr/tcp_posix.h"
37 #include "src/core/lib/surface/channel.h"
38 #include "src/core/lib/surface/completion_queue.h"
39 #include "src/core/lib/surface/server.h"
40 #include "src/cpp/client/create_channel_internal.h"
41 #include "test/core/util/passthru_endpoint.h"
42 #include "test/core/util/port.h"
43 #include "test/cpp/microbenchmarks/helpers.h"
48 class FixtureConfiguration {
50 virtual ~FixtureConfiguration() {}
51 virtual void ApplyCommonChannelArguments(ChannelArguments* c) const {
52 c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
53 c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);
56 virtual void ApplyCommonServerBuilderConfig(ServerBuilder* b) const {
57 b->SetMaxReceiveMessageSize(INT_MAX);
58 b->SetMaxSendMessageSize(INT_MAX);
62 class BaseFixture : public TrackCounters {};
64 class FullstackFixture : public BaseFixture {
66 FullstackFixture(Service* service, const FixtureConfiguration& config,
67 const std::string& address) {
69 if (address.length() > 0) {
70 b.AddListeningPort(address, InsecureServerCredentials());
72 cq_ = b.AddCompletionQueue(true);
73 b.RegisterService(service);
74 config.ApplyCommonServerBuilderConfig(&b);
75 server_ = b.BuildAndStart();
76 ChannelArguments args;
77 config.ApplyCommonChannelArguments(&args);
78 if (address.length() > 0) {
79 channel_ = ::grpc::CreateCustomChannel(
80 address, InsecureChannelCredentials(), args);
82 channel_ = server_->InProcessChannel(args);
86 ~FullstackFixture() override {
91 while (cq_->Next(&tag, &ok)) {
95 void AddToLabel(std::ostream& out, benchmark::State& state) override {
96 BaseFixture::AddToLabel(out, state);
98 << static_cast<double>(grpc_get_cq_poll_num(this->cq()->cq())) /
102 ServerCompletionQueue* cq() { return cq_.get(); }
103 std::shared_ptr<Channel> channel() { return channel_; }
106 std::unique_ptr<Server> server_;
107 std::unique_ptr<ServerCompletionQueue> cq_;
108 std::shared_ptr<Channel> channel_;
111 class TCP : public FullstackFixture {
113 explicit TCP(Service* service,
114 const FixtureConfiguration& fixture_configuration =
115 FixtureConfiguration())
116 : FullstackFixture(service, fixture_configuration, MakeAddress(&port_)) {}
118 ~TCP() override { grpc_recycle_unused_port(port_); }
123 static std::string MakeAddress(int* port) {
124 *port = grpc_pick_unused_port_or_die();
125 std::stringstream addr;
126 addr << "localhost:" << *port;
131 class UDS : public FullstackFixture {
133 explicit UDS(Service* service,
134 const FixtureConfiguration& fixture_configuration =
135 FixtureConfiguration())
136 : FullstackFixture(service, fixture_configuration, MakeAddress(&port_)) {}
138 ~UDS() override { grpc_recycle_unused_port(port_); }
143 static std::string MakeAddress(int* port) {
144 *port = grpc_pick_unused_port_or_die(); // just for a unique id - not a
146 std::stringstream addr;
147 addr << "unix:/tmp/bm_fullstack." << *port;
152 class InProcess : public FullstackFixture {
154 explicit InProcess(Service* service,
155 const FixtureConfiguration& fixture_configuration =
156 FixtureConfiguration())
157 : FullstackFixture(service, fixture_configuration, "") {}
158 ~InProcess() override {}
161 class EndpointPairFixture : public BaseFixture {
163 EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints,
164 const FixtureConfiguration& fixture_configuration)
165 : endpoint_pair_(endpoints) {
167 cq_ = b.AddCompletionQueue(true);
168 b.RegisterService(service);
169 fixture_configuration.ApplyCommonServerBuilderConfig(&b);
170 server_ = b.BuildAndStart();
171 grpc_core::ExecCtx exec_ctx;
172 /* add server endpoint to server_
175 const grpc_channel_args* server_args =
176 server_->c_server()->core_server->channel_args();
177 grpc_resource_quota* server_resource_quota =
178 grpc_resource_quota_from_channel_args(server_args, true);
179 server_transport_ = grpc_create_chttp2_transport(
180 server_args, endpoints.server, false /* is_client */,
181 grpc_resource_user_create(server_resource_quota, "server_transport"));
182 grpc_resource_quota_unref(server_resource_quota);
183 for (grpc_pollset* pollset :
184 server_->c_server()->core_server->pollsets()) {
185 grpc_endpoint_add_to_pollset(endpoints.server, pollset);
188 server_->c_server()->core_server->SetupTransport(
189 server_transport_, nullptr, server_args, nullptr);
190 grpc_chttp2_transport_start_reading(server_transport_, nullptr, nullptr,
196 ChannelArguments args;
197 args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
198 fixture_configuration.ApplyCommonChannelArguments(&args);
200 grpc_channel_args c_args = args.c_channel_args();
201 grpc_resource_quota* client_resource_quota =
202 grpc_resource_quota_from_channel_args(&c_args, true);
203 client_transport_ = grpc_create_chttp2_transport(
204 &c_args, endpoints.client, true,
205 grpc_resource_user_create(client_resource_quota, "client_transport"));
206 grpc_resource_quota_unref(client_resource_quota);
207 GPR_ASSERT(client_transport_);
208 grpc_channel* channel =
209 grpc_channel_create("target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL,
210 client_transport_, nullptr, 0, nullptr);
211 grpc_chttp2_transport_start_reading(client_transport_, nullptr, nullptr,
214 channel_ = ::grpc::CreateChannelInternal(
216 std::vector<std::unique_ptr<
217 experimental::ClientInterceptorFactoryInterface>>());
221 ~EndpointPairFixture() override {
226 while (cq_->Next(&tag, &ok)) {
230 void AddToLabel(std::ostream& out, benchmark::State& state) override {
231 BaseFixture::AddToLabel(out, state);
232 out << " polls/iter:"
233 << static_cast<double>(grpc_get_cq_poll_num(this->cq()->cq())) /
237 ServerCompletionQueue* cq() { return cq_.get(); }
238 std::shared_ptr<Channel> channel() { return channel_; }
241 grpc_endpoint_pair endpoint_pair_;
242 grpc_transport* client_transport_;
243 grpc_transport* server_transport_;
246 std::unique_ptr<Server> server_;
247 std::unique_ptr<ServerCompletionQueue> cq_;
248 std::shared_ptr<Channel> channel_;
251 class SockPair : public EndpointPairFixture {
253 explicit SockPair(Service* service,
254 const FixtureConfiguration& fixture_configuration =
255 FixtureConfiguration())
256 : EndpointPairFixture(service,
257 grpc_iomgr_create_endpoint_pair("test", nullptr),
258 fixture_configuration) {}
261 /* Use InProcessCHTTP2 instead. This class (with stats as an explicit parameter)
262 is here only to be able to initialize both the base class and stats_ with the
263 same stats instance without accessing the stats_ fields before the object is
264 properly initialized. */
265 class InProcessCHTTP2WithExplicitStats : public EndpointPairFixture {
267 InProcessCHTTP2WithExplicitStats(
268 Service* service, grpc_passthru_endpoint_stats* stats,
269 const FixtureConfiguration& fixture_configuration)
270 : EndpointPairFixture(service, MakeEndpoints(stats),
271 fixture_configuration),
274 ~InProcessCHTTP2WithExplicitStats() override {
275 if (stats_ != nullptr) {
276 grpc_passthru_endpoint_stats_destroy(stats_);
280 void AddToLabel(std::ostream& out, benchmark::State& state) override {
281 EndpointPairFixture::AddToLabel(out, state);
282 out << " writes/iter:"
283 << static_cast<double>(gpr_atm_no_barrier_load(&stats_->num_writes)) /
284 static_cast<double>(state.iterations());
288 grpc_passthru_endpoint_stats* stats_;
290 static grpc_endpoint_pair MakeEndpoints(grpc_passthru_endpoint_stats* stats) {
291 grpc_endpoint_pair p;
292 grpc_passthru_endpoint_create(&p.client, &p.server, stats);
297 class InProcessCHTTP2 : public InProcessCHTTP2WithExplicitStats {
299 explicit InProcessCHTTP2(Service* service,
300 const FixtureConfiguration& fixture_configuration =
301 FixtureConfiguration())
302 : InProcessCHTTP2WithExplicitStats(service,
303 grpc_passthru_endpoint_stats_create(),
304 fixture_configuration) {}
307 ////////////////////////////////////////////////////////////////////////////////
308 // Minimal stack fixtures
310 class MinStackConfiguration : public FixtureConfiguration {
311 void ApplyCommonChannelArguments(ChannelArguments* a) const override {
312 a->SetInt(GRPC_ARG_MINIMAL_STACK, 1);
313 FixtureConfiguration::ApplyCommonChannelArguments(a);
316 void ApplyCommonServerBuilderConfig(ServerBuilder* b) const override {
317 b->AddChannelArgument(GRPC_ARG_MINIMAL_STACK, 1);
318 FixtureConfiguration::ApplyCommonServerBuilderConfig(b);
322 template <class Base>
323 class MinStackize : public Base {
325 explicit MinStackize(Service* service)
326 : Base(service, MinStackConfiguration()) {}
329 typedef MinStackize<TCP> MinTCP;
330 typedef MinStackize<UDS> MinUDS;
331 typedef MinStackize<InProcess> MinInProcess;
332 typedef MinStackize<SockPair> MinSockPair;
333 typedef MinStackize<InProcessCHTTP2> MinInProcessCHTTP2;
335 } // namespace testing