bm_closure.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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. /* Test various closure related operations */
  19. #include <sstream>
  20. #include <benchmark/benchmark.h>
  21. #include <grpc/grpc.h>
  22. #include "src/core/lib/gpr/spinlock.h"
  23. #include "src/core/lib/iomgr/closure.h"
  24. #include "src/core/lib/iomgr/combiner.h"
  25. #include "src/core/lib/iomgr/exec_ctx.h"
  26. #include "test/core/util/test_config.h"
  27. #include "test/cpp/microbenchmarks/helpers.h"
  28. #include "test/cpp/util/test_config.h"
  29. static void BM_NoOpExecCtx(benchmark::State& state) {
  30. TrackCounters track_counters;
  31. for (auto _ : state) {
  32. grpc_core::ExecCtx exec_ctx;
  33. }
  34. track_counters.Finish(state);
  35. }
  36. BENCHMARK(BM_NoOpExecCtx);
  37. static void BM_WellFlushed(benchmark::State& state) {
  38. TrackCounters track_counters;
  39. grpc_core::ExecCtx exec_ctx;
  40. for (auto _ : state) {
  41. grpc_core::ExecCtx::Get()->Flush();
  42. }
  43. track_counters.Finish(state);
  44. }
  45. BENCHMARK(BM_WellFlushed);
  46. static void DoNothing(void* /*arg*/, grpc_error_handle /*error*/) {}
  47. static void BM_ClosureInitAgainstExecCtx(benchmark::State& state) {
  48. TrackCounters track_counters;
  49. grpc_closure c;
  50. for (auto _ : state) {
  51. benchmark::DoNotOptimize(
  52. GRPC_CLOSURE_INIT(&c, DoNothing, nullptr, grpc_schedule_on_exec_ctx));
  53. }
  54. track_counters.Finish(state);
  55. }
  56. BENCHMARK(BM_ClosureInitAgainstExecCtx);
  57. static void BM_ClosureInitAgainstCombiner(benchmark::State& state) {
  58. TrackCounters track_counters;
  59. grpc_core::Combiner* combiner = grpc_combiner_create();
  60. grpc_closure c;
  61. grpc_core::ExecCtx exec_ctx;
  62. for (auto _ : state) {
  63. benchmark::DoNotOptimize(
  64. GRPC_CLOSURE_INIT(&c, DoNothing, nullptr, nullptr));
  65. }
  66. GRPC_COMBINER_UNREF(combiner, "finished");
  67. track_counters.Finish(state);
  68. }
  69. BENCHMARK(BM_ClosureInitAgainstCombiner);
  70. static void BM_ClosureRun(benchmark::State& state) {
  71. TrackCounters track_counters;
  72. grpc_closure c;
  73. GRPC_CLOSURE_INIT(&c, DoNothing, nullptr, grpc_schedule_on_exec_ctx);
  74. grpc_core::ExecCtx exec_ctx;
  75. for (auto _ : state) {
  76. grpc_core::Closure::Run(DEBUG_LOCATION, &c, GRPC_ERROR_NONE);
  77. }
  78. track_counters.Finish(state);
  79. }
  80. BENCHMARK(BM_ClosureRun);
  81. static void BM_ClosureCreateAndRun(benchmark::State& state) {
  82. TrackCounters track_counters;
  83. grpc_core::ExecCtx exec_ctx;
  84. for (auto _ : state) {
  85. grpc_core::Closure::Run(
  86. DEBUG_LOCATION,
  87. GRPC_CLOSURE_CREATE(DoNothing, nullptr, grpc_schedule_on_exec_ctx),
  88. GRPC_ERROR_NONE);
  89. }
  90. track_counters.Finish(state);
  91. }
  92. BENCHMARK(BM_ClosureCreateAndRun);
  93. static void BM_ClosureInitAndRun(benchmark::State& state) {
  94. TrackCounters track_counters;
  95. grpc_core::ExecCtx exec_ctx;
  96. grpc_closure c;
  97. for (auto _ : state) {
  98. grpc_core::Closure::Run(
  99. DEBUG_LOCATION,
  100. GRPC_CLOSURE_INIT(&c, DoNothing, nullptr, grpc_schedule_on_exec_ctx),
  101. GRPC_ERROR_NONE);
  102. }
  103. track_counters.Finish(state);
  104. }
  105. BENCHMARK(BM_ClosureInitAndRun);
  106. static void BM_ClosureSchedOnExecCtx(benchmark::State& state) {
  107. TrackCounters track_counters;
  108. grpc_closure c;
  109. GRPC_CLOSURE_INIT(&c, DoNothing, nullptr, grpc_schedule_on_exec_ctx);
  110. grpc_core::ExecCtx exec_ctx;
  111. for (auto _ : state) {
  112. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &c, GRPC_ERROR_NONE);
  113. grpc_core::ExecCtx::Get()->Flush();
  114. }
  115. track_counters.Finish(state);
  116. }
  117. BENCHMARK(BM_ClosureSchedOnExecCtx);
  118. static void BM_ClosureSched2OnExecCtx(benchmark::State& state) {
  119. TrackCounters track_counters;
  120. grpc_closure c1;
  121. grpc_closure c2;
  122. GRPC_CLOSURE_INIT(&c1, DoNothing, nullptr, grpc_schedule_on_exec_ctx);
  123. GRPC_CLOSURE_INIT(&c2, DoNothing, nullptr, grpc_schedule_on_exec_ctx);
  124. grpc_core::ExecCtx exec_ctx;
  125. for (auto _ : state) {
  126. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &c1, GRPC_ERROR_NONE);
  127. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &c2, GRPC_ERROR_NONE);
  128. grpc_core::ExecCtx::Get()->Flush();
  129. }
  130. track_counters.Finish(state);
  131. }
  132. BENCHMARK(BM_ClosureSched2OnExecCtx);
  133. static void BM_ClosureSched3OnExecCtx(benchmark::State& state) {
  134. TrackCounters track_counters;
  135. grpc_closure c1;
  136. grpc_closure c2;
  137. grpc_closure c3;
  138. GRPC_CLOSURE_INIT(&c1, DoNothing, nullptr, grpc_schedule_on_exec_ctx);
  139. GRPC_CLOSURE_INIT(&c2, DoNothing, nullptr, grpc_schedule_on_exec_ctx);
  140. GRPC_CLOSURE_INIT(&c3, DoNothing, nullptr, grpc_schedule_on_exec_ctx);
  141. grpc_core::ExecCtx exec_ctx;
  142. for (auto _ : state) {
  143. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &c1, GRPC_ERROR_NONE);
  144. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &c2, GRPC_ERROR_NONE);
  145. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &c3, GRPC_ERROR_NONE);
  146. grpc_core::ExecCtx::Get()->Flush();
  147. }
  148. track_counters.Finish(state);
  149. }
  150. BENCHMARK(BM_ClosureSched3OnExecCtx);
  151. static void BM_AcquireMutex(benchmark::State& state) {
  152. TrackCounters track_counters;
  153. // for comparison with the combiner stuff below
  154. gpr_mu mu;
  155. gpr_mu_init(&mu);
  156. grpc_core::ExecCtx exec_ctx;
  157. for (auto _ : state) {
  158. gpr_mu_lock(&mu);
  159. DoNothing(nullptr, GRPC_ERROR_NONE);
  160. gpr_mu_unlock(&mu);
  161. }
  162. gpr_mu_destroy(&mu);
  163. track_counters.Finish(state);
  164. }
  165. BENCHMARK(BM_AcquireMutex);
  166. static void BM_TryAcquireMutex(benchmark::State& state) {
  167. TrackCounters track_counters;
  168. // for comparison with the combiner stuff below
  169. gpr_mu mu;
  170. gpr_mu_init(&mu);
  171. grpc_core::ExecCtx exec_ctx;
  172. for (auto _ : state) {
  173. if (gpr_mu_trylock(&mu)) {
  174. DoNothing(nullptr, GRPC_ERROR_NONE);
  175. gpr_mu_unlock(&mu);
  176. } else {
  177. abort();
  178. }
  179. }
  180. gpr_mu_destroy(&mu);
  181. track_counters.Finish(state);
  182. }
  183. BENCHMARK(BM_TryAcquireMutex);
  184. static void BM_AcquireSpinlock(benchmark::State& state) {
  185. TrackCounters track_counters;
  186. // for comparison with the combiner stuff below
  187. gpr_spinlock mu = GPR_SPINLOCK_INITIALIZER;
  188. grpc_core::ExecCtx exec_ctx;
  189. for (auto _ : state) {
  190. gpr_spinlock_lock(&mu);
  191. DoNothing(nullptr, GRPC_ERROR_NONE);
  192. gpr_spinlock_unlock(&mu);
  193. }
  194. track_counters.Finish(state);
  195. }
  196. BENCHMARK(BM_AcquireSpinlock);
  197. static void BM_TryAcquireSpinlock(benchmark::State& state) {
  198. TrackCounters track_counters;
  199. // for comparison with the combiner stuff below
  200. gpr_spinlock mu = GPR_SPINLOCK_INITIALIZER;
  201. grpc_core::ExecCtx exec_ctx;
  202. for (auto _ : state) {
  203. if (gpr_spinlock_trylock(&mu)) {
  204. DoNothing(nullptr, GRPC_ERROR_NONE);
  205. gpr_spinlock_unlock(&mu);
  206. } else {
  207. abort();
  208. }
  209. }
  210. track_counters.Finish(state);
  211. }
  212. BENCHMARK(BM_TryAcquireSpinlock);
  213. static void BM_ClosureSchedOnCombiner(benchmark::State& state) {
  214. TrackCounters track_counters;
  215. grpc_core::Combiner* combiner = grpc_combiner_create();
  216. grpc_closure c;
  217. GRPC_CLOSURE_INIT(&c, DoNothing, nullptr, nullptr);
  218. grpc_core::ExecCtx exec_ctx;
  219. for (auto _ : state) {
  220. combiner->Run(&c, GRPC_ERROR_NONE);
  221. grpc_core::ExecCtx::Get()->Flush();
  222. }
  223. GRPC_COMBINER_UNREF(combiner, "finished");
  224. track_counters.Finish(state);
  225. }
  226. BENCHMARK(BM_ClosureSchedOnCombiner);
  227. static void BM_ClosureSched2OnCombiner(benchmark::State& state) {
  228. TrackCounters track_counters;
  229. grpc_core::Combiner* combiner = grpc_combiner_create();
  230. grpc_closure c1;
  231. grpc_closure c2;
  232. GRPC_CLOSURE_INIT(&c1, DoNothing, nullptr, nullptr);
  233. GRPC_CLOSURE_INIT(&c2, DoNothing, nullptr, nullptr);
  234. grpc_core::ExecCtx exec_ctx;
  235. for (auto _ : state) {
  236. combiner->Run(&c1, GRPC_ERROR_NONE);
  237. combiner->Run(&c2, GRPC_ERROR_NONE);
  238. grpc_core::ExecCtx::Get()->Flush();
  239. }
  240. GRPC_COMBINER_UNREF(combiner, "finished");
  241. track_counters.Finish(state);
  242. }
  243. BENCHMARK(BM_ClosureSched2OnCombiner);
  244. static void BM_ClosureSched3OnCombiner(benchmark::State& state) {
  245. TrackCounters track_counters;
  246. grpc_core::Combiner* combiner = grpc_combiner_create();
  247. grpc_closure c1;
  248. grpc_closure c2;
  249. grpc_closure c3;
  250. GRPC_CLOSURE_INIT(&c1, DoNothing, nullptr, nullptr);
  251. GRPC_CLOSURE_INIT(&c2, DoNothing, nullptr, nullptr);
  252. GRPC_CLOSURE_INIT(&c3, DoNothing, nullptr, nullptr);
  253. grpc_core::ExecCtx exec_ctx;
  254. for (auto _ : state) {
  255. combiner->Run(&c1, GRPC_ERROR_NONE);
  256. combiner->Run(&c2, GRPC_ERROR_NONE);
  257. combiner->Run(&c3, GRPC_ERROR_NONE);
  258. grpc_core::ExecCtx::Get()->Flush();
  259. }
  260. GRPC_COMBINER_UNREF(combiner, "finished");
  261. track_counters.Finish(state);
  262. }
  263. BENCHMARK(BM_ClosureSched3OnCombiner);
  264. static void BM_ClosureSched2OnTwoCombiners(benchmark::State& state) {
  265. TrackCounters track_counters;
  266. grpc_core::Combiner* combiner1 = grpc_combiner_create();
  267. grpc_core::Combiner* combiner2 = grpc_combiner_create();
  268. grpc_closure c1;
  269. grpc_closure c2;
  270. GRPC_CLOSURE_INIT(&c1, DoNothing, nullptr, nullptr);
  271. GRPC_CLOSURE_INIT(&c2, DoNothing, nullptr, nullptr);
  272. grpc_core::ExecCtx exec_ctx;
  273. for (auto _ : state) {
  274. combiner1->Run(&c1, GRPC_ERROR_NONE);
  275. combiner2->Run(&c2, GRPC_ERROR_NONE);
  276. grpc_core::ExecCtx::Get()->Flush();
  277. }
  278. GRPC_COMBINER_UNREF(combiner1, "finished");
  279. GRPC_COMBINER_UNREF(combiner2, "finished");
  280. track_counters.Finish(state);
  281. }
  282. BENCHMARK(BM_ClosureSched2OnTwoCombiners);
  283. static void BM_ClosureSched4OnTwoCombiners(benchmark::State& state) {
  284. TrackCounters track_counters;
  285. grpc_core::Combiner* combiner1 = grpc_combiner_create();
  286. grpc_core::Combiner* combiner2 = grpc_combiner_create();
  287. grpc_closure c1;
  288. grpc_closure c2;
  289. grpc_closure c3;
  290. grpc_closure c4;
  291. GRPC_CLOSURE_INIT(&c1, DoNothing, nullptr, nullptr);
  292. GRPC_CLOSURE_INIT(&c2, DoNothing, nullptr, nullptr);
  293. GRPC_CLOSURE_INIT(&c3, DoNothing, nullptr, nullptr);
  294. GRPC_CLOSURE_INIT(&c4, DoNothing, nullptr, nullptr);
  295. grpc_core::ExecCtx exec_ctx;
  296. for (auto _ : state) {
  297. combiner1->Run(&c1, GRPC_ERROR_NONE);
  298. combiner2->Run(&c2, GRPC_ERROR_NONE);
  299. combiner1->Run(&c3, GRPC_ERROR_NONE);
  300. combiner2->Run(&c4, GRPC_ERROR_NONE);
  301. grpc_core::ExecCtx::Get()->Flush();
  302. }
  303. GRPC_COMBINER_UNREF(combiner1, "finished");
  304. GRPC_COMBINER_UNREF(combiner2, "finished");
  305. track_counters.Finish(state);
  306. }
  307. BENCHMARK(BM_ClosureSched4OnTwoCombiners);
  308. // Helper that continuously reschedules the same closure against something until
  309. // the benchmark is complete
  310. class Rescheduler {
  311. public:
  312. explicit Rescheduler(benchmark::State& state) : state_(state) {
  313. GRPC_CLOSURE_INIT(&closure_, Step, this, nullptr);
  314. }
  315. void ScheduleFirst() {
  316. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &closure_, GRPC_ERROR_NONE);
  317. }
  318. void ScheduleFirstAgainstDifferentScheduler() {
  319. grpc_core::ExecCtx::Run(DEBUG_LOCATION,
  320. GRPC_CLOSURE_CREATE(Step, this, nullptr),
  321. GRPC_ERROR_NONE);
  322. }
  323. private:
  324. benchmark::State& state_;
  325. grpc_closure closure_;
  326. static void Step(void* arg, grpc_error_handle /*error*/) {
  327. Rescheduler* self = static_cast<Rescheduler*>(arg);
  328. if (self->state_.KeepRunning()) {
  329. grpc_core::ExecCtx::Run(DEBUG_LOCATION, &self->closure_, GRPC_ERROR_NONE);
  330. }
  331. }
  332. };
  333. static void BM_ClosureReschedOnExecCtx(benchmark::State& state) {
  334. TrackCounters track_counters;
  335. grpc_core::ExecCtx exec_ctx;
  336. Rescheduler r(state);
  337. r.ScheduleFirst();
  338. grpc_core::ExecCtx::Get()->Flush();
  339. track_counters.Finish(state);
  340. }
  341. BENCHMARK(BM_ClosureReschedOnExecCtx);
  342. // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
  343. // and others do not. This allows us to support both modes.
  344. namespace benchmark {
  345. void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
  346. } // namespace benchmark
  347. int main(int argc, char** argv) {
  348. grpc::testing::TestEnvironment env(argc, argv);
  349. LibraryInitializer libInit;
  350. ::benchmark::Initialize(&argc, argv);
  351. grpc::testing::InitTest(&argc, &argv, false);
  352. benchmark::RunTheBenchmarksNamespaced();
  353. return 0;
  354. }