]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/leaf/benchmark/deep_stack_other.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / leaf / benchmark / deep_stack_other.cpp
CommitLineData
1e59de90 1// Copyright 2018-2022 Emil Dotchevski and Reverge Studios, Inc.
20effc67
TL
2
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6// See benchmark.md
7
8#ifndef BENCHMARK_WHAT
9# define BENCHMARK_WHAT 0
10#endif
11
12#if BENCHMARK_WHAT == 0
13
14# ifndef TL_EXPECTED_HPP
15# include "tl/expected.hpp"
16# endif
17# define BENCHMARK_SUCCESS(e) e
18# define BENCHMARK_FAILURE(e) tl::make_unexpected(e)
19# define BENCHMARK_TRY(v,r)\
20 auto && _r_##v = r;\
21 if( !_r_##v )\
22 return BENCHMARK_FAILURE(_r_##v.error());\
23 auto && v = _r_##v.value()
24
25#else
26
27# include <boost/outcome/std_outcome.hpp>
28# include <boost/outcome/try.hpp>
29# define BENCHMARK_SUCCESS(e) boost::outcome_v2::success(e)
30# define BENCHMARK_FAILURE(e) boost::outcome_v2::failure(e)
31# define BENCHMARK_TRY BOOST_OUTCOME_TRY
32# ifndef BOOST_NO_EXCEPTIONS
33# error Please disable exception handling.
34# endif
35
36#endif
37
38#ifdef _MSC_VER
39# define NOINLINE __declspec(noinline)
40# define ALWAYS_INLINE __forceinline
41#else
42# define NOINLINE __attribute__((noinline))
43# define ALWAYS_INLINE __attribute__((always_inline)) inline
44#endif
45
46#include <cstring>
47#include <cstdlib>
48#include <cassert>
49#include <chrono>
50#include <iostream>
51#include <fstream>
52#include <iomanip>
53#include <numeric>
54#include <algorithm>
55#include <system_error>
56#include <array>
57
58namespace boost
59{
60 void throw_exception( std::exception const & e )
61 {
62 std::cerr << "Terminating due to a C++ exception under BOOST_NO_EXCEPTIONS: " << e.what();
63 std::terminate();
64 }
65
66 struct source_location;
67 void throw_exception( std::exception const & e, boost::source_location const & )
68 {
69 throw_exception(e);
70 }
71}
72
73//////////////////////////////////////
74
75#if BENCHMARK_WHAT == 0 // tl::expected
76
77# define USING_RESULT_TYPE "tl::expected<T, E>"
78
79 template <class T, class E>
80 using result = tl::expected<T, E>;
81
82#elif BENCHMARK_WHAT == 1 // outcome::result
83
84# define USING_RESULT_TYPE "outcome::result<T, E>"
85
86 template <class T, class E>
87 using result = boost::outcome_v2::std_result<T, E, boost::outcome_v2::policy::terminate>;
88
89#elif BENCHMARK_WHAT == 2 // outcome::outcome
90
91# define USING_RESULT_TYPE "outcome::outcome<T, E>"
92
93 template <class T, class E>
94 using result = boost::outcome_v2::std_outcome<T, E>;
95
96#else
97# error Benchmark what?
98#endif
99
100//////////////////////////////////////
101
102enum class e_error_code
103{
104 ec0, ec1, ec2, ec3
105};
106
107struct e_system_error
108{
109 int value;
110 std::string what;
111};
112
113struct e_heavy_payload
114{
115 std::array<char, 4096> value;
116};
117
118template <class E>
119E make_error() noexcept;
120
121template <>
122inline e_error_code make_error<e_error_code>() noexcept
123{
124 switch(std::rand()%4)
125 {
126 default: return e_error_code::ec0;
127 case 1: return e_error_code::ec1;
128 case 2: return e_error_code::ec2;
129 case 3: return e_error_code::ec3;
130 }
131}
132
133template <>
134inline std::error_code make_error<std::error_code>() noexcept
135{
136 return std::error_code(std::rand(), std::system_category());
137}
138
139template <>
140inline e_system_error make_error<e_system_error>() noexcept
141{
142 return { std::rand(), std::string(std::rand()%32, ' ') };
143}
144
145template <>
146inline e_heavy_payload make_error<e_heavy_payload>() noexcept
147{
148 e_heavy_payload e;
149 std::fill(e.value.begin(), e.value.end(), std::rand());
150 return e;
151}
152
153inline bool should_fail( int failure_rate ) noexcept
154{
155 assert(failure_rate>=0);
156 assert(failure_rate<=100);
157 return (std::rand()%100) < failure_rate;
158}
159
160inline int handle_error( e_error_code e ) noexcept
161{
162 return int(e);
163}
164
165inline int handle_error( std::error_code const & e ) noexcept
166{
167 return e.value();
168}
169
170inline int handle_error( e_system_error const & e ) noexcept
171{
172 return e.value + e.what.size();
173}
174
175inline int handle_error( e_heavy_payload const & e ) noexcept
176{
177 return std::accumulate(e.value.begin(), e.value.end(), 0);
178}
179
180//////////////////////////////////////
181
182// This is used to change the "success" type at each level.
183// Generally, functions return values of different types.
184template <int N, class E, bool Odd = N%2>
185struct select_result_type;
186
187template <int N, class E>
188struct select_result_type<N, E, true>
189{
190 using type = result<int, E>;
191};
192
193template <int N, class E>
194struct select_result_type<N, E, false>
195{
196 using type = result<float, E>;
197};
198
199template <int N, class E>
200using select_result_t = typename select_result_type<N, E>::type;
201
202//////////////////////////////////////
203
204template <int N, class E>
205struct benchmark
206{
207 using e_type = E;
208
209 NOINLINE static select_result_t<N, E> f( int failure_rate ) noexcept
210 {
211 BENCHMARK_TRY(x, (benchmark<N-1, E>::f(failure_rate)));
212 return BENCHMARK_SUCCESS(x+1);
213 }
214};
215
216template <class E>
217struct benchmark<1, E>
218{
219 using e_type = E;
220
221 NOINLINE static select_result_t<1, E> f( int failure_rate ) noexcept
222 {
223 if( should_fail(failure_rate) )
224 return BENCHMARK_FAILURE(make_error<E>());
225 else
226 return BENCHMARK_SUCCESS(std::rand());
227 }
228};
229
230//////////////////////////////////////
231
232template <class Benchmark>
233NOINLINE int runner( int failure_rate ) noexcept
234{
235 if( auto r = Benchmark::f(failure_rate) )
236 return r.value();
237 else
238 return handle_error(r.error());
239}
240
241//////////////////////////////////////
242
243std::fstream append_csv()
244{
245 if( FILE * f = fopen("benchmark.csv","rb") )
246 {
247 fclose(f);
248 return std::fstream("benchmark.csv", std::fstream::out | std::fstream::app);
249 }
250 else
251 {
252 std::fstream fs("benchmark.csv", std::fstream::out | std::fstream::app);
253 fs << "\"Result Type\",2%,98%\n";
254 return fs;
255 }
256}
257
258template <class F>
259int print_elapsed_time( int iteration_count, F && f )
260{
261 auto start = std::chrono::steady_clock::now();
262 int val = 0;
263 for( int i = 0; i!=iteration_count; ++i )
264 val += std::forward<F>(f)();
265 auto stop = std::chrono::steady_clock::now();
266 int elapsed = std::chrono::duration_cast<std::chrono::microseconds>(stop-start).count();
267 std::cout << std::right << std::setw(9) << elapsed;
268 append_csv() << ',' << elapsed;
269 return val;
270}
271
272//////////////////////////////////////
273
274template <int Depth, class E>
275int benchmark_type( char const * type_name, int iteration_count )
276{
277 int x=0;
278 append_csv() << "\"" USING_RESULT_TYPE "\"";
279 std::cout << '\n' << std::left << std::setw(16) << type_name << '|';
280 std::srand(0);
281 x += print_elapsed_time( iteration_count, [] { return runner<benchmark<Depth, E>>(2); } );
282 std::cout << " |";
283 std::srand(0);
284 x += print_elapsed_time( iteration_count, [] { return runner<benchmark<Depth, E>>(98); } );
285 append_csv() << '\n';
286 return x;
287}
288
289//////////////////////////////////////
290
291int main()
292{
293 int const depth = 10;
294 int const iteration_count = 10000000;
295 std::cout <<
296 iteration_count << " iterations, call depth " << depth << ", sizeof(e_heavy_payload) = " << sizeof(e_heavy_payload) << "\n"
297 USING_RESULT_TYPE "\n"
298 "Error type | 2% (μs) | 98% (μs)\n"
299 "----------------|----------|---------";
300 int r = 0;
301 r += benchmark_type<depth, e_error_code>("e_error_code", iteration_count);
302 r += benchmark_type<depth, std::error_code>("std::error_code", iteration_count);
303 r += benchmark_type<depth, e_system_error>("e_system_error", iteration_count);
304 r += benchmark_type<depth, e_heavy_payload>("e_heavy_payload", iteration_count);
305 std::cout << '\n';
306 // std::cout << std::rand() << '\n';
307 return r;
308}