|
2 | 2 |
|
3 | 3 | #include <benchmark/benchmark.h>
|
4 | 4 |
|
| 5 | +#include <array> |
| 6 | +#include <cstddef> |
5 | 7 | #include <string>
|
| 8 | +#include <thread> |
6 | 9 |
|
| 10 | +// clang-format off |
7 | 11 | /**
|
8 | 12 | Results on release build with CPU scaling disabled
|
9 | 13 | c++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
|
10 | 14 |
|
11 |
| - 2025-06-13T00:17:30+03:00 |
12 |
| - Running ./tests/channel_benchmark |
13 |
| - Run on (8 X 3999.91 MHz CPU s) |
| 15 | + 2025-06-17T19:55:02+03:00 |
| 16 | + Running ./benchmarks/channel_benchmark |
| 17 | + Run on (8 X 4000.08 MHz CPU s) |
14 | 18 | CPU Caches:
|
15 | 19 | L1 Data 32 KiB (x4)
|
16 | 20 | L1 Instruction 32 KiB (x4)
|
17 | 21 | L2 Unified 256 KiB (x4)
|
18 | 22 | L3 Unified 8192 KiB (x1)
|
19 |
| - Load Average: 2.65, 1.61, 1.50 |
20 |
| - ------------------------------------------------------------------------------ |
21 |
| - Benchmark Time CPU Iterations |
22 |
| - ------------------------------------------------------------------------------ |
23 |
| - channel_with_queue_storage 42602 ns 42598 ns 16407 |
24 |
| - channel_with_vector_storage 42724 ns 42723 ns 16288 |
25 |
| - channel_with_vector_storage 51332 ns 51328 ns 11776 |
| 23 | + Load Average: 1.38, 1.22, 1.06 |
| 24 | + ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 25 | + Benchmark Time CPU Iterations |
| 26 | + ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 27 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<100000>>_mean 652607002 ns 226690848 ns 10 |
| 28 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<100000>>_median 651695229 ns 225379690 ns 10 |
| 29 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<100000>>_stddev 12253781 ns 15462972 ns 10 |
| 30 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<100000>>_cv 1.88 % 6.82 % 10 |
| 31 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<100000>>_max 672915805 ns 255534858 ns 10 |
| 32 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<100000>>_mean 974087950 ns 514260828 ns 10 |
| 33 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<100000>>_median 977160289 ns 516344216 ns 10 |
| 34 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<100000>>_stddev 18312948 ns 28280400 ns 10 |
| 35 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<100000>>_cv 1.88 % 5.50 % 10 |
| 36 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<100000>>_max 1003003285 ns 558790265 ns 10 |
| 37 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<100000>>_mean 628774895 ns 213404616 ns 10 |
| 38 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<100000>>_median 629143659 ns 215630841 ns 10 |
| 39 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<100000>>_stddev 8790540 ns 8340659 ns 10 |
| 40 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<100000>>_cv 1.40 % 3.91 % 10 |
| 41 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<100000>>_max 640584436 ns 224198673 ns 10 |
| 42 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<1000>>_mean 43353148 ns 33321779 ns 10 |
| 43 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<1000>>_median 43035735 ns 33114531 ns 10 |
| 44 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<1000>>_stddev 626857 ns 516438 ns 10 |
| 45 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<1000>>_cv 1.45 % 1.55 % 10 |
| 46 | + bench_dynamic_storage<std::string, msd::queue_storage<std::string>, string_input<1000>>_max 44420815 ns 34055142 ns 10 |
| 47 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<1000>>_mean 143175350 ns 134608661 ns 10 |
| 48 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<1000>>_median 143349862 ns 135104870 ns 10 |
| 49 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<1000>>_stddev 9874397 ns 9112605 ns 10 |
| 50 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<1000>>_cv 6.90 % 6.77 % 10 |
| 51 | + bench_dynamic_storage<std::string, msd::vector_storage<std::string>, string_input<1000>>_max 160931701 ns 149620486 ns 10 |
| 52 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<1000>>_mean 37482750 ns 36598866 ns 10 |
| 53 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<1000>>_median 37678000 ns 36697213 ns 10 |
| 54 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<1000>>_stddev 972055 ns 739164 ns 10 |
| 55 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<1000>>_cv 2.59 % 2.02 % 10 |
| 56 | + bench_static_storage<std::string, msd::array_storage<std::string, channel_capacity>, string_input<1000>>_max 38740257 ns 37767023 ns 10 |
| 57 | + bench_dynamic_storage<data, msd::queue_storage<data>, struct_input>_mean 56195102 ns 37959789 ns 10 |
| 58 | + bench_dynamic_storage<data, msd::queue_storage<data>, struct_input>_median 56222959 ns 37916027 ns 10 |
| 59 | + bench_dynamic_storage<data, msd::queue_storage<data>, struct_input>_stddev 239106 ns 192415 ns 10 |
| 60 | + bench_dynamic_storage<data, msd::queue_storage<data>, struct_input>_cv 0.43 % 0.51 % 10 |
| 61 | + bench_dynamic_storage<data, msd::queue_storage<data>, struct_input>_max 56524553 ns 38392052 ns 10 |
| 62 | + bench_dynamic_storage<data, msd::vector_storage<data>, struct_input>_mean 318745363 ns 299820882 ns 10 |
| 63 | + bench_dynamic_storage<data, msd::vector_storage<data>, struct_input>_median 333031832 ns 312967363 ns 10 |
| 64 | + bench_dynamic_storage<data, msd::vector_storage<data>, struct_input>_stddev 30118977 ns 28236407 ns 10 |
| 65 | + bench_dynamic_storage<data, msd::vector_storage<data>, struct_input>_cv 9.45 % 9.42 % 10 |
| 66 | + bench_dynamic_storage<data, msd::vector_storage<data>, struct_input>_max 343551976 ns 323198986 ns 10 |
| 67 | + bench_static_storage<data, msd::array_storage<data, channel_capacity>, struct_input>_mean 39037187 ns 32142886 ns 10 |
| 68 | + bench_static_storage<data, msd::array_storage<data, channel_capacity>, struct_input>_median 39015373 ns 32017939 ns 10 |
| 69 | + bench_static_storage<data, msd::array_storage<data, channel_capacity>, struct_input>_stddev 557539 ns 701550 ns 10 |
| 70 | + bench_static_storage<data, msd::array_storage<data, channel_capacity>, struct_input>_cv 1.43 % 2.18 % 10 |
| 71 | + bench_static_storage<data, msd::array_storage<data, channel_capacity>, struct_input>_max 40336146 ns 33191282 ns 10 |
26 | 72 | */
|
| 73 | +// clang-format on |
27 | 74 |
|
28 |
| -static void channel_with_queue_storage(benchmark::State& state) |
29 |
| -{ |
30 |
| - msd::channel<std::string, msd::queue_storage<std::string>> channel{10}; |
| 75 | +static constexpr std::size_t channel_capacity = 1024; |
| 76 | +static constexpr std::size_t number_of_inputs = 100000; |
31 | 77 |
|
32 |
| - std::string input(1000000, 'x'); |
33 |
| - std::string out{}; |
34 |
| - out.resize(input.size()); |
| 78 | +template <std::size_t Size> |
| 79 | +struct string_input { |
| 80 | + static std::string make() { return std::string(Size, 'c'); } |
| 81 | +}; |
35 | 82 |
|
36 |
| - for (auto _ : state) { |
37 |
| - benchmark::DoNotOptimize(channel << input); |
38 |
| - benchmark::DoNotOptimize(channel >> out); |
39 |
| - } |
40 |
| -} |
| 83 | +struct data { |
| 84 | + std::array<int, 1000> data{}; |
| 85 | +}; |
41 | 86 |
|
42 |
| -BENCHMARK(channel_with_queue_storage); |
| 87 | +struct struct_input { |
| 88 | + static data make() { return data{}; } |
| 89 | +}; |
43 | 90 |
|
44 |
| -static void channel_with_vector_storage(benchmark::State& state) |
| 91 | +template <typename T, typename Storage, typename Input> |
| 92 | +static void bench_dynamic_storage(benchmark::State& state) |
45 | 93 | {
|
46 |
| - msd::channel<std::string, msd::vector_storage<std::string>> channel{10}; |
47 |
| - |
48 |
| - std::string input(1000000, 'x'); |
49 |
| - std::string out{}; |
50 |
| - out.resize(input.size()); |
| 94 | + const auto input = Input::make(); |
51 | 95 |
|
52 | 96 | for (auto _ : state) {
|
53 |
| - benchmark::DoNotOptimize(channel << input); |
54 |
| - benchmark::DoNotOptimize(channel >> out); |
| 97 | + msd::channel<T, Storage> channel{channel_capacity}; |
| 98 | + |
| 99 | + std::thread producer([&] { |
| 100 | + for (std::size_t i = 0; i < number_of_inputs; ++i) { |
| 101 | + channel << input; |
| 102 | + } |
| 103 | + channel.close(); |
| 104 | + }); |
| 105 | + |
| 106 | + for (auto& value : channel) { |
| 107 | + volatile auto* do_not_optimize = &value; |
| 108 | + (void)do_not_optimize; |
| 109 | + } |
| 110 | + |
| 111 | + producer.join(); |
55 | 112 | }
|
56 | 113 | }
|
57 | 114 |
|
58 |
| -BENCHMARK(channel_with_vector_storage); |
59 |
| - |
60 |
| -static void channel_with_array_storage(benchmark::State& state) |
| 115 | +template <typename T, typename Storage, typename Input> |
| 116 | +static void bench_static_storage(benchmark::State& state) |
61 | 117 | {
|
62 |
| - msd::channel<std::string, msd::array_storage<std::string, 10>> channel{}; |
63 |
| - |
64 |
| - std::string input(1000000, 'x'); |
65 |
| - std::string out{}; |
66 |
| - out.resize(input.size()); |
| 118 | + const auto input = Input::make(); |
67 | 119 |
|
68 | 120 | for (auto _ : state) {
|
69 |
| - benchmark::DoNotOptimize(channel << input); |
70 |
| - benchmark::DoNotOptimize(channel >> out); |
| 121 | + msd::channel<T, Storage> channel{}; |
| 122 | + |
| 123 | + std::thread producer([&] { |
| 124 | + for (std::size_t i = 0; i < number_of_inputs; ++i) { |
| 125 | + channel << input; |
| 126 | + } |
| 127 | + channel.close(); |
| 128 | + }); |
| 129 | + |
| 130 | + for (auto& value : channel) { |
| 131 | + volatile auto* do_not_optimize = &value; |
| 132 | + (void)do_not_optimize; |
| 133 | + } |
| 134 | + |
| 135 | + producer.join(); |
71 | 136 | }
|
72 | 137 | }
|
73 | 138 |
|
74 |
| -BENCHMARK(channel_with_array_storage); |
| 139 | +#define BENCH(...) \ |
| 140 | + BENCHMARK_TEMPLATE(__VA_ARGS__)->ComputeStatistics("max", [](const std::vector<double>& v) { \ |
| 141 | + return *std::max_element(v.begin(), v.end()); \ |
| 142 | + }) |
| 143 | + |
| 144 | +BENCH(bench_dynamic_storage, std::string, msd::queue_storage<std::string>, string_input<100000>); |
| 145 | +BENCH(bench_dynamic_storage, std::string, msd::vector_storage<std::string>, string_input<100000>); |
| 146 | +BENCH(bench_static_storage, std::string, msd::array_storage<std::string, channel_capacity>, string_input<100000>); |
| 147 | + |
| 148 | +BENCH(bench_dynamic_storage, std::string, msd::queue_storage<std::string>, string_input<1000>); |
| 149 | +BENCH(bench_dynamic_storage, std::string, msd::vector_storage<std::string>, string_input<1000>); |
| 150 | +BENCH(bench_static_storage, std::string, msd::array_storage<std::string, channel_capacity>, string_input<1000>); |
| 151 | + |
| 152 | +BENCH(bench_dynamic_storage, data, msd::queue_storage<data>, struct_input); |
| 153 | +BENCH(bench_dynamic_storage, data, msd::vector_storage<data>, struct_input); |
| 154 | +BENCH(bench_static_storage, data, msd::array_storage<data, channel_capacity>, struct_input); |
75 | 155 |
|
76 | 156 | BENCHMARK_MAIN();
|
0 commit comments