bm_call_create.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. /*
  2. *
  3. * Copyright 2017 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. /* This benchmark exists to ensure that the benchmark integration is
  19. * working */
  20. #include <string.h>
  21. #include <sstream>
  22. #include <benchmark/benchmark.h>
  23. #include <grpc/grpc.h>
  24. #include <grpc/grpc_security.h>
  25. #include <grpc/support/alloc.h>
  26. #include <grpc/support/string_util.h>
  27. #include <grpcpp/channel.h>
  28. #include <grpcpp/support/channel_arguments.h>
  29. #include "src/core/ext/filters/client_channel/client_channel.h"
  30. #include "src/core/ext/filters/deadline/deadline_filter.h"
  31. #include "src/core/ext/filters/http/client/http_client_filter.h"
  32. #include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
  33. #include "src/core/ext/filters/http/server/http_server_filter.h"
  34. #include "src/core/ext/filters/message_size/message_size_filter.h"
  35. #include "src/core/lib/channel/channel_stack.h"
  36. #include "src/core/lib/channel/connected_channel.h"
  37. #include "src/core/lib/config/core_configuration.h"
  38. #include "src/core/lib/iomgr/call_combiner.h"
  39. #include "src/core/lib/profiling/timers.h"
  40. #include "src/core/lib/resource_quota/resource_quota.h"
  41. #include "src/core/lib/surface/channel.h"
  42. #include "src/core/lib/transport/transport_impl.h"
  43. #include "src/cpp/client/create_channel_internal.h"
  44. #include "src/proto/grpc/testing/echo.grpc.pb.h"
  45. #include "test/core/util/test_config.h"
  46. #include "test/cpp/microbenchmarks/helpers.h"
  47. #include "test/cpp/util/test_config.h"
  48. static auto* g_memory_allocator = new grpc_core::MemoryAllocator(
  49. grpc_core::ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
  50. "test"));
  51. void BM_Zalloc(benchmark::State& state) {
  52. // speed of light for call creation is zalloc, so benchmark a few interesting
  53. // sizes
  54. TrackCounters track_counters;
  55. size_t sz = state.range(0);
  56. for (auto _ : state) {
  57. gpr_free(gpr_zalloc(sz));
  58. }
  59. track_counters.Finish(state);
  60. }
  61. BENCHMARK(BM_Zalloc)
  62. ->Arg(64)
  63. ->Arg(128)
  64. ->Arg(256)
  65. ->Arg(512)
  66. ->Arg(1024)
  67. ->Arg(1536)
  68. ->Arg(2048)
  69. ->Arg(3072)
  70. ->Arg(4096)
  71. ->Arg(5120)
  72. ->Arg(6144)
  73. ->Arg(7168);
  74. ////////////////////////////////////////////////////////////////////////////////
  75. // Benchmarks creating full stacks
  76. class BaseChannelFixture {
  77. public:
  78. explicit BaseChannelFixture(grpc_channel* channel) : channel_(channel) {}
  79. ~BaseChannelFixture() { grpc_channel_destroy(channel_); }
  80. grpc_channel* channel() const { return channel_; }
  81. private:
  82. grpc_channel* const channel_;
  83. };
  84. static grpc_channel* CreateChannel() {
  85. grpc_channel_credentials* creds = grpc_insecure_credentials_create();
  86. grpc_channel* channel = grpc_channel_create("localhost:1234", creds, nullptr);
  87. grpc_channel_credentials_release(creds);
  88. return channel;
  89. }
  90. class InsecureChannel : public BaseChannelFixture {
  91. public:
  92. InsecureChannel() : BaseChannelFixture(CreateChannel()) {}
  93. };
  94. class LameChannel : public BaseChannelFixture {
  95. public:
  96. LameChannel()
  97. : BaseChannelFixture(grpc_lame_client_channel_create(
  98. "localhost:1234", GRPC_STATUS_UNAUTHENTICATED, "blah")) {}
  99. };
  100. template <class Fixture>
  101. static void BM_CallCreateDestroy(benchmark::State& state) {
  102. TrackCounters track_counters;
  103. Fixture fixture;
  104. grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
  105. gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
  106. void* method_hdl = grpc_channel_register_call(fixture.channel(), "/foo/bar",
  107. nullptr, nullptr);
  108. for (auto _ : state) {
  109. grpc_call_unref(grpc_channel_create_registered_call(
  110. fixture.channel(), nullptr, GRPC_PROPAGATE_DEFAULTS, cq, method_hdl,
  111. deadline, nullptr));
  112. }
  113. grpc_completion_queue_destroy(cq);
  114. track_counters.Finish(state);
  115. }
  116. BENCHMARK_TEMPLATE(BM_CallCreateDestroy, InsecureChannel);
  117. BENCHMARK_TEMPLATE(BM_CallCreateDestroy, LameChannel);
  118. ////////////////////////////////////////////////////////////////////////////////
  119. // Benchmarks isolating individual filters
  120. static void* tag(int i) {
  121. return reinterpret_cast<void*>(static_cast<intptr_t>(i));
  122. }
  123. static void BM_LameChannelCallCreateCpp(benchmark::State& state) {
  124. TrackCounters track_counters;
  125. auto stub =
  126. grpc::testing::EchoTestService::NewStub(grpc::CreateChannelInternal(
  127. "",
  128. grpc_lame_client_channel_create("localhost:1234",
  129. GRPC_STATUS_UNAUTHENTICATED, "blah"),
  130. std::vector<std::unique_ptr<
  131. grpc::experimental::ClientInterceptorFactoryInterface>>()));
  132. grpc::CompletionQueue cq;
  133. grpc::testing::EchoRequest send_request;
  134. grpc::testing::EchoResponse recv_response;
  135. grpc::Status recv_status;
  136. for (auto _ : state) {
  137. GPR_TIMER_SCOPE("BenchmarkCycle", 0);
  138. grpc::ClientContext cli_ctx;
  139. auto reader = stub->AsyncEcho(&cli_ctx, send_request, &cq);
  140. reader->Finish(&recv_response, &recv_status, tag(0));
  141. void* t;
  142. bool ok;
  143. GPR_ASSERT(cq.Next(&t, &ok));
  144. GPR_ASSERT(ok);
  145. }
  146. track_counters.Finish(state);
  147. }
  148. BENCHMARK(BM_LameChannelCallCreateCpp);
  149. static void do_nothing(void* /*ignored*/) {}
  150. static void BM_LameChannelCallCreateCore(benchmark::State& state) {
  151. TrackCounters track_counters;
  152. grpc_channel* channel;
  153. grpc_completion_queue* cq;
  154. grpc_metadata_array initial_metadata_recv;
  155. grpc_metadata_array trailing_metadata_recv;
  156. grpc_byte_buffer* response_payload_recv = nullptr;
  157. grpc_status_code status;
  158. grpc_slice details;
  159. grpc::testing::EchoRequest send_request;
  160. grpc_slice send_request_slice =
  161. grpc_slice_new(&send_request, sizeof(send_request), do_nothing);
  162. channel = grpc_lame_client_channel_create(
  163. "localhost:1234", GRPC_STATUS_UNAUTHENTICATED, "blah");
  164. cq = grpc_completion_queue_create_for_next(nullptr);
  165. void* rc = grpc_channel_register_call(
  166. channel, "/grpc.testing.EchoTestService/Echo", nullptr, nullptr);
  167. for (auto _ : state) {
  168. GPR_TIMER_SCOPE("BenchmarkCycle", 0);
  169. grpc_call* call = grpc_channel_create_registered_call(
  170. channel, nullptr, GRPC_PROPAGATE_DEFAULTS, cq, rc,
  171. gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
  172. grpc_metadata_array_init(&initial_metadata_recv);
  173. grpc_metadata_array_init(&trailing_metadata_recv);
  174. grpc_byte_buffer* request_payload_send =
  175. grpc_raw_byte_buffer_create(&send_request_slice, 1);
  176. // Fill in call ops
  177. grpc_op ops[6];
  178. memset(ops, 0, sizeof(ops));
  179. grpc_op* op = ops;
  180. op->op = GRPC_OP_SEND_INITIAL_METADATA;
  181. op->data.send_initial_metadata.count = 0;
  182. op++;
  183. op->op = GRPC_OP_SEND_MESSAGE;
  184. op->data.send_message.send_message = request_payload_send;
  185. op++;
  186. op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  187. op++;
  188. op->op = GRPC_OP_RECV_INITIAL_METADATA;
  189. op->data.recv_initial_metadata.recv_initial_metadata =
  190. &initial_metadata_recv;
  191. op++;
  192. op->op = GRPC_OP_RECV_MESSAGE;
  193. op->data.recv_message.recv_message = &response_payload_recv;
  194. op++;
  195. op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  196. op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
  197. op->data.recv_status_on_client.status = &status;
  198. op->data.recv_status_on_client.status_details = &details;
  199. op++;
  200. GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call, ops,
  201. (size_t)(op - ops),
  202. (void*)1, nullptr));
  203. grpc_event ev = grpc_completion_queue_next(
  204. cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
  205. GPR_ASSERT(ev.type != GRPC_QUEUE_SHUTDOWN);
  206. GPR_ASSERT(ev.success != 0);
  207. grpc_call_unref(call);
  208. grpc_byte_buffer_destroy(request_payload_send);
  209. grpc_byte_buffer_destroy(response_payload_recv);
  210. grpc_metadata_array_destroy(&initial_metadata_recv);
  211. grpc_metadata_array_destroy(&trailing_metadata_recv);
  212. }
  213. grpc_channel_destroy(channel);
  214. grpc_completion_queue_destroy(cq);
  215. grpc_slice_unref(send_request_slice);
  216. track_counters.Finish(state);
  217. }
  218. BENCHMARK(BM_LameChannelCallCreateCore);
  219. static void BM_LameChannelCallCreateCoreSeparateBatch(benchmark::State& state) {
  220. TrackCounters track_counters;
  221. grpc_channel* channel;
  222. grpc_completion_queue* cq;
  223. grpc_metadata_array initial_metadata_recv;
  224. grpc_metadata_array trailing_metadata_recv;
  225. grpc_byte_buffer* response_payload_recv = nullptr;
  226. grpc_status_code status;
  227. grpc_slice details;
  228. grpc::testing::EchoRequest send_request;
  229. grpc_slice send_request_slice =
  230. grpc_slice_new(&send_request, sizeof(send_request), do_nothing);
  231. channel = grpc_lame_client_channel_create(
  232. "localhost:1234", GRPC_STATUS_UNAUTHENTICATED, "blah");
  233. cq = grpc_completion_queue_create_for_next(nullptr);
  234. void* rc = grpc_channel_register_call(
  235. channel, "/grpc.testing.EchoTestService/Echo", nullptr, nullptr);
  236. for (auto _ : state) {
  237. GPR_TIMER_SCOPE("BenchmarkCycle", 0);
  238. grpc_call* call = grpc_channel_create_registered_call(
  239. channel, nullptr, GRPC_PROPAGATE_DEFAULTS, cq, rc,
  240. gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
  241. grpc_metadata_array_init(&initial_metadata_recv);
  242. grpc_metadata_array_init(&trailing_metadata_recv);
  243. grpc_byte_buffer* request_payload_send =
  244. grpc_raw_byte_buffer_create(&send_request_slice, 1);
  245. // Fill in call ops
  246. grpc_op ops[3];
  247. memset(ops, 0, sizeof(ops));
  248. grpc_op* op = ops;
  249. op->op = GRPC_OP_SEND_INITIAL_METADATA;
  250. op->data.send_initial_metadata.count = 0;
  251. op++;
  252. op->op = GRPC_OP_SEND_MESSAGE;
  253. op->data.send_message.send_message = request_payload_send;
  254. op++;
  255. op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  256. op++;
  257. GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call, ops,
  258. (size_t)(op - ops),
  259. (void*)nullptr, nullptr));
  260. memset(ops, 0, sizeof(ops));
  261. op = ops;
  262. op->op = GRPC_OP_RECV_INITIAL_METADATA;
  263. op->data.recv_initial_metadata.recv_initial_metadata =
  264. &initial_metadata_recv;
  265. op++;
  266. op->op = GRPC_OP_RECV_MESSAGE;
  267. op->data.recv_message.recv_message = &response_payload_recv;
  268. op++;
  269. op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  270. op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
  271. op->data.recv_status_on_client.status = &status;
  272. op->data.recv_status_on_client.status_details = &details;
  273. op++;
  274. GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call, ops,
  275. (size_t)(op - ops),
  276. (void*)1, nullptr));
  277. grpc_event ev = grpc_completion_queue_next(
  278. cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
  279. GPR_ASSERT(ev.type != GRPC_QUEUE_SHUTDOWN);
  280. GPR_ASSERT(ev.success == 0);
  281. ev = grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
  282. nullptr);
  283. GPR_ASSERT(ev.type != GRPC_QUEUE_SHUTDOWN);
  284. GPR_ASSERT(ev.success != 0);
  285. grpc_call_unref(call);
  286. grpc_byte_buffer_destroy(request_payload_send);
  287. grpc_byte_buffer_destroy(response_payload_recv);
  288. grpc_metadata_array_destroy(&initial_metadata_recv);
  289. grpc_metadata_array_destroy(&trailing_metadata_recv);
  290. }
  291. grpc_channel_destroy(channel);
  292. grpc_completion_queue_destroy(cq);
  293. grpc_slice_unref(send_request_slice);
  294. track_counters.Finish(state);
  295. }
  296. BENCHMARK(BM_LameChannelCallCreateCoreSeparateBatch);
  297. static void FilterDestroy(void* arg, grpc_error_handle /*error*/) {
  298. gpr_free(arg);
  299. }
  300. static void DoNothing(void* /*arg*/, grpc_error_handle /*error*/) {}
  301. class FakeClientChannelFactory : public grpc_core::ClientChannelFactory {
  302. public:
  303. grpc_core::RefCountedPtr<grpc_core::Subchannel> CreateSubchannel(
  304. const grpc_resolved_address& /*address*/,
  305. const grpc_channel_args* /*args*/) override {
  306. return nullptr;
  307. }
  308. };
  309. static grpc_arg StringArg(const char* key, const char* value) {
  310. grpc_arg a;
  311. a.type = GRPC_ARG_STRING;
  312. a.key = const_cast<char*>(key);
  313. a.value.string = const_cast<char*>(value);
  314. return a;
  315. }
  316. enum FixtureFlags : uint32_t {
  317. CHECKS_NOT_LAST = 1,
  318. REQUIRES_TRANSPORT = 2,
  319. };
  320. template <const grpc_channel_filter* kFilter, uint32_t kFlags>
  321. struct Fixture {
  322. const grpc_channel_filter* filter = kFilter;
  323. const uint32_t flags = kFlags;
  324. };
  325. namespace phony_filter {
  326. static void StartTransportStreamOp(grpc_call_element* /*elem*/,
  327. grpc_transport_stream_op_batch* /*op*/) {}
  328. static void StartTransportOp(grpc_channel_element* /*elem*/,
  329. grpc_transport_op* /*op*/) {}
  330. static grpc_error_handle InitCallElem(grpc_call_element* /*elem*/,
  331. const grpc_call_element_args* /*args*/) {
  332. return GRPC_ERROR_NONE;
  333. }
  334. static void SetPollsetOrPollsetSet(grpc_call_element* /*elem*/,
  335. grpc_polling_entity* /*pollent*/) {}
  336. static void DestroyCallElem(grpc_call_element* /*elem*/,
  337. const grpc_call_final_info* /*final_info*/,
  338. grpc_closure* /*then_sched_closure*/) {}
  339. grpc_error_handle InitChannelElem(grpc_channel_element* /*elem*/,
  340. grpc_channel_element_args* /*args*/) {
  341. return GRPC_ERROR_NONE;
  342. }
  343. void DestroyChannelElem(grpc_channel_element* /*elem*/) {}
  344. void GetChannelInfo(grpc_channel_element* /*elem*/,
  345. const grpc_channel_info* /*channel_info*/) {}
  346. static const grpc_channel_filter phony_filter = {
  347. StartTransportStreamOp, nullptr,
  348. StartTransportOp, 0,
  349. InitCallElem, SetPollsetOrPollsetSet,
  350. DestroyCallElem, 0,
  351. InitChannelElem, DestroyChannelElem,
  352. GetChannelInfo, "phony_filter"};
  353. } // namespace phony_filter
  354. namespace phony_transport {
  355. /* Memory required for a single stream element - this is allocated by upper
  356. layers and initialized by the transport */
  357. size_t sizeof_stream; /* = sizeof(transport stream) */
  358. /* name of this transport implementation */
  359. const char* name;
  360. /* implementation of grpc_transport_init_stream */
  361. int InitStream(grpc_transport* /*self*/, grpc_stream* /*stream*/,
  362. grpc_stream_refcount* /*refcount*/, const void* /*server_data*/,
  363. grpc_core::Arena* /*arena*/) {
  364. return 0;
  365. }
  366. /* implementation of grpc_transport_set_pollset */
  367. void SetPollset(grpc_transport* /*self*/, grpc_stream* /*stream*/,
  368. grpc_pollset* /*pollset*/) {}
  369. /* implementation of grpc_transport_set_pollset */
  370. void SetPollsetSet(grpc_transport* /*self*/, grpc_stream* /*stream*/,
  371. grpc_pollset_set* /*pollset_set*/) {}
  372. /* implementation of grpc_transport_perform_stream_op */
  373. void PerformStreamOp(grpc_transport* /*self*/, grpc_stream* /*stream*/,
  374. grpc_transport_stream_op_batch* op) {
  375. grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_complete, GRPC_ERROR_NONE);
  376. }
  377. /* implementation of grpc_transport_perform_op */
  378. void PerformOp(grpc_transport* /*self*/, grpc_transport_op* /*op*/) {}
  379. /* implementation of grpc_transport_destroy_stream */
  380. void DestroyStream(grpc_transport* /*self*/, grpc_stream* /*stream*/,
  381. grpc_closure* /*then_sched_closure*/) {}
  382. /* implementation of grpc_transport_destroy */
  383. void Destroy(grpc_transport* /*self*/) {}
  384. /* implementation of grpc_transport_get_endpoint */
  385. grpc_endpoint* GetEndpoint(grpc_transport* /*self*/) { return nullptr; }
  386. static const grpc_transport_vtable phony_transport_vtable = {0,
  387. "phony_http2",
  388. InitStream,
  389. nullptr,
  390. SetPollset,
  391. SetPollsetSet,
  392. PerformStreamOp,
  393. PerformOp,
  394. DestroyStream,
  395. Destroy,
  396. GetEndpoint};
  397. static grpc_transport phony_transport = {&phony_transport_vtable};
  398. grpc_arg Arg() {
  399. static const grpc_arg_pointer_vtable vtable = {
  400. // copy
  401. [](void* p) { return p; },
  402. // destroy
  403. [](void*) {},
  404. // cmp
  405. [](void* a, void* b) { return grpc_core::QsortCompare(a, b); },
  406. };
  407. return grpc_channel_arg_pointer_create(const_cast<char*>(GRPC_ARG_TRANSPORT),
  408. &phony_transport, &vtable);
  409. }
  410. } // namespace phony_transport
  411. class NoOp {
  412. public:
  413. class Op {
  414. public:
  415. Op(NoOp* /*p*/, grpc_call_stack* /*s*/, grpc_core::Arena*) {}
  416. void Finish() {}
  417. };
  418. };
  419. class SendEmptyMetadata {
  420. public:
  421. SendEmptyMetadata() : op_payload_(nullptr) {
  422. op_ = {};
  423. op_.on_complete = GRPC_CLOSURE_INIT(&closure_, DoNothing, nullptr,
  424. grpc_schedule_on_exec_ctx);
  425. op_.send_initial_metadata = true;
  426. op_.payload = &op_payload_;
  427. }
  428. class Op {
  429. public:
  430. Op(SendEmptyMetadata* p, grpc_call_stack* /*s*/, grpc_core::Arena* arena)
  431. : batch_(arena) {
  432. p->op_payload_.send_initial_metadata.send_initial_metadata = &batch_;
  433. }
  434. void Finish() {}
  435. private:
  436. grpc_metadata_batch batch_;
  437. };
  438. private:
  439. const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
  440. const gpr_timespec start_time_ = gpr_now(GPR_CLOCK_MONOTONIC);
  441. const grpc_slice method_ = grpc_slice_from_static_string("/foo/bar");
  442. grpc_transport_stream_op_batch op_;
  443. grpc_transport_stream_op_batch_payload op_payload_;
  444. grpc_closure closure_;
  445. };
  446. // Test a filter in isolation. Fixture specifies the filter under test (use the
  447. // Fixture<> template to specify this), and TestOp defines some unit of work to
  448. // perform on said filter.
  449. template <class Fixture, class TestOp>
  450. static void BM_IsolatedFilter(benchmark::State& state) {
  451. TrackCounters track_counters;
  452. Fixture fixture;
  453. std::ostringstream label;
  454. FakeClientChannelFactory fake_client_channel_factory;
  455. std::vector<grpc_arg> args = {
  456. grpc_core::ClientChannelFactory::CreateChannelArg(
  457. &fake_client_channel_factory),
  458. StringArg(GRPC_ARG_SERVER_URI, "localhost"),
  459. };
  460. if (fixture.flags & REQUIRES_TRANSPORT) {
  461. args.push_back(phony_transport::Arg());
  462. }
  463. grpc_channel_args channel_args = {args.size(), args.data()};
  464. std::vector<const grpc_channel_filter*> filters;
  465. if (fixture.filter != nullptr) {
  466. filters.push_back(fixture.filter);
  467. }
  468. if (fixture.flags & CHECKS_NOT_LAST) {
  469. filters.push_back(&phony_filter::phony_filter);
  470. label << " #has_phony_filter";
  471. }
  472. grpc_core::ExecCtx exec_ctx;
  473. size_t channel_size = grpc_channel_stack_size(
  474. filters.empty() ? nullptr : &filters[0], filters.size());
  475. grpc_channel_stack* channel_stack =
  476. static_cast<grpc_channel_stack*>(gpr_zalloc(channel_size));
  477. GPR_ASSERT(GRPC_LOG_IF_ERROR(
  478. "channel_stack_init",
  479. grpc_channel_stack_init(1, FilterDestroy, channel_stack,
  480. filters.empty() ? nullptr : &filters[0],
  481. filters.size(), &channel_args, "CHANNEL",
  482. channel_stack)));
  483. grpc_core::ExecCtx::Get()->Flush();
  484. grpc_call_stack* call_stack =
  485. static_cast<grpc_call_stack*>(gpr_zalloc(channel_stack->call_stack_size));
  486. grpc_core::Timestamp deadline = grpc_core::Timestamp::InfFuture();
  487. gpr_cycle_counter start_time = gpr_get_cycle_counter();
  488. grpc_slice method = grpc_slice_from_static_string("/foo/bar");
  489. grpc_call_final_info final_info;
  490. TestOp test_op_data;
  491. const int kArenaSize = 4096;
  492. grpc_call_context_element context[GRPC_CONTEXT_COUNT] = {};
  493. grpc_call_element_args call_args{
  494. call_stack,
  495. nullptr,
  496. context,
  497. method,
  498. start_time,
  499. deadline,
  500. grpc_core::Arena::Create(kArenaSize, g_memory_allocator),
  501. nullptr};
  502. while (state.KeepRunning()) {
  503. GPR_TIMER_SCOPE("BenchmarkCycle", 0);
  504. GRPC_ERROR_UNREF(
  505. grpc_call_stack_init(channel_stack, 1, DoNothing, nullptr, &call_args));
  506. typename TestOp::Op op(&test_op_data, call_stack, call_args.arena);
  507. grpc_call_stack_destroy(call_stack, &final_info, nullptr);
  508. op.Finish();
  509. grpc_core::ExecCtx::Get()->Flush();
  510. // recreate arena every 64k iterations to avoid oom
  511. if (0 == (state.iterations() & 0xffff)) {
  512. call_args.arena->Destroy();
  513. call_args.arena =
  514. grpc_core::Arena::Create(kArenaSize, g_memory_allocator);
  515. }
  516. }
  517. call_args.arena->Destroy();
  518. grpc_channel_stack_destroy(channel_stack);
  519. grpc_core::ExecCtx::Get()->Flush();
  520. gpr_free(channel_stack);
  521. gpr_free(call_stack);
  522. state.SetLabel(label.str());
  523. track_counters.Finish(state);
  524. }
  525. typedef Fixture<nullptr, 0> NoFilter;
  526. BENCHMARK_TEMPLATE(BM_IsolatedFilter, NoFilter, NoOp);
  527. typedef Fixture<&phony_filter::phony_filter, 0> PhonyFilter;
  528. BENCHMARK_TEMPLATE(BM_IsolatedFilter, PhonyFilter, NoOp);
  529. BENCHMARK_TEMPLATE(BM_IsolatedFilter, PhonyFilter, SendEmptyMetadata);
  530. typedef Fixture<&grpc_core::ClientChannel::kFilterVtable, 0>
  531. ClientChannelFilter;
  532. BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientChannelFilter, NoOp);
  533. typedef Fixture<&grpc_message_compress_filter, CHECKS_NOT_LAST> CompressFilter;
  534. BENCHMARK_TEMPLATE(BM_IsolatedFilter, CompressFilter, NoOp);
  535. BENCHMARK_TEMPLATE(BM_IsolatedFilter, CompressFilter, SendEmptyMetadata);
  536. typedef Fixture<&grpc_client_deadline_filter, CHECKS_NOT_LAST>
  537. ClientDeadlineFilter;
  538. BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientDeadlineFilter, NoOp);
  539. BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientDeadlineFilter, SendEmptyMetadata);
  540. typedef Fixture<&grpc_server_deadline_filter, CHECKS_NOT_LAST>
  541. ServerDeadlineFilter;
  542. BENCHMARK_TEMPLATE(BM_IsolatedFilter, ServerDeadlineFilter, NoOp);
  543. BENCHMARK_TEMPLATE(BM_IsolatedFilter, ServerDeadlineFilter, SendEmptyMetadata);
  544. typedef Fixture<&grpc_http_client_filter, CHECKS_NOT_LAST | REQUIRES_TRANSPORT>
  545. HttpClientFilter;
  546. BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpClientFilter, NoOp);
  547. BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpClientFilter, SendEmptyMetadata);
  548. typedef Fixture<&grpc_http_server_filter, CHECKS_NOT_LAST> HttpServerFilter;
  549. BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpServerFilter, NoOp);
  550. BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpServerFilter, SendEmptyMetadata);
  551. typedef Fixture<&grpc_message_size_filter, CHECKS_NOT_LAST> MessageSizeFilter;
  552. BENCHMARK_TEMPLATE(BM_IsolatedFilter, MessageSizeFilter, NoOp);
  553. BENCHMARK_TEMPLATE(BM_IsolatedFilter, MessageSizeFilter, SendEmptyMetadata);
  554. // This cmake target is disabled for now because it depends on OpenCensus, which
  555. // is Bazel-only.
  556. // typedef Fixture<&grpc_server_load_reporting_filter, CHECKS_NOT_LAST>
  557. // LoadReportingFilter;
  558. // BENCHMARK_TEMPLATE(BM_IsolatedFilter, LoadReportingFilter, NoOp);
  559. // BENCHMARK_TEMPLATE(BM_IsolatedFilter, LoadReportingFilter,
  560. // SendEmptyMetadata);
  561. ////////////////////////////////////////////////////////////////////////////////
  562. // Benchmarks isolating grpc_call
  563. namespace isolated_call_filter {
  564. typedef struct {
  565. grpc_core::CallCombiner* call_combiner;
  566. } call_data;
  567. static void StartTransportStreamOp(grpc_call_element* elem,
  568. grpc_transport_stream_op_batch* op) {
  569. call_data* calld = static_cast<call_data*>(elem->call_data);
  570. // Construct list of closures to return.
  571. grpc_core::CallCombinerClosureList closures;
  572. if (op->recv_initial_metadata) {
  573. closures.Add(op->payload->recv_initial_metadata.recv_initial_metadata_ready,
  574. GRPC_ERROR_NONE, "recv_initial_metadata");
  575. }
  576. if (op->recv_message) {
  577. closures.Add(op->payload->recv_message.recv_message_ready, GRPC_ERROR_NONE,
  578. "recv_message");
  579. }
  580. if (op->recv_trailing_metadata) {
  581. closures.Add(
  582. op->payload->recv_trailing_metadata.recv_trailing_metadata_ready,
  583. GRPC_ERROR_NONE, "recv_trailing_metadata");
  584. }
  585. if (op->on_complete != nullptr) {
  586. closures.Add(op->on_complete, GRPC_ERROR_NONE, "on_complete");
  587. }
  588. // Execute closures.
  589. closures.RunClosures(calld->call_combiner);
  590. }
  591. static void StartTransportOp(grpc_channel_element* /*elem*/,
  592. grpc_transport_op* op) {
  593. if (op->disconnect_with_error != GRPC_ERROR_NONE) {
  594. GRPC_ERROR_UNREF(op->disconnect_with_error);
  595. }
  596. grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_consumed, GRPC_ERROR_NONE);
  597. }
  598. static grpc_error_handle InitCallElem(grpc_call_element* elem,
  599. const grpc_call_element_args* args) {
  600. call_data* calld = static_cast<call_data*>(elem->call_data);
  601. calld->call_combiner = args->call_combiner;
  602. return GRPC_ERROR_NONE;
  603. }
  604. static void SetPollsetOrPollsetSet(grpc_call_element* /*elem*/,
  605. grpc_polling_entity* /*pollent*/) {}
  606. static void DestroyCallElem(grpc_call_element* /*elem*/,
  607. const grpc_call_final_info* /*final_info*/,
  608. grpc_closure* then_sched_closure) {
  609. grpc_core::ExecCtx::Run(DEBUG_LOCATION, then_sched_closure, GRPC_ERROR_NONE);
  610. }
  611. grpc_error_handle InitChannelElem(grpc_channel_element* /*elem*/,
  612. grpc_channel_element_args* /*args*/) {
  613. return GRPC_ERROR_NONE;
  614. }
  615. void DestroyChannelElem(grpc_channel_element* /*elem*/) {}
  616. void GetChannelInfo(grpc_channel_element* /*elem*/,
  617. const grpc_channel_info* /*channel_info*/) {}
  618. static const grpc_channel_filter isolated_call_filter = {
  619. StartTransportStreamOp, nullptr,
  620. StartTransportOp, sizeof(call_data),
  621. InitCallElem, SetPollsetOrPollsetSet,
  622. DestroyCallElem, 0,
  623. InitChannelElem, DestroyChannelElem,
  624. GetChannelInfo, "isolated_call_filter"};
  625. } // namespace isolated_call_filter
  626. class IsolatedCallFixture : public TrackCounters {
  627. public:
  628. IsolatedCallFixture() {
  629. // We are calling grpc_channel_stack_builder_create() instead of
  630. // grpc_channel_create() here, which means we're not getting the
  631. // grpc_init() called by grpc_channel_create(), but we are getting
  632. // the grpc_shutdown() run by grpc_channel_destroy(). So we need to
  633. // call grpc_init() manually here to balance things out.
  634. grpc_init();
  635. const grpc_channel_args* args = grpc_core::CoreConfiguration::Get()
  636. .channel_args_preconditioning()
  637. .PreconditionChannelArgs(nullptr);
  638. grpc_core::ChannelStackBuilder builder("phony");
  639. builder.SetTarget("phony_target");
  640. builder.SetChannelArgs(args);
  641. builder.AppendFilter(&isolated_call_filter::isolated_call_filter, nullptr);
  642. {
  643. grpc_core::ExecCtx exec_ctx;
  644. channel_ = grpc_channel_create_with_builder(&builder, GRPC_CLIENT_CHANNEL,
  645. nullptr);
  646. }
  647. cq_ = grpc_completion_queue_create_for_next(nullptr);
  648. grpc_channel_args_destroy(args);
  649. }
  650. void Finish(benchmark::State& state) override {
  651. grpc_completion_queue_destroy(cq_);
  652. grpc_channel_destroy(channel_);
  653. TrackCounters::Finish(state);
  654. }
  655. grpc_channel* channel() const { return channel_; }
  656. grpc_completion_queue* cq() const { return cq_; }
  657. private:
  658. grpc_completion_queue* cq_;
  659. grpc_channel* channel_;
  660. };
  661. static void BM_IsolatedCall_NoOp(benchmark::State& state) {
  662. IsolatedCallFixture fixture;
  663. gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
  664. void* method_hdl = grpc_channel_register_call(fixture.channel(), "/foo/bar",
  665. nullptr, nullptr);
  666. for (auto _ : state) {
  667. GPR_TIMER_SCOPE("BenchmarkCycle", 0);
  668. grpc_call_unref(grpc_channel_create_registered_call(
  669. fixture.channel(), nullptr, GRPC_PROPAGATE_DEFAULTS, fixture.cq(),
  670. method_hdl, deadline, nullptr));
  671. }
  672. fixture.Finish(state);
  673. }
  674. BENCHMARK(BM_IsolatedCall_NoOp);
  675. static void BM_IsolatedCall_Unary(benchmark::State& state) {
  676. IsolatedCallFixture fixture;
  677. gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
  678. void* method_hdl = grpc_channel_register_call(fixture.channel(), "/foo/bar",
  679. nullptr, nullptr);
  680. grpc_slice slice = grpc_slice_from_static_string("hello world");
  681. grpc_byte_buffer* send_message = grpc_raw_byte_buffer_create(&slice, 1);
  682. grpc_byte_buffer* recv_message = nullptr;
  683. grpc_status_code status_code;
  684. grpc_slice status_details = grpc_empty_slice();
  685. grpc_metadata_array recv_initial_metadata;
  686. grpc_metadata_array_init(&recv_initial_metadata);
  687. grpc_metadata_array recv_trailing_metadata;
  688. grpc_metadata_array_init(&recv_trailing_metadata);
  689. grpc_op ops[6];
  690. memset(ops, 0, sizeof(ops));
  691. ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
  692. ops[1].op = GRPC_OP_SEND_MESSAGE;
  693. ops[1].data.send_message.send_message = send_message;
  694. ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  695. ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
  696. ops[3].data.recv_initial_metadata.recv_initial_metadata =
  697. &recv_initial_metadata;
  698. ops[4].op = GRPC_OP_RECV_MESSAGE;
  699. ops[4].data.recv_message.recv_message = &recv_message;
  700. ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  701. ops[5].data.recv_status_on_client.status = &status_code;
  702. ops[5].data.recv_status_on_client.status_details = &status_details;
  703. ops[5].data.recv_status_on_client.trailing_metadata = &recv_trailing_metadata;
  704. for (auto _ : state) {
  705. GPR_TIMER_SCOPE("BenchmarkCycle", 0);
  706. grpc_call* call = grpc_channel_create_registered_call(
  707. fixture.channel(), nullptr, GRPC_PROPAGATE_DEFAULTS, fixture.cq(),
  708. method_hdl, deadline, nullptr);
  709. grpc_call_start_batch(call, ops, 6, tag(1), nullptr);
  710. grpc_completion_queue_next(fixture.cq(),
  711. gpr_inf_future(GPR_CLOCK_MONOTONIC), nullptr);
  712. grpc_call_unref(call);
  713. }
  714. fixture.Finish(state);
  715. grpc_metadata_array_destroy(&recv_initial_metadata);
  716. grpc_metadata_array_destroy(&recv_trailing_metadata);
  717. grpc_byte_buffer_destroy(send_message);
  718. }
  719. BENCHMARK(BM_IsolatedCall_Unary);
  720. static void BM_IsolatedCall_StreamingSend(benchmark::State& state) {
  721. IsolatedCallFixture fixture;
  722. gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
  723. void* method_hdl = grpc_channel_register_call(fixture.channel(), "/foo/bar",
  724. nullptr, nullptr);
  725. grpc_slice slice = grpc_slice_from_static_string("hello world");
  726. grpc_byte_buffer* send_message = grpc_raw_byte_buffer_create(&slice, 1);
  727. grpc_metadata_array recv_initial_metadata;
  728. grpc_metadata_array_init(&recv_initial_metadata);
  729. grpc_metadata_array recv_trailing_metadata;
  730. grpc_metadata_array_init(&recv_trailing_metadata);
  731. grpc_op ops[2];
  732. memset(ops, 0, sizeof(ops));
  733. ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
  734. ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
  735. ops[1].data.recv_initial_metadata.recv_initial_metadata =
  736. &recv_initial_metadata;
  737. grpc_call* call = grpc_channel_create_registered_call(
  738. fixture.channel(), nullptr, GRPC_PROPAGATE_DEFAULTS, fixture.cq(),
  739. method_hdl, deadline, nullptr);
  740. grpc_call_start_batch(call, ops, 2, tag(1), nullptr);
  741. grpc_completion_queue_next(fixture.cq(), gpr_inf_future(GPR_CLOCK_MONOTONIC),
  742. nullptr);
  743. memset(ops, 0, sizeof(ops));
  744. ops[0].op = GRPC_OP_SEND_MESSAGE;
  745. ops[0].data.send_message.send_message = send_message;
  746. for (auto _ : state) {
  747. GPR_TIMER_SCOPE("BenchmarkCycle", 0);
  748. grpc_call_start_batch(call, ops, 1, tag(2), nullptr);
  749. grpc_completion_queue_next(fixture.cq(),
  750. gpr_inf_future(GPR_CLOCK_MONOTONIC), nullptr);
  751. }
  752. grpc_call_unref(call);
  753. fixture.Finish(state);
  754. grpc_metadata_array_destroy(&recv_initial_metadata);
  755. grpc_metadata_array_destroy(&recv_trailing_metadata);
  756. grpc_byte_buffer_destroy(send_message);
  757. }
  758. BENCHMARK(BM_IsolatedCall_StreamingSend);
  759. // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
  760. // and others do not. This allows us to support both modes.
  761. namespace benchmark {
  762. void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
  763. } // namespace benchmark
  764. int main(int argc, char** argv) {
  765. grpc::testing::TestEnvironment env(argc, argv);
  766. LibraryInitializer libInit;
  767. ::benchmark::Initialize(&argc, argv);
  768. grpc::testing::InitTest(&argc, &argv, false);
  769. benchmark::RunTheBenchmarksNamespaced();
  770. return 0;
  771. }