Skip to content

Commit 231c504

Browse files
snarkmasterfacebook-github-bot
authored andcommitted
Minimal benchmark
Summary: Before further prioritizing `result` coro usage in `folly/coro/safe` collector code, I wanted to know if the compiler is currently allocating result coro frames on-stack. It turned out that prior to llvm/llvm-project#152623, it is not. ``` Before P152623: ============================================================================ [...]lly/result/test/result_coro_bench.cpp relative time/iter iters/s ============================================================================ result_coro_success 13.61ns 73.49M non_catching_result_func_success 3.39ns 295.00M catching_result_func_success 4.41ns 226.88M result_coro_error 19.55ns 51.16M non_catching_result_func_error 9.15ns 109.26M catching_result_func_error 10.19ns 98.10M After P152623: ============================================================================ [...]lly/result/test/result_coro_bench.cpp relative time/iter iters/s ============================================================================ result_coro_success 10.59ns 94.39M non_catching_result_func_success 3.39ns 295.00M catching_result_func_success 4.07ns 245.81M result_coro_error 13.66ns 73.18M non_catching_result_func_error 9.00ns 111.11M catching_result_func_error 10.04ns 99.63M ``` While it should be possible to further reduce the optimization gap between coro & non-coro, I'm not planning to work on it in the immediate future. Reviewed By: ispeters Differential Revision: D79969519 fbshipit-source-id: 0583a773965f718388715b06067bda4ca8d85737
1 parent 712c406 commit 231c504

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <stdexcept>
18+
19+
#include <folly/Benchmark.h>
20+
#include <folly/Portability.h>
21+
#include <folly/lang/Keep.h>
22+
23+
#if FOLLY_HAS_RESULT
24+
25+
#include <folly/result/result.h>
26+
27+
namespace folly {
28+
29+
// Simple result coroutine that adds 1 to the input
30+
result<int> result_coro(result<int>&& r) {
31+
co_return co_await std::move(r) + 1;
32+
}
33+
34+
// Non-coroutine equivalent using value_or_throw()
35+
result<int> catching_result_func(result<int>&& r) {
36+
return result_catch_all([&]() -> result<int> {
37+
if (r.has_value()) {
38+
return r.value_or_throw() + 1;
39+
}
40+
return std::move(r).non_value();
41+
});
42+
}
43+
44+
// Not QUITE equivalent to the coro -- lacks the exception boundary
45+
result<int> non_catching_result_func(result<int>&& r) {
46+
if (r.has_value()) {
47+
return r.value_or_throw() + 1;
48+
}
49+
return std::move(r).non_value();
50+
}
51+
52+
// The wrappers are for ease of `objdump --disassemble=FN`.
53+
54+
extern "C" FOLLY_KEEP FOLLY_NOINLINE void result_coro_wrapper(result<int> r) {
55+
folly::compiler_must_not_elide(result_coro(std::move(r)));
56+
}
57+
58+
extern "C" FOLLY_KEEP FOLLY_NOINLINE void non_catching_result_func_wrapper(
59+
result<int> r) {
60+
folly::compiler_must_not_elide(non_catching_result_func(std::move(r)));
61+
}
62+
63+
extern "C" FOLLY_KEEP FOLLY_NOINLINE void catching_result_func_wrapper(
64+
result<int> r) {
65+
folly::compiler_must_not_elide(catching_result_func(std::move(r)));
66+
}
67+
68+
BENCHMARK(result_coro_success, iters) {
69+
BenchmarkSuspender suspender;
70+
result<int> input{42};
71+
suspender.dismissing([&] {
72+
while (iters--) {
73+
folly::compiler_must_not_elide(result_coro(input.copy()));
74+
}
75+
});
76+
}
77+
78+
BENCHMARK(non_catching_result_func_success, iters) {
79+
BenchmarkSuspender suspender;
80+
result<int> input{42};
81+
suspender.dismissing([&] {
82+
while (iters--) {
83+
folly::compiler_must_not_elide(non_catching_result_func(input.copy()));
84+
}
85+
});
86+
}
87+
88+
BENCHMARK(catching_result_func_success, iters) {
89+
BenchmarkSuspender suspender;
90+
result<int> input{42};
91+
suspender.dismissing([&] {
92+
while (iters--) {
93+
folly::compiler_must_not_elide(catching_result_func(input.copy()));
94+
}
95+
});
96+
}
97+
98+
BENCHMARK(result_coro_error, iters) {
99+
BenchmarkSuspender suspender;
100+
result<int> input{non_value_result{std::runtime_error{"test error"}}};
101+
suspender.dismissing([&] {
102+
while (iters--) {
103+
folly::compiler_must_not_elide(result_coro(input.copy()));
104+
}
105+
});
106+
}
107+
108+
BENCHMARK(non_catching_result_func_error, iters) {
109+
BenchmarkSuspender suspender;
110+
result<int> input{non_value_result{std::runtime_error{"test error"}}};
111+
suspender.dismissing([&] {
112+
while (iters--) {
113+
folly::compiler_must_not_elide(non_catching_result_func(input.copy()));
114+
}
115+
});
116+
}
117+
118+
BENCHMARK(catching_result_func_error, iters) {
119+
BenchmarkSuspender suspender;
120+
result<int> input{non_value_result{std::runtime_error{"test error"}}};
121+
suspender.dismissing([&] {
122+
while (iters--) {
123+
folly::compiler_must_not_elide(catching_result_func(input.copy()));
124+
}
125+
});
126+
}
127+
128+
} // namespace folly
129+
130+
int main(int argc, char** argv) {
131+
folly::gflags::ParseCommandLineFlags(&argc, &argv, true);
132+
folly::runBenchmarks();
133+
return 0;
134+
}
135+
136+
#endif // FOLLY_HAS_RESULT

0 commit comments

Comments
 (0)