libcopp  2.2.0
sample_benchmark_task_stack_pool.cpp
Go to the documentation of this file.
1 /*
2  * sample_benchmark_task_stack_pool.cpp
3  *
4  * Created on: 2017年5月19日
5  * Author: owent
6  *
7  * Released under the MIT license
8  */
9 
10 #include <inttypes.h>
11 #include <stdint.h>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #include <ctime>
16 #include <vector>
17 
18 // include manager header file
20 #include <libcotask/task.h>
21 
22 #ifdef LIBCOTASK_MACRO_ENABLED
23 
24 # if defined(PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO) && PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO
25 # include <chrono>
26 # define CALC_CLOCK_T std::chrono::system_clock::time_point
27 # define CALC_CLOCK_NOW() std::chrono::system_clock::now()
28 # define CALC_MS_CLOCK(x) static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(x).count())
29 # define CALC_NS_AVG_CLOCK(x, y) \
30  static_cast<long long>(std::chrono::duration_cast<std::chrono::nanoseconds>(x).count() / (y ? y : 1))
31 # else
32 # define CALC_CLOCK_T clock_t
33 # define CALC_CLOCK_NOW() clock()
34 # define CALC_MS_CLOCK(x) static_cast<int>((x) / (CLOCKS_PER_SEC / 1000))
35 # define CALC_NS_AVG_CLOCK(x, y) (1000000LL * static_cast<long long>((x) / (CLOCKS_PER_SEC / 1000)) / (y ? y : 1))
36 # endif
37 
38 // =============== 栈池对象 ===============
39 typedef copp::stack_pool<copp::allocator::default_statck_allocator> stack_pool_t;
40 stack_pool_t::ptr_t global_stack_pool;
41 // --------------- 栈池对象 ---------------
42 
43 int switch_count = 100;
44 int max_task_number = 100000; // 协程Task数量
45 
46 struct my_macro_coroutine {
47  using stack_allocator_type = copp::allocator::stack_allocator_pool<stack_pool_t>;
48  using coroutine_type = copp::coroutine_context_container<stack_allocator_type>;
49  using value_type = int;
50 };
51 
52 typedef cotask::task<my_macro_coroutine> my_task_t;
53 
54 std::vector<my_task_t::ptr_t> task_arr;
55 
56 // define a coroutine runner
57 int my_task_action(void *) {
58  // ... your code here ...
59  int count = switch_count; // 每个task地切换次数
60  cotask::impl::task_impl *self = cotask::this_task::get_task();
61  while (count-- > 0) {
62  self->yield();
63  }
64 
65  return 0;
66 }
67 
68 static void benchmark_round(int index) {
69  printf("### Round: %d ###\n", index);
70 
71  time_t begin_time = time(nullptr);
72  CALC_CLOCK_T begin_clock = CALC_CLOCK_NOW();
73 
74  // create coroutines
75  task_arr.reserve(static_cast<size_t>(max_task_number));
76  while (task_arr.size() < static_cast<size_t>(max_task_number)) {
77  copp::allocator::stack_allocator_pool<stack_pool_t> alloc(global_stack_pool);
78  my_task_t::ptr_t new_task = my_task_t::create(my_task_action, alloc, 0);
79  if (!new_task) {
80  fprintf(stderr, "create coroutine task failed, real size is %d.\n", static_cast<int>(task_arr.size()));
81  fprintf(stderr, "maybe sysconf [vm.max_map_count] extended.\n");
82  max_task_number = static_cast<int>(task_arr.size());
83  break;
84  } else {
85  task_arr.push_back(new_task);
86  }
87  }
88 
89  time_t end_time = time(nullptr);
90  CALC_CLOCK_T end_clock = CALC_CLOCK_NOW();
91  printf("create %d task, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number,
92  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
93  CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));
94 
95  begin_time = end_time;
96  begin_clock = end_clock;
97 
98  // start a task
99  for (int i = 0; i < max_task_number; ++i) {
100  task_arr[i]->start();
101  }
102 
103  // yield & resume from runner
104  bool continue_flag = true;
105  long long real_switch_times = static_cast<long long>(0);
106 
107  while (continue_flag) {
108  continue_flag = false;
109  for (int i = 0; i < max_task_number; ++i) {
110  if (false == task_arr[i]->is_completed()) {
111  continue_flag = true;
112  ++real_switch_times;
113  task_arr[i]->resume();
114  }
115  }
116  }
117 
118  end_time = time(nullptr);
119  end_clock = CALC_CLOCK_NOW();
120  printf("switch %d tasks %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number,
121  real_switch_times, static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
122  CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));
123 
124  begin_time = end_time;
125  begin_clock = end_clock;
126 
127  task_arr.clear();
128 
129  end_time = time(nullptr);
130  end_clock = CALC_CLOCK_NOW();
131  printf("remove %d tasks, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number,
132  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
133  CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));
134 }
135 
136 int main(int argc, char *argv[]) {
137  puts("###################### task (stack using stack pool) ###################");
138  printf("########## Cmd:");
139  for (int i = 0; i < argc; ++i) {
140  printf(" %s", argv[i]);
141  }
142  puts("");
143 
144  if (argc > 1) {
145  max_task_number = atoi(argv[1]);
146  }
147 
148  if (argc > 2) {
149  switch_count = atoi(argv[2]);
150  }
151 
152  size_t stack_size = 16 * 1024;
153  if (argc > 3) {
154  stack_size = static_cast<size_t>(atoi(argv[3]) * 1024);
155  }
156 
157  global_stack_pool = stack_pool_t::create();
158  global_stack_pool->set_min_stack_number(static_cast<size_t>(max_task_number));
159  global_stack_pool->set_stack_size(stack_size);
160 
161  for (int i = 1; i <= 5; ++i) {
162  benchmark_round(i);
163  }
164  return 0;
165 }
166 #else
167 int main() {
168  puts("cotask disabled.");
169  return 0;
170 }
171 
172 #endif
LIBCOPP_COTASK_API impl::task_impl * get_task() LIBCOPP_MACRO_NOEXCEPT
get current running task
Definition: this_task.cpp:9
std::shared_ptr< cli::cmd_option_value > value_type
Definition: cmd_option.h:50
#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)
stack_pool_t::ptr_t global_stack_pool
copp::stack_pool< copp::allocator::default_statck_allocator > stack_pool_t
cotask::task my_task_t