libcopp  1.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 
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14 #include <ctime>
15 #include <inttypes.h>
16 #include <stdint.h>
17 
18 // include manager header file
21 
22 #if defined(PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO) && PROJECT_LIBCOPP_SAMPLE_HAS_CHRONO
23 #include <chrono>
24 #define CALC_CLOCK_T std::chrono::system_clock::time_point
25 #define CALC_CLOCK_NOW() std::chrono::system_clock::now()
26 #define CALC_MS_CLOCK(x) static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(x).count())
27 #define CALC_NS_AVG_CLOCK(x, y) 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 // === 栈内存池 ===
38 int switch_count = 100;
39 
41 
42 // define a coroutine runner
43 static int my_runner(void *) {
44  // ... your code here ...
45  int count = switch_count; // 每个协程N次切换
46  my_cotoutine_t *addr = copp::this_coroutine::get<my_cotoutine_t>();
47 
48  while (count-- > 0) {
49  addr->yield();
50  }
51 
52  return 1;
53 }
54 
55 int MAX_COROUTINE_NUMBER = 100000; // 协程数量
56 
57 static void benchmark_round(int index) {
58  printf("### Round: %d ###\n", index);
59 
60  time_t begin_time = time(NULL);
61  CALC_CLOCK_T begin_clock = CALC_CLOCK_NOW();
62 
63  // create coroutines
65 
66  time_t end_time = time(NULL);
67  CALC_CLOCK_T end_clock = CALC_CLOCK_NOW();
68  printf("allocate %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
69  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
70  CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));
71 
72  for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
74  co_arr[i] = my_cotoutine_t::create(my_runner, alloc);
75  if (!co_arr[i]) {
76  fprintf(stderr, "coroutine create failed, the real number is %d\n", i);
77  fprintf(stderr, "maybe sysconf [vm.max_map_count] extended?\n");
78  MAX_COROUTINE_NUMBER = i;
79  break;
80  }
81  }
82 
83  end_time = time(NULL);
84  end_clock = CALC_CLOCK_NOW();
85  printf("create %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
86  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
87  CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));
88 
89  begin_time = end_time;
90  begin_clock = end_clock;
91 
92  // start a coroutine
93  for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
94  co_arr[i]->start();
95  }
96 
97  // yield & resume from runner
98  bool continue_flag = true;
99  long long real_switch_times = static_cast<long long>(0);
100 
101  while (continue_flag) {
102  continue_flag = false;
103  for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
104  if (0 == co_arr[i]->resume()) {
105  continue_flag = true;
106  ++real_switch_times;
107  }
108  }
109  }
110 
111  end_time = time(NULL);
112  end_clock = CALC_CLOCK_NOW();
113  printf("switch %d coroutine contest %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
114  real_switch_times, static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
115  CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));
116 
117  begin_time = end_time;
118  begin_clock = end_clock;
119 
120  delete[] co_arr;
121 
122  end_time = time(NULL);
123  end_clock = CALC_CLOCK_NOW();
124  printf("remove %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
125  static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
126  CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));
127 }
128 
129 int main(int argc, char *argv[]) {
130  puts("###################### context coroutine (stack using stack pool) ###################");
131  printf("########## Cmd:");
132  for (int i = 0; i < argc; ++i) {
133  printf(" %s", argv[i]);
134  }
135  puts("");
136 
137  if (argc > 1) {
138  MAX_COROUTINE_NUMBER = atoi(argv[1]);
139  }
140 
141  if (argc > 2) {
142  switch_count = atoi(argv[2]);
143  }
144 
145  size_t stack_size = 16 * 1024;
146  if (argc > 3) {
147  stack_size = static_cast<size_t>(atoi(argv[3]) * 1024);
148  }
149 
151  global_stack_pool->set_min_stack_number(static_cast<size_t>(MAX_COROUTINE_NUMBER));
152  global_stack_pool->set_stack_size(stack_size);
153 
154  for (int i = 1; i <= 5; ++i) {
155  benchmark_round(i);
156  }
157  return 0;
158 }
static void benchmark_round(int index)
static ptr_t create(const callback_t &runner, allocator_type &alloc, size_t stack_sz=0, size_t private_buffer_size=0, size_t coroutine_size=0) UTIL_CONFIG_NOEXCEPT
create and init coroutine with specify runner and specify stack size
copp::stack_pool< copp::allocator::default_statck_allocator > stack_pool_t
stack_pool_t::ptr_t global_stack_pool
static ptr_t create()
Definition: stack_pool.h:52
copp::coroutine_context_default::ptr_t * co_arr
int yield(void **priv_data=UTIL_CONFIG_NULLPTR)
yield coroutine
coroutine container contain stack context, stack allocator and runtime fcontext
copp::coroutine_context_container< copp::allocator::stack_allocator_pool< stack_pool_t > > my_cotoutine_t
#define CALC_NS_AVG_CLOCK(x, y)
memory allocator this allocator will maintain buffer using malloc/free function
static int my_runner(void *)
int main(int argc, char *argv[])
std::shared_ptr< stack_pool< TAlloc > > ptr_t
Definition: stack_pool.h:25