libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sample_benchmark_std_couroutine_callable_create_generator.cpp
Go to the documentation of this file.
1// Copyright 2023 owent
2// std coroutine trivial callable benchmark
3
6
7#include <inttypes.h>
8#include <stdint.h>
9#include <cstdio>
10#include <cstdlib>
11#include <cstring>
12#include <ctime>
13#include <vector>
14
15#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
16
17# if defined(PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO) && PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO
18# include <chrono>
19# define CALC_CLOCK_T std::chrono::system_clock::time_point
20# define CALC_CLOCK_NOW() std::chrono::system_clock::now()
21# define CALC_MS_CLOCK(x) static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(x).count())
22# define CALC_NS_AVG_CLOCK(x, y) \
23 static_cast<long long>(std::chrono::duration_cast<std::chrono::nanoseconds>(x).count() / (y ? y : 1))
24# else
25# define CALC_CLOCK_T clock_t
26# define CALC_CLOCK_NOW() clock()
27# define CALC_MS_CLOCK(x) static_cast<int>((x) / (CLOCKS_PER_SEC / 1000))
28# define CALC_NS_AVG_CLOCK(x, y) (1000000LL * static_cast<long long>((x) / (CLOCKS_PER_SEC / 1000)) / (y ? y : 1))
29# endif
30
31using benchmark_callable_future_type = copp::callable_future<int64_t>;
32using benchmark_generator_future_type = copp::generator_future<int64_t>;
33
34std::vector<std::unique_ptr<benchmark_callable_future_type>> g_benchmark_callable_list;
35std::vector<benchmark_generator_future_type::context_pointer_type> g_benchmark_generator_list;
36
37int switch_count = 100;
38int max_task_number = 100000;
39
40benchmark_callable_future_type run_benchmark(size_t idx, int left_switch_count) {
41 int64_t result = 0;
42
43 while (left_switch_count-- >= 0) {
44 auto gen_res =
45 co_await benchmark_generator_future_type([idx](benchmark_generator_future_type::context_pointer_type ctx) {
46 g_benchmark_generator_list[idx] = std::move(ctx);
47 });
48 result += gen_res;
49 }
50
51 co_return result;
52}
53
54static void benchmark_round(int index) {
55 g_benchmark_callable_list.reserve(static_cast<size_t>(max_task_number));
56 g_benchmark_generator_list.resize(static_cast<size_t>(max_task_number), nullptr);
57
58 printf("### Round: %d ###\n", index);
59
60 time_t begin_time = time(nullptr);
61 CALC_CLOCK_T begin_clock = CALC_CLOCK_NOW();
62
63 // create coroutines callable
64 while (g_benchmark_callable_list.size() < static_cast<size_t>(max_task_number)) {
65 g_benchmark_callable_list.push_back(std::unique_ptr<benchmark_callable_future_type>(
66 new benchmark_callable_future_type(run_benchmark(g_benchmark_callable_list.size(), switch_count))));
67 }
68
69 time_t end_time = time(nullptr);
70 CALC_CLOCK_T end_clock = CALC_CLOCK_NOW();
71 printf("create %d callable(s) and generator(s), cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number,
72 static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
73 CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));
74
75 begin_time = end_time;
76 begin_clock = end_clock;
77
78 // yield & resume from runner
79 bool continue_flag = true;
80 long long real_switch_times = static_cast<long long>(0);
81 int32_t round = 0;
82
83 while (continue_flag) {
84 ++round;
85 continue_flag = false;
86 for (auto& generator_context : g_benchmark_generator_list) {
87 benchmark_generator_future_type::context_pointer_type move_context;
88 move_context.swap(generator_context);
89 if (move_context) {
90 move_context->set_value(round);
91 ++real_switch_times;
92 continue_flag = true;
93 }
94 }
95 }
96
97 end_time = time(nullptr);
98 end_clock = CALC_CLOCK_NOW();
99 printf("resume %d callable(s) and generator(s) for %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n",
100 max_task_number, real_switch_times, static_cast<int>(end_time - begin_time),
101 CALC_MS_CLOCK(end_clock - begin_clock), CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));
102
103 begin_time = end_time;
104 begin_clock = end_clock;
105
106 g_benchmark_callable_list.clear();
107 g_benchmark_generator_list.clear();
108
109 end_time = time(nullptr);
110 end_clock = CALC_CLOCK_NOW();
111 printf("remove %d callable(s), cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number,
112 static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
113 CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));
114}
115
116int main(int argc, char* argv[]) {
117 puts("###################### std callable - create generator - trivial ###################");
118 printf("########## Cmd:");
119 for (int i = 0; i < argc; ++i) {
120 printf(" %s", argv[i]);
121 }
122 puts("");
123
124 if (argc > 1) {
125 max_task_number = atoi(argv[1]);
126 }
127
128 if (argc > 2) {
129 switch_count = atoi(argv[2]);
130 }
131
132 for (int i = 1; i <= 5; ++i) {
134 }
135 return 0;
136}
137#else
138int main() {
139 puts("std coroutine is not supported by current compiler.");
140 return 0;
141}
142#endif
#define CALC_CLOCK_T
#define CALC_MS_CLOCK(x)
#define CALC_NS_AVG_CLOCK(x, y)
#define CALC_CLOCK_NOW()
static void benchmark_round(int index)