bm_chttp2_transport.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. *
  3. * Copyright 2015 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. /* Microbenchmarks around CHTTP2 transport operations */
  19. #include <string.h>
  20. #include <memory>
  21. #include <queue>
  22. #include <sstream>
  23. #include <benchmark/benchmark.h>
  24. #include <grpc/support/alloc.h>
  25. #include <grpc/support/log.h>
  26. #include <grpc/support/string_util.h>
  27. #include <grpcpp/support/channel_arguments.h>
  28. #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
  29. #include "src/core/ext/transport/chttp2/transport/internal.h"
  30. #include "src/core/lib/iomgr/closure.h"
  31. #include "src/core/lib/resource_quota/api.h"
  32. #include "src/core/lib/slice/slice_internal.h"
  33. #include "test/core/util/test_config.h"
  34. #include "test/cpp/microbenchmarks/helpers.h"
  35. #include "test/cpp/util/test_config.h"
  36. static auto* g_memory_allocator = new grpc_core::MemoryAllocator(
  37. grpc_core::ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
  38. "test"));
  39. ////////////////////////////////////////////////////////////////////////////////
  40. // Helper classes
  41. //
  42. class PhonyEndpoint : public grpc_endpoint {
  43. public:
  44. PhonyEndpoint() {
  45. static const grpc_endpoint_vtable my_vtable = {read,
  46. write,
  47. add_to_pollset,
  48. add_to_pollset_set,
  49. delete_from_pollset_set,
  50. shutdown,
  51. destroy,
  52. get_peer,
  53. get_local_address,
  54. get_fd,
  55. can_track_err};
  56. grpc_endpoint::vtable = &my_vtable;
  57. }
  58. void PushInput(grpc_slice slice) {
  59. if (read_cb_ == nullptr) {
  60. GPR_ASSERT(!have_slice_);
  61. buffered_slice_ = slice;
  62. have_slice_ = true;
  63. return;
  64. }
  65. grpc_slice_buffer_add(slices_, slice);
  66. grpc_core::ExecCtx::Run(DEBUG_LOCATION, read_cb_, GRPC_ERROR_NONE);
  67. read_cb_ = nullptr;
  68. }
  69. private:
  70. grpc_closure* read_cb_ = nullptr;
  71. grpc_slice_buffer* slices_ = nullptr;
  72. bool have_slice_ = false;
  73. grpc_slice buffered_slice_;
  74. void QueueRead(grpc_slice_buffer* slices, grpc_closure* cb) {
  75. GPR_ASSERT(read_cb_ == nullptr);
  76. if (have_slice_) {
  77. have_slice_ = false;
  78. grpc_slice_buffer_add(slices, buffered_slice_);
  79. grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, GRPC_ERROR_NONE);
  80. return;
  81. }
  82. read_cb_ = cb;
  83. slices_ = slices;
  84. }
  85. static void read(grpc_endpoint* ep, grpc_slice_buffer* slices,
  86. grpc_closure* cb, bool /*urgent*/) {
  87. static_cast<PhonyEndpoint*>(ep)->QueueRead(slices, cb);
  88. }
  89. static void write(grpc_endpoint* /*ep*/, grpc_slice_buffer* /*slices*/,
  90. grpc_closure* cb, void* /*arg*/) {
  91. grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, GRPC_ERROR_NONE);
  92. }
  93. static void add_to_pollset(grpc_endpoint* /*ep*/, grpc_pollset* /*pollset*/) {
  94. }
  95. static void add_to_pollset_set(grpc_endpoint* /*ep*/,
  96. grpc_pollset_set* /*pollset*/) {}
  97. static void delete_from_pollset_set(grpc_endpoint* /*ep*/,
  98. grpc_pollset_set* /*pollset*/) {}
  99. static void shutdown(grpc_endpoint* ep, grpc_error_handle why) {
  100. grpc_core::ExecCtx::Run(DEBUG_LOCATION,
  101. static_cast<PhonyEndpoint*>(ep)->read_cb_, why);
  102. }
  103. static void destroy(grpc_endpoint* ep) {
  104. delete static_cast<PhonyEndpoint*>(ep);
  105. }
  106. static absl::string_view get_peer(grpc_endpoint* /*ep*/) { return "test"; }
  107. static absl::string_view get_local_address(grpc_endpoint* /*ep*/) {
  108. return "test";
  109. }
  110. static int get_fd(grpc_endpoint* /*ep*/) { return 0; }
  111. static bool can_track_err(grpc_endpoint* /*ep*/) { return false; }
  112. };
  113. class Fixture {
  114. public:
  115. Fixture(const grpc::ChannelArguments& args, bool client) {
  116. grpc_channel_args c_args = args.c_channel_args();
  117. ep_ = new PhonyEndpoint;
  118. const grpc_channel_args* final_args = grpc_core::CoreConfiguration::Get()
  119. .channel_args_preconditioning()
  120. .PreconditionChannelArgs(&c_args);
  121. t_ = grpc_create_chttp2_transport(final_args, ep_, client);
  122. grpc_channel_args_destroy(final_args);
  123. grpc_chttp2_transport_start_reading(t_, nullptr, nullptr, nullptr);
  124. FlushExecCtx();
  125. }
  126. void FlushExecCtx() { grpc_core::ExecCtx::Get()->Flush(); }
  127. ~Fixture() { grpc_transport_destroy(t_); }
  128. grpc_chttp2_transport* chttp2_transport() {
  129. return reinterpret_cast<grpc_chttp2_transport*>(t_);
  130. }
  131. grpc_transport* transport() { return t_; }
  132. void PushInput(grpc_slice slice) { ep_->PushInput(slice); }
  133. private:
  134. PhonyEndpoint* ep_;
  135. grpc_transport* t_;
  136. };
  137. class TestClosure : public grpc_closure {
  138. public:
  139. virtual ~TestClosure() {}
  140. };
  141. template <class F>
  142. std::unique_ptr<TestClosure> MakeTestClosure(F f) {
  143. struct C : public TestClosure {
  144. explicit C(const F& f) : f_(f) {
  145. GRPC_CLOSURE_INIT(this, Execute, this, nullptr);
  146. }
  147. F f_;
  148. static void Execute(void* arg, grpc_error_handle error) {
  149. static_cast<C*>(arg)->f_(error);
  150. }
  151. };
  152. return std::unique_ptr<TestClosure>(new C(f));
  153. }
  154. template <class F>
  155. grpc_closure* MakeOnceClosure(F f) {
  156. struct C : public grpc_closure {
  157. explicit C(const F& f) : f_(f) {}
  158. F f_;
  159. static void Execute(void* arg, grpc_error_handle error) {
  160. static_cast<C*>(arg)->f_(error);
  161. delete static_cast<C*>(arg);
  162. }
  163. };
  164. auto* c = new C{f};
  165. return GRPC_CLOSURE_INIT(c, C::Execute, c, nullptr);
  166. }
  167. class Stream {
  168. public:
  169. explicit Stream(Fixture* f) : f_(f) {
  170. stream_size_ = grpc_transport_stream_size(f->transport());
  171. stream_ = gpr_malloc(stream_size_);
  172. arena_ = grpc_core::Arena::Create(4096, g_memory_allocator);
  173. }
  174. ~Stream() {
  175. gpr_event_wait(&done_, gpr_inf_future(GPR_CLOCK_REALTIME));
  176. gpr_free(stream_);
  177. arena_->Destroy();
  178. }
  179. void Init(benchmark::State& state) {
  180. GRPC_STREAM_REF_INIT(&refcount_, 1, &Stream::FinishDestroy, this,
  181. "test_stream");
  182. gpr_event_init(&done_);
  183. memset(stream_, 0, stream_size_);
  184. if ((state.iterations() & 0xffff) == 0) {
  185. arena_->Destroy();
  186. arena_ = grpc_core::Arena::Create(4096, g_memory_allocator);
  187. }
  188. grpc_transport_init_stream(f_->transport(),
  189. static_cast<grpc_stream*>(stream_), &refcount_,
  190. nullptr, arena_);
  191. }
  192. void DestroyThen(grpc_closure* closure) {
  193. destroy_closure_ = closure;
  194. #ifndef NDEBUG
  195. grpc_stream_unref(&refcount_, "DestroyThen");
  196. #else
  197. grpc_stream_unref(&refcount_);
  198. #endif
  199. }
  200. void Op(grpc_transport_stream_op_batch* op) {
  201. grpc_transport_perform_stream_op(f_->transport(),
  202. static_cast<grpc_stream*>(stream_), op);
  203. }
  204. grpc_chttp2_stream* chttp2_stream() {
  205. return static_cast<grpc_chttp2_stream*>(stream_);
  206. }
  207. private:
  208. static void FinishDestroy(void* arg, grpc_error_handle /*error*/) {
  209. auto stream = static_cast<Stream*>(arg);
  210. grpc_transport_destroy_stream(stream->f_->transport(),
  211. static_cast<grpc_stream*>(stream->stream_),
  212. stream->destroy_closure_);
  213. gpr_event_set(&stream->done_, reinterpret_cast<void*>(1));
  214. }
  215. Fixture* f_;
  216. grpc_stream_refcount refcount_;
  217. grpc_core::Arena* arena_;
  218. size_t stream_size_;
  219. void* stream_;
  220. grpc_closure* destroy_closure_ = nullptr;
  221. gpr_event done_;
  222. };
  223. ////////////////////////////////////////////////////////////////////////////////
  224. // Benchmarks
  225. //
  226. std::vector<std::unique_ptr<gpr_event>> done_events;
  227. static void BM_StreamCreateDestroy(benchmark::State& state) {
  228. grpc_core::ExecCtx exec_ctx;
  229. TrackCounters track_counters;
  230. Fixture f(grpc::ChannelArguments(), true);
  231. auto* s = new Stream(&f);
  232. grpc_transport_stream_op_batch op;
  233. grpc_transport_stream_op_batch_payload op_payload(nullptr);
  234. op = {};
  235. op.cancel_stream = true;
  236. op.payload = &op_payload;
  237. op_payload.cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
  238. std::unique_ptr<TestClosure> next =
  239. MakeTestClosure([&, s](grpc_error_handle /*error*/) {
  240. if (!state.KeepRunning()) {
  241. delete s;
  242. return;
  243. }
  244. s->Init(state);
  245. s->Op(&op);
  246. s->DestroyThen(next.get());
  247. });
  248. grpc_core::Closure::Run(DEBUG_LOCATION, next.get(), GRPC_ERROR_NONE);
  249. f.FlushExecCtx();
  250. track_counters.Finish(state);
  251. }
  252. BENCHMARK(BM_StreamCreateDestroy);
  253. class RepresentativeClientInitialMetadata {
  254. public:
  255. static void Prepare(grpc_metadata_batch* b) {
  256. b->Set(grpc_core::HttpSchemeMetadata(),
  257. grpc_core::HttpSchemeMetadata::kHttp);
  258. b->Set(grpc_core::HttpMethodMetadata(),
  259. grpc_core::HttpMethodMetadata::kPost);
  260. b->Set(grpc_core::HttpPathMetadata(),
  261. grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
  262. "/foo/bar/bm_chttp2_transport")));
  263. b->Set(grpc_core::HttpAuthorityMetadata(),
  264. grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
  265. "foo.test.google.fr:1234")));
  266. b->Set(
  267. grpc_core::GrpcAcceptEncodingMetadata(),
  268. grpc_core::CompressionAlgorithmSet(
  269. {GRPC_COMPRESS_NONE, GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_GZIP}));
  270. b->Set(grpc_core::TeMetadata(), grpc_core::TeMetadata::kTrailers);
  271. b->Set(grpc_core::ContentTypeMetadata(),
  272. grpc_core::ContentTypeMetadata::kApplicationGrpc);
  273. b->Set(grpc_core::UserAgentMetadata(),
  274. grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
  275. "grpc-c/3.0.0-dev (linux; chttp2; green)")));
  276. }
  277. };
  278. template <class Metadata>
  279. static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State& state) {
  280. TrackCounters track_counters;
  281. grpc_core::ExecCtx exec_ctx;
  282. Fixture f(grpc::ChannelArguments(), true);
  283. auto* s = new Stream(&f);
  284. grpc_transport_stream_op_batch op;
  285. grpc_transport_stream_op_batch_payload op_payload(nullptr);
  286. std::unique_ptr<TestClosure> start;
  287. std::unique_ptr<TestClosure> done;
  288. auto reset_op = [&]() {
  289. op = {};
  290. op.payload = &op_payload;
  291. };
  292. auto arena = grpc_core::MakeScopedArena(1024, g_memory_allocator);
  293. grpc_metadata_batch b(arena.get());
  294. Metadata::Prepare(&b);
  295. f.FlushExecCtx();
  296. gpr_event bm_done;
  297. gpr_event_init(&bm_done);
  298. start = MakeTestClosure([&, s](grpc_error_handle /*error*/) {
  299. if (!state.KeepRunning()) {
  300. delete s;
  301. gpr_event_set(&bm_done, (void*)1);
  302. return;
  303. }
  304. s->Init(state);
  305. reset_op();
  306. op.on_complete = done.get();
  307. op.send_initial_metadata = true;
  308. op.payload->send_initial_metadata.send_initial_metadata = &b;
  309. s->Op(&op);
  310. });
  311. done = MakeTestClosure([&](grpc_error_handle /*error*/) {
  312. reset_op();
  313. op.cancel_stream = true;
  314. op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
  315. s->Op(&op);
  316. s->DestroyThen(start.get());
  317. });
  318. grpc_core::ExecCtx::Run(DEBUG_LOCATION, start.get(), GRPC_ERROR_NONE);
  319. f.FlushExecCtx();
  320. gpr_event_wait(&bm_done, gpr_inf_future(GPR_CLOCK_REALTIME));
  321. track_counters.Finish(state);
  322. }
  323. BENCHMARK_TEMPLATE(BM_StreamCreateSendInitialMetadataDestroy,
  324. RepresentativeClientInitialMetadata);
  325. static void BM_TransportEmptyOp(benchmark::State& state) {
  326. TrackCounters track_counters;
  327. grpc_core::ExecCtx exec_ctx;
  328. Fixture f(grpc::ChannelArguments(), true);
  329. auto* s = new Stream(&f);
  330. s->Init(state);
  331. grpc_transport_stream_op_batch op;
  332. grpc_transport_stream_op_batch_payload op_payload(nullptr);
  333. auto reset_op = [&]() {
  334. op = {};
  335. op.payload = &op_payload;
  336. };
  337. std::unique_ptr<TestClosure> c =
  338. MakeTestClosure([&](grpc_error_handle /*error*/) {
  339. if (!state.KeepRunning()) return;
  340. reset_op();
  341. op.on_complete = c.get();
  342. s->Op(&op);
  343. });
  344. grpc_core::ExecCtx::Run(DEBUG_LOCATION, c.get(), GRPC_ERROR_NONE);
  345. f.FlushExecCtx();
  346. reset_op();
  347. op.cancel_stream = true;
  348. op_payload.cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
  349. gpr_event* stream_cancel_done = new gpr_event;
  350. gpr_event_init(stream_cancel_done);
  351. std::unique_ptr<TestClosure> stream_cancel_closure =
  352. MakeTestClosure([&](grpc_error_handle error) {
  353. GPR_ASSERT(error == GRPC_ERROR_NONE);
  354. gpr_event_set(stream_cancel_done, reinterpret_cast<void*>(1));
  355. });
  356. op.on_complete = stream_cancel_closure.get();
  357. s->Op(&op);
  358. f.FlushExecCtx();
  359. gpr_event_wait(stream_cancel_done, gpr_inf_future(GPR_CLOCK_REALTIME));
  360. done_events.emplace_back(stream_cancel_done);
  361. s->DestroyThen(
  362. MakeOnceClosure([s](grpc_error_handle /*error*/) { delete s; }));
  363. f.FlushExecCtx();
  364. track_counters.Finish(state);
  365. }
  366. BENCHMARK(BM_TransportEmptyOp);
  367. static void BM_TransportStreamSend(benchmark::State& state) {
  368. TrackCounters track_counters;
  369. grpc_core::ExecCtx exec_ctx;
  370. Fixture f(grpc::ChannelArguments(), true);
  371. auto* s = new Stream(&f);
  372. s->Init(state);
  373. grpc_transport_stream_op_batch op;
  374. grpc_transport_stream_op_batch_payload op_payload(nullptr);
  375. auto reset_op = [&]() {
  376. op = {};
  377. op.payload = &op_payload;
  378. };
  379. // Create the send_message payload slice.
  380. // Note: We use grpc_slice_malloc_large() instead of grpc_slice_malloc()
  381. // to force the slice to be refcounted, so that it remains alive when it
  382. // is unreffed after each send_message op.
  383. grpc_slice send_slice = grpc_slice_malloc_large(state.range(0));
  384. memset(GRPC_SLICE_START_PTR(send_slice), 0, GRPC_SLICE_LENGTH(send_slice));
  385. grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> send_stream;
  386. auto arena = grpc_core::MakeScopedArena(1024, g_memory_allocator);
  387. grpc_metadata_batch b(arena.get());
  388. RepresentativeClientInitialMetadata::Prepare(&b);
  389. gpr_event* bm_done = new gpr_event;
  390. gpr_event_init(bm_done);
  391. std::unique_ptr<TestClosure> c =
  392. MakeTestClosure([&](grpc_error_handle /*error*/) {
  393. if (!state.KeepRunning()) {
  394. gpr_event_set(bm_done, reinterpret_cast<void*>(1));
  395. return;
  396. }
  397. grpc_slice_buffer send_buffer;
  398. grpc_slice_buffer_init(&send_buffer);
  399. grpc_slice_buffer_add(&send_buffer, grpc_slice_ref(send_slice));
  400. send_stream.Init(&send_buffer, 0);
  401. grpc_slice_buffer_destroy(&send_buffer);
  402. // force outgoing window to be yuge
  403. s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
  404. f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
  405. reset_op();
  406. op.on_complete = c.get();
  407. op.send_message = true;
  408. op.payload->send_message.send_message.reset(send_stream.get());
  409. s->Op(&op);
  410. });
  411. reset_op();
  412. op.send_initial_metadata = true;
  413. op.payload->send_initial_metadata.send_initial_metadata = &b;
  414. op.on_complete = c.get();
  415. s->Op(&op);
  416. f.FlushExecCtx();
  417. gpr_event_wait(bm_done, gpr_inf_future(GPR_CLOCK_REALTIME));
  418. done_events.emplace_back(bm_done);
  419. reset_op();
  420. op.cancel_stream = true;
  421. op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
  422. gpr_event* stream_cancel_done = new gpr_event;
  423. gpr_event_init(stream_cancel_done);
  424. std::unique_ptr<TestClosure> stream_cancel_closure =
  425. MakeTestClosure([&](grpc_error_handle error) {
  426. GPR_ASSERT(error == GRPC_ERROR_NONE);
  427. gpr_event_set(stream_cancel_done, reinterpret_cast<void*>(1));
  428. });
  429. op.on_complete = stream_cancel_closure.get();
  430. s->Op(&op);
  431. f.FlushExecCtx();
  432. gpr_event_wait(stream_cancel_done, gpr_inf_future(GPR_CLOCK_REALTIME));
  433. done_events.emplace_back(stream_cancel_done);
  434. s->DestroyThen(
  435. MakeOnceClosure([s](grpc_error_handle /*error*/) { delete s; }));
  436. f.FlushExecCtx();
  437. track_counters.Finish(state);
  438. grpc_slice_unref(send_slice);
  439. }
  440. BENCHMARK(BM_TransportStreamSend)->Range(0, 128 * 1024 * 1024);
  441. #define SLICE_FROM_BUFFER(s) grpc_slice_from_static_buffer(s, sizeof(s) - 1)
  442. static grpc_slice CreateIncomingDataSlice(size_t length, size_t frame_size) {
  443. std::queue<char> unframed;
  444. unframed.push(static_cast<uint8_t>(0));
  445. unframed.push(static_cast<uint8_t>(length >> 24));
  446. unframed.push(static_cast<uint8_t>(length >> 16));
  447. unframed.push(static_cast<uint8_t>(length >> 8));
  448. unframed.push(static_cast<uint8_t>(length));
  449. for (size_t i = 0; i < length; i++) {
  450. unframed.push('a');
  451. }
  452. std::vector<char> framed;
  453. while (unframed.size() > frame_size) {
  454. // frame size
  455. framed.push_back(static_cast<uint8_t>(frame_size >> 16));
  456. framed.push_back(static_cast<uint8_t>(frame_size >> 8));
  457. framed.push_back(static_cast<uint8_t>(frame_size));
  458. // data frame
  459. framed.push_back(0);
  460. // no flags
  461. framed.push_back(0);
  462. // stream id
  463. framed.push_back(0);
  464. framed.push_back(0);
  465. framed.push_back(0);
  466. framed.push_back(1);
  467. // frame data
  468. for (size_t i = 0; i < frame_size; i++) {
  469. framed.push_back(unframed.front());
  470. unframed.pop();
  471. }
  472. }
  473. // frame size
  474. framed.push_back(static_cast<uint8_t>(unframed.size() >> 16));
  475. framed.push_back(static_cast<uint8_t>(unframed.size() >> 8));
  476. framed.push_back(static_cast<uint8_t>(unframed.size()));
  477. // data frame
  478. framed.push_back(0);
  479. // no flags
  480. framed.push_back(0);
  481. // stream id
  482. framed.push_back(0);
  483. framed.push_back(0);
  484. framed.push_back(0);
  485. framed.push_back(1);
  486. while (!unframed.empty()) {
  487. framed.push_back(unframed.front());
  488. unframed.pop();
  489. }
  490. return grpc_slice_from_copied_buffer(framed.data(), framed.size());
  491. }
  492. static void BM_TransportStreamRecv(benchmark::State& state) {
  493. TrackCounters track_counters;
  494. grpc_core::ExecCtx exec_ctx;
  495. Fixture f(grpc::ChannelArguments(), true);
  496. auto* s = new Stream(&f);
  497. s->Init(state);
  498. grpc_transport_stream_op_batch_payload op_payload(nullptr);
  499. grpc_transport_stream_op_batch op;
  500. grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_stream;
  501. grpc_slice incoming_data = CreateIncomingDataSlice(state.range(0), 16384);
  502. auto reset_op = [&]() {
  503. op = {};
  504. op.payload = &op_payload;
  505. };
  506. auto arena = grpc_core::MakeScopedArena(1024, g_memory_allocator);
  507. grpc_metadata_batch b(arena.get());
  508. RepresentativeClientInitialMetadata::Prepare(&b);
  509. std::unique_ptr<TestClosure> do_nothing =
  510. MakeTestClosure([](grpc_error_handle /*error*/) {});
  511. uint32_t received;
  512. std::unique_ptr<TestClosure> drain_start;
  513. std::unique_ptr<TestClosure> drain;
  514. std::unique_ptr<TestClosure> drain_continue;
  515. grpc_slice recv_slice;
  516. std::unique_ptr<TestClosure> c =
  517. MakeTestClosure([&](grpc_error_handle /*error*/) {
  518. if (!state.KeepRunning()) return;
  519. // force outgoing window to be yuge
  520. s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
  521. f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
  522. received = 0;
  523. reset_op();
  524. op.on_complete = do_nothing.get();
  525. op.recv_message = true;
  526. op.payload->recv_message.recv_message = &recv_stream;
  527. op.payload->recv_message.call_failed_before_recv_message = nullptr;
  528. op.payload->recv_message.recv_message_ready = drain_start.get();
  529. s->Op(&op);
  530. f.PushInput(grpc_slice_ref(incoming_data));
  531. });
  532. drain_start = MakeTestClosure([&](grpc_error_handle /*error*/) {
  533. if (recv_stream == nullptr) {
  534. GPR_ASSERT(!state.KeepRunning());
  535. return;
  536. }
  537. grpc_core::Closure::Run(DEBUG_LOCATION, drain.get(), GRPC_ERROR_NONE);
  538. });
  539. drain = MakeTestClosure([&](grpc_error_handle /*error*/) {
  540. do {
  541. if (received == recv_stream->length()) {
  542. recv_stream.reset();
  543. grpc_core::ExecCtx::Run(DEBUG_LOCATION, c.get(), GRPC_ERROR_NONE);
  544. return;
  545. }
  546. } while (recv_stream->Next(recv_stream->length() - received,
  547. drain_continue.get()) &&
  548. GRPC_ERROR_NONE == recv_stream->Pull(&recv_slice) &&
  549. (received += GRPC_SLICE_LENGTH(recv_slice),
  550. grpc_slice_unref_internal(recv_slice), true));
  551. });
  552. drain_continue = MakeTestClosure([&](grpc_error_handle /*error*/) {
  553. GPR_ASSERT(GRPC_LOG_IF_ERROR("Pull", recv_stream->Pull(&recv_slice)));
  554. received += GRPC_SLICE_LENGTH(recv_slice);
  555. grpc_slice_unref_internal(recv_slice);
  556. grpc_core::Closure::Run(DEBUG_LOCATION, drain.get(), GRPC_ERROR_NONE);
  557. });
  558. reset_op();
  559. auto b_recv = absl::make_unique<grpc_metadata_batch>(arena.get());
  560. op.send_initial_metadata = true;
  561. op.payload->send_initial_metadata.send_initial_metadata = &b;
  562. op.recv_initial_metadata = true;
  563. op.payload->recv_initial_metadata.recv_initial_metadata = b_recv.get();
  564. op.payload->recv_initial_metadata.recv_initial_metadata_ready =
  565. do_nothing.get();
  566. op.on_complete = c.get();
  567. s->Op(&op);
  568. f.PushInput(SLICE_FROM_BUFFER(
  569. "\x00\x00\x00\x04\x00\x00\x00\x00\x00"
  570. // Generated using:
  571. // tools/codegen/core/gen_header_frame.py <
  572. // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
  573. "\x00\x00X\x01\x04\x00\x00\x00\x01"
  574. "\x10\x07:status\x03"
  575. "200"
  576. "\x10\x0c"
  577. "content-type\x10"
  578. "application/grpc"
  579. "\x10\x14grpc-accept-encoding\x15identity,deflate,gzip"));
  580. f.FlushExecCtx();
  581. reset_op();
  582. op.cancel_stream = true;
  583. op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
  584. gpr_event* stream_cancel_done = new gpr_event;
  585. gpr_event_init(stream_cancel_done);
  586. std::unique_ptr<TestClosure> stream_cancel_closure =
  587. MakeTestClosure([&](grpc_error_handle error) {
  588. GPR_ASSERT(error == GRPC_ERROR_NONE);
  589. gpr_event_set(stream_cancel_done, reinterpret_cast<void*>(1));
  590. });
  591. op.on_complete = stream_cancel_closure.get();
  592. s->Op(&op);
  593. f.FlushExecCtx();
  594. gpr_event_wait(stream_cancel_done, gpr_inf_future(GPR_CLOCK_REALTIME));
  595. done_events.emplace_back(stream_cancel_done);
  596. s->DestroyThen(MakeOnceClosure([s, &b_recv](grpc_error_handle /*error*/) {
  597. b_recv.reset();
  598. delete s;
  599. }));
  600. f.FlushExecCtx();
  601. track_counters.Finish(state);
  602. grpc_slice_unref(incoming_data);
  603. }
  604. BENCHMARK(BM_TransportStreamRecv)->Range(0, 128 * 1024 * 1024);
  605. // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
  606. // and others do not. This allows us to support both modes.
  607. namespace benchmark {
  608. void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
  609. } // namespace benchmark
  610. int main(int argc, char** argv) {
  611. grpc::testing::TestEnvironment env(argc, argv);
  612. LibraryInitializer libInit;
  613. ::benchmark::Initialize(&argc, argv);
  614. grpc::testing::InitTest(&argc, &argv, false);
  615. benchmark::RunTheBenchmarksNamespaced();
  616. return 0;
  617. }