@@ -19,9 +19,8 @@ struct stack_on_heap {
1919 }
2020};
2121
22- template <lf::alloc_mixin StackPolicy>
23- constexpr auto no_await =
24- [](this auto fib, std::int64_t *ret, std::int64_t n) -> lf::task<void , StackPolicy> {
22+ template <lf::alloc_mixin Stack>
23+ constexpr auto no_await = [](this auto fib, std::int64_t *ret, std::int64_t n) -> lf::task<void , Stack> {
2524 if (n < 2 ) {
2625 *ret = n;
2726 co_return ;
@@ -30,14 +29,19 @@ constexpr auto no_await =
3029 std::int64_t lhs = 0 ;
3130 std::int64_t rhs = 0 ;
3231
33- fib (&lhs, n - 1 ).promise ->handle ().resume ();
34- fib (&rhs, n - 2 ).promise ->handle ().resume ();
32+ auto t1 = fib (&lhs, n - 1 );
33+ t1.promise ->frame .kind = lf::category::root;
34+ t1.promise ->handle ().resume ();
35+
36+ auto t2 = fib (&rhs, n - 2 );
37+ t2.promise ->frame .kind = lf::category::root;
38+ t2.promise ->handle ().resume ();
3539
3640 *ret = lhs + rhs;
3741};
3842
39- template <lf::alloc_mixin StackPolicy >
40- constexpr auto await = [](this auto fib, std::int64_t *ret, std::int64_t n) -> lf::task<void , StackPolicy > {
43+ template <lf::alloc_mixin Stack >
44+ constexpr auto await = [](this auto fib, std::int64_t *ret, std::int64_t n) -> lf::task<void , Stack > {
4145 if (n < 2 ) {
4246 *ret = n;
4347 co_return ;
@@ -52,6 +56,35 @@ constexpr auto await = [](this auto fib, std::int64_t *ret, std::int64_t n) -> l
5256 *ret = lhs + rhs;
5357};
5458
59+ constexpr auto ret = [](this auto fib, std::int64_t n) -> lf::task<std::int64_t , tls_bump> {
60+ if (n < 2 ) {
61+ co_return n;
62+ }
63+
64+ std::int64_t lhs = 0 ;
65+ std::int64_t rhs = 0 ;
66+
67+ co_await lf::call (&lhs, fib, n - 1 );
68+ co_await lf::call (&rhs, fib, n - 2 );
69+
70+ co_return lhs + rhs;
71+ };
72+
73+ template <typename Ctx, typename A = tls_bump>
74+ constexpr auto fork_call = [](this auto fib, std::int64_t n) -> lf::task<std::int64_t , A, Ctx> {
75+ if (n < 2 ) {
76+ co_return n;
77+ }
78+
79+ std::int64_t lhs = 0 ;
80+ std::int64_t rhs = 0 ;
81+
82+ co_await lf::fork (&rhs, fib, n - 2 );
83+ co_await lf::call (&lhs, fib, n - 1 );
84+
85+ co_return lhs + rhs;
86+ };
87+
5588template <auto Fn>
5689void fib (benchmark::State &state) {
5790
@@ -60,18 +93,27 @@ void fib(benchmark::State &state) {
6093
6194 state.counters [" n" ] = static_cast <double >(n);
6295
63- std::unique_ptr buffer = std::make_unique<std::byte[]>(1024 * 1024 );
96+ // Set bump allocator buffer
97+ std::unique_ptr buf = std::make_unique<std::byte[]>(1024 * 1024 );
98+ tls_bump_ptr = buf.get ();
99+ bump_ptr = buf.get ();
64100
65- fib_bump_ptr = buffer.get ();
101+ // Set both context and poly context
102+ std::unique_ptr ctx = std::make_unique<vector_ctx>();
103+ lf::thread_context<vector_ctx> = ctx.get ();
104+ lf::thread_context<lf::polymorphic_context> = ctx.get ();
66105
67106 for (auto _ : state) {
68107 benchmark::DoNotOptimize (n);
69108 std::int64_t result = 0 ;
70109
71110 if constexpr (requires { Fn (&result, n); }) {
72- Fn (&result, n).promise ->handle ().resume ();
111+ auto task = Fn (&result, n);
112+ task.promise ->frame .kind = lf::category::root;
113+ task.promise ->handle ().resume ();
73114 } else {
74115 auto task = Fn (n);
116+ task.promise ->frame .kind = lf::category::root;
75117 task.promise ->return_address = &result;
76118 task.promise ->handle ().resume ();
77119 }
@@ -80,39 +122,54 @@ void fib(benchmark::State &state) {
80122 benchmark::DoNotOptimize (result);
81123 }
82124
83- if (fib_bump_ptr != buffer .get ()) {
125+ if (tls_bump_ptr != buf. get () || bump_ptr != buf .get ()) {
84126 LF_TERMINATE (" Stack leak detected" );
85127 }
86- }
87-
88- template <lf::alloc_mixin StackPolicy>
89- constexpr auto ret = [](this auto fib, std::int64_t n) -> lf::task<std::int64_t , StackPolicy> {
90- if (n < 2 ) {
91- co_return n;
92- }
93-
94- std::int64_t lhs = 0 ;
95- std::int64_t rhs = 0 ;
96128
97- co_await lf::call (&lhs, fib, n - 1 ) ;
98- co_await lf::call (&rhs, fib, n - 2 ) ;
99-
100- co_return lhs + rhs ;
101- };
129+ tls_bump_ptr = nullptr ;
130+ bump_ptr = nullptr ;
131+ lf::thread_context<vector_ctx> = nullptr ;
132+ lf::thread_context<lf::polymorphic_context> = nullptr ;
133+ }
102134
103135} // namespace
104136
137+ // Return by ref-arg, test direct root, no co-await, direct resumes, uses new/delete for alloc
105138BENCHMARK (fib<no_await<stack_on_heap>>)->Name(" test/libfork/fib/heap/no_await" )->Arg(fib_test);
106139BENCHMARK (fib<no_await<stack_on_heap>>)->Name(" base/libfork/fib/heap/no_await" )->Arg(fib_base);
107140
141+ // Same as above but uses tls bump allocator
142+ BENCHMARK (fib<no_await<tls_bump>>)->Name(" test/libfork/fib/tls_bump/no_await" )->Arg(fib_test);
143+ BENCHMARK (fib<no_await<tls_bump>>)->Name(" base/libfork/fib/tls_bump/no_await" )->Arg(fib_base);
144+
145+ // Same as above but with global bump allocator
146+ BENCHMARK (fib<no_await<global_bump>>)->Name(" test/libfork/fib/global_bump/no_await" )->Arg(fib_test);
147+ BENCHMARK (fib<no_await<global_bump>>)->Name(" base/libfork/fib/global_bump/no_await" )->Arg(fib_base);
148+
149+ // TODO: no_await with segmented stack allocator?
150+
151+ // Return by ref-arg, libfork call/call with co-await, uses new/delete for alloc
108152BENCHMARK (fib<await<stack_on_heap>>)->Name(" test/libfork/fib/heap/await" )->Arg(fib_test);
109153BENCHMARK (fib<await<stack_on_heap>>)->Name(" base/libfork/fib/heap/await" )->Arg(fib_base);
110154
111- BENCHMARK (fib<no_await<fib_bump_allocator>>)->Name(" test/libfork/fib/bump_alloc/no_await" )->Arg(fib_test);
112- BENCHMARK (fib<no_await<fib_bump_allocator>>)->Name(" base/libfork/fib/bump_alloc/no_await" )->Arg(fib_base);
155+ // Same as above but uses tls bump allocator
156+ BENCHMARK (fib<await<tls_bump>>)->Name(" test/libfork/fib/tls_bump/await" )->Arg(fib_test);
157+ BENCHMARK (fib<await<tls_bump>>)->Name(" base/libfork/fib/tls_bump/await" )->Arg(fib_base);
158+
159+ // Same as above but with global bump allocator
160+ BENCHMARK (fib<await<global_bump>>)->Name(" test/libfork/fib/global_bump/await" )->Arg(fib_test);
161+ BENCHMARK (fib<await<global_bump>>)->Name(" base/libfork/fib/global_bump/await" )->Arg(fib_base);
162+
163+ // Return by value
164+ // libfork call/call with co-await
165+ BENCHMARK (fib<ret>)->Name(" test/libfork/fib/tls_bump/return" )->Arg(fib_test);
166+ BENCHMARK (fib<ret>)->Name(" base/libfork/fib/tls_bump/return" )->Arg(fib_base);
113167
114- BENCHMARK (fib<await<fib_bump_allocator>>)->Name(" test/libfork/fib/bump_alloc/await" )->Arg(fib_test);
115- BENCHMARK (fib<await<fib_bump_allocator>>)->Name(" base/libfork/fib/bump_alloc/await" )->Arg(fib_base);
168+ // Return by value
169+ // libfork call/fork (no join)
170+ // Non-polymorphic vector-backed context
171+ BENCHMARK (fib<fork_call<vector_ctx>>)->Name(" test/libfork/fib/vector_ctx" )->Arg(fib_test);
172+ BENCHMARK (fib<fork_call<vector_ctx>>)->Name(" base/libfork/fib/vector_ctx" )->Arg(fib_base);
116173
117- BENCHMARK (fib<ret<fib_bump_allocator >>)->Name(" test/libfork/fib/bump_alloc/return " )->Arg(fib_test);
118- BENCHMARK (fib<ret<fib_bump_allocator >>)->Name(" base/libfork/fib/bump_alloc/return " )->Arg(fib_base);
174+ BENCHMARK (fib<fork_call<lf::polymorphic_context >>)->Name(" test/libfork/fib/poly_vector_ctx " )->Arg(fib_test);
175+ BENCHMARK (fib<fork_call<lf::polymorphic_context >>)->Name(" base/libfork/fib/poly_vector_ctx " )->Arg(fib_base);
0 commit comments