libcopp  2.2.0
sample_benchmark_coroutine_stack_pool.cpp
Go to the documentation of this file.
1 /*
2  * sample_benchmark_coroutine_stack_pool.cpp
3  *
4  * Created on: 2017年5月09日
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 
17 // include manager header file
20 
21 #if defined(PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO) && PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO
22 # include <chrono>
23 # define CALC_CLOCK_T std::chrono::system_clock::time_point
24 # define CALC_CLOCK_NOW() std::chrono::system_clock::now()
25 # define CALC_MS_CLOCK(x) static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(x).count())
26 # define CALC_NS_AVG_CLOCK(x, y) \
27  static_cast<long long>(std::chrono::duration_cast<std::chrono::nanoseconds>(x).count() / (y ? y : 1))
28 #else
29 # define CALC_CLOCK_T clock_t
30 # define CALC_CLOCK_NOW() clock()
31 # define CALC_MS_CLOCK(x) static_cast<int>((x) / (CLOCKS_PER_SEC / 1000))
32 # define CALC_NS_AVG_CLOCK(x, y) (1000000LL * static_cast<long long>((x) / (CLOCKS_PER_SEC / 1000)) / (y ? y : 1))
33 #endif
34 
35 // === 栈内存池 ===
36 typedef copp::stack_pool<copp::allocator::default_statck_allocator> stack_pool_t;
37 stack_pool_t::ptr_t global_stack_pool;
38 int switch_count = 100;
39 
40 typedef copp::coroutine_context_container<copp::allocator::stack_allocator_pool<stack_pool_t> > my_cotoutine_t;
41 
42 // define a coroutine runner
43 static int my_runner(void *) {
44  // ... your code here ...
45  int count = switch_count; // 每个协程N次切换
46  copp::coroutine_context *self = copp::this_coroutine::get_coroutine();
47  while (count-- > 0) {
48  self->yield();
49  }
50 
51  return 1;
52 }
53 
54 int MAX_COROUTINE_NUMBER = 100000; // 协程数量
55 
56 static void benchmark_round(int index) {
57  printf("### Round: %d ###\n", index);
58 
59  time_t begin_time = time(nullptr);
60  CALC_CLOCK_T begin_clock = CALC_CLOCK_NOW();
61 
62  // create coroutines
63  my_cotoutine_t::ptr_t *co_arr = new my_cotoutine_t::ptr_t[MAX_COROUTINE_NUMBER];
64 
65  time_t end_time = time(nullptr);
66  CALC_CLOCK_T end_clock = CALC_CLOCK_NOW();
67  printf("allocate %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
68  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
69  CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));
70 
71  for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
72  copp::allocator::stack_allocator_pool<stack_pool_t> alloc(global_stack_pool);
73  co_arr[i] = my_cotoutine_t::create(my_runner, alloc);
74  if (!co_arr[i]) {
75  fprintf(stderr, "coroutine create failed, the real number is %d\n", i);
76  fprintf(stderr, "maybe sysconf [vm.max_map_count] extended?\n");
78  break;
79  }
80  }
81 
82  end_time = time(nullptr);
83  end_clock = CALC_CLOCK_NOW();
84  printf("create %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
85  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
86  CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));
87 
88  begin_time = end_time;
89  begin_clock = end_clock;
90 
91  // start a coroutine
92  for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
93  co_arr[i]->start();
94  }
95 
96  // yield & resume from runner
97  bool continue_flag = true;
98  long long real_switch_times = static_cast<long long>(0);
99 
100  while (continue_flag) {
101  continue_flag = false;
102  for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
103  if (0 == co_arr[i]->resume()) {
104  continue_flag = true;
105  ++real_switch_times;
106  }
107  }
108  }
109 
110  end_time = time(nullptr);
111  end_clock = CALC_CLOCK_NOW();
112  printf("switch %d coroutine contest %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n",
113  MAX_COROUTINE_NUMBER, real_switch_times, static_cast<int>(end_time - begin_time),
114  CALC_MS_CLOCK(end_clock - begin_clock), CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));
115 
116  begin_time = end_time;
117  begin_clock = end_clock;
118 
119  delete[] co_arr;
120 
121  end_time = time(nullptr);
122  end_clock = CALC_CLOCK_NOW();
123  printf("remove %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
124  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
125  CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));
126 }
127 
128 int main(int argc, char *argv[]) {
129  puts("###################### context coroutine (stack using stack pool) ###################");
130  printf("########## Cmd:");
131  for (int i = 0; i < argc; ++i) {
132  printf(" %s", argv[i]);
133  }
134  puts("");
135 
136  if (argc > 1) {
137  MAX_COROUTINE_NUMBER = atoi(argv[1]);
138  }
139 
140  if (argc > 2) {
141  switch_count = atoi(argv[2]);
142  }
143 
144  size_t stack_size = 16 * 1024;
145  if (argc > 3) {
146  stack_size = static_cast<size_t>(atoi(argv[3]) * 1024);
147  }
148 
149  global_stack_pool = stack_pool_t::create();
150  global_stack_pool->set_min_stack_number(static_cast<size_t>(MAX_COROUTINE_NUMBER));
151  global_stack_pool->set_stack_size(stack_size);
152 
153  for (int i = 1; i <= 5; ++i) {
154  benchmark_round(i);
155  }
156  return 0;
157 }
LIBCOPP_COPP_API coroutine_context * get_coroutine() LIBCOPP_MACRO_NOEXCEPT
get current coroutine
copp::coroutine_context_default::ptr_t * co_arr
int main(int argc, char *argv[])
static void benchmark_round(int index)
stack_pool_t::ptr_t global_stack_pool
static int my_runner(void *)
copp::stack_pool< copp::allocator::default_statck_allocator > stack_pool_t
#define CALC_NS_AVG_CLOCK(x, y)
copp::coroutine_context_container< copp::allocator::stack_allocator_pool< stack_pool_t > > my_cotoutine_t