int main(int argc, char *argv[]) {
#ifdef LIBCOPP_MACRO_SYS_POSIX
    puts("###################### context coroutine (stack using default allocator[mmap]) ###################");
#elif defined(LIBCOPP_MACRO_SYS_WIN)
    puts("###################### context coroutine (stack using default allocator[VirtualAlloc]) ###################");
#else
    puts("###################### context coroutine (stack using default allocator ###################");
#endif
    printf("########## Cmd:");
    for (int i = 0; i < argc; ++i) {
        printf(" %s", argv[i]);
    }
    puts("");

    if (argc > 1) {
        max_task_number = atoi(argv[1]);
    }

    if (argc > 2) {
        switch_count = atoi(argv[2]);
    }

    size_t stack_size = 16 * 1024;
    if (argc > 3) {
        stack_size = atoi(argv[3]) * 1024;
    }

    time_t       begin_time  = time(NULL);
    CALC_CLOCK_T begin_clock = CALC_CLOCK_NOW();

    // create coroutines
    task_arr.reserve(static_cast<size_t>(max_task_number));
    while (task_arr.size() < static_cast<size_t>(max_task_number)) {
        my_task_t::ptr_t new_task = my_task_t::create(my_task_action, stack_size);
        if (!new_task) {
            fprintf(stderr, "create coroutine task failed, real size is %d.\n", static_cast<int>(task_arr.size()));
            fprintf(stderr, "maybe sysconf [vm.max_map_count] extended.\n");
            max_task_number = static_cast<int>(task_arr.size());
            break;
        }
        task_arr.push_back(new_task);
    }

    time_t       end_time  = time(NULL);
    CALC_CLOCK_T end_clock = CALC_CLOCK_NOW();
    printf("create %d task, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number, static_cast<int>(end_time - begin_time),
           CALC_MS_CLOCK(end_clock - begin_clock), CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));

    begin_time  = end_time;
    begin_clock = end_clock;

    // start a task
    for (int i = 0; i < max_task_number; ++i) {
        task_arr[i]->start();
    }

    // yield & resume from runner
    bool      continue_flag     = true;
    long long real_switch_times = static_cast<long long>(0);

    while (continue_flag) {
        continue_flag = false;
        for (int i = 0; i < max_task_number; ++i) {
            if (false == task_arr[i]->is_completed()) {
                continue_flag = true;
                ++real_switch_times;
                task_arr[i]->resume();
            }
        }
    }

    end_time  = time(NULL);
    end_clock = CALC_CLOCK_NOW();
    printf("switch %d tasks %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number, real_switch_times,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));

    begin_time  = end_time;
    begin_clock = end_clock;

    task_arr.clear();

    end_time  = time(NULL);
    end_clock = CALC_CLOCK_NOW();
    printf("remove %d tasks, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number, static_cast<int>(end_time - begin_time),
           CALC_MS_CLOCK(end_clock - begin_clock), CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));

    return 0;
}
int                                     main(int argc, char *argv[]) {
#ifdef LIBCOPP_MACRO_SYS_POSIX
    puts("###################### context coroutine (stack using default allocator[mmap]) ###################");
#elif defined(LIBCOPP_MACRO_SYS_WIN)
    puts("###################### context coroutine (stack using default allocator[VirtualAlloc]) ###################");
#else
    puts("###################### context coroutine (stack using default allocator ###################");
#endif
    printf("########## Cmd:");
    for (int i = 0; i < argc; ++i) {
        printf(" %s", argv[i]);
    }
    puts("");

    if (argc > 1) {
        max_coroutine_number = atoi(argv[1]);
    }

    if (argc > 2) {
        switch_count = atoi(argv[2]);
    }

    size_t stack_size = 16 * 1024;
    if (argc > 3) {
        stack_size = atoi(argv[3]) * 1024;
    }

    time_t       begin_time  = time(NULL);
    CALC_CLOCK_T begin_clock = CALC_CLOCK_NOW();

    // create coroutines
    co_arr = new copp::coroutine_context_default::ptr_t[max_coroutine_number];

    time_t       end_time  = time(NULL);
    CALC_CLOCK_T end_clock = CALC_CLOCK_NOW();
    printf("allocate %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_coroutine_number,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_coroutine_number));

    // create a runner
    // bind runner to coroutine object
    for (int i = 0; i < max_coroutine_number; ++i) {
        co_arr[i] = copp::coroutine_context_default::create(my_runner, stack_size);
        if (!co_arr[i]) {
            fprintf(stderr, "coroutine create failed, the real number is %d\n", i);
            fprintf(stderr, "maybe sysconf [vm.max_map_count] extended?\n");
            max_coroutine_number = i;
            break;
        }
    }

    end_time  = time(NULL);
    end_clock = CALC_CLOCK_NOW();
    printf("create %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_coroutine_number,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_coroutine_number));

    begin_time  = end_time;
    begin_clock = end_clock;

    // start a coroutine
    for (int i = 0; i < max_coroutine_number; ++i) {
        co_arr[i]->start();
    }

    // yield & resume from runner
    bool      continue_flag     = true;
    long long real_switch_times = static_cast<long long>(0);

    while (continue_flag) {
        continue_flag = false;
        for (int i = 0; i < max_coroutine_number; ++i) {
            if (false == co_arr[i]->is_finished()) {
                continue_flag = true;
                ++real_switch_times;
                co_arr[i]->resume();
            }
        }
    }

    end_time  = time(NULL);
    end_clock = CALC_CLOCK_NOW();
    printf("switch %d coroutine contest %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_coroutine_number,
           real_switch_times, static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));

    begin_time  = end_time;
    begin_clock = end_clock;

    delete[] co_arr;

    end_time  = time(NULL);
    end_clock = CALC_CLOCK_NOW();
    printf("remove %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_coroutine_number,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_coroutine_number));

    return 0;
}
static void benchmark_round(int index) {
    printf("### Round: %d ###\n", index);

    time_t       begin_time  = time(NULL);
    CALC_CLOCK_T begin_clock = CALC_CLOCK_NOW();

    // create coroutines
    task_arr.reserve(static_cast<size_t>(max_task_number));
    while (task_arr.size() < static_cast<size_t>(max_task_number)) {
        copp::allocator::stack_allocator_pool<stack_pool_t> alloc(global_stack_pool);
        my_task_t::ptr_t                                    new_task = my_task_t::create(my_task_action, alloc, 0);
        if (!new_task) {
            fprintf(stderr, "create coroutine task failed, real size is %d.\n", static_cast<int>(task_arr.size()));
            fprintf(stderr, "maybe sysconf [vm.max_map_count] extended.\n");
            max_task_number = static_cast<int>(task_arr.size());
            break;
        } else {
            task_arr.push_back(new_task);
        }
    }

    time_t       end_time  = time(NULL);
    CALC_CLOCK_T end_clock = CALC_CLOCK_NOW();
    printf("create %d task, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number, static_cast<int>(end_time - begin_time),
           CALC_MS_CLOCK(end_clock - begin_clock), CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));

    begin_time  = end_time;
    begin_clock = end_clock;

    // start a task
    for (int i = 0; i < max_task_number; ++i) {
        task_arr[i]->start();
    }

    // yield & resume from runner
    bool      continue_flag     = true;
    long long real_switch_times = static_cast<long long>(0);

    while (continue_flag) {
        continue_flag = false;
        for (int i = 0; i < max_task_number; ++i) {
            if (false == task_arr[i]->is_completed()) {
                continue_flag = true;
                ++real_switch_times;
                task_arr[i]->resume();
            }
        }
    }

    end_time  = time(NULL);
    end_clock = CALC_CLOCK_NOW();
    printf("switch %d tasks %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number, real_switch_times,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));

    begin_time  = end_time;
    begin_clock = end_clock;

    task_arr.clear();

    end_time  = time(NULL);
    end_clock = CALC_CLOCK_NOW();
    printf("remove %d tasks, cost time: %d s, clock time: %d ms, avg: %lld ns\n", max_task_number, static_cast<int>(end_time - begin_time),
           CALC_MS_CLOCK(end_clock - begin_clock), CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number));
}
int main(int argc, char *argv[]) {
    puts("###################### context coroutine (stack using malloc/free) ###################");
    printf("########## Cmd:");
    for (int i = 0; i < argc; ++i) {
        printf(" %s", argv[i]);
    }
    puts("");

    if (argc > 1) {
        MAX_COROUTINE_NUMBER = atoi(argv[1]);
    }

    if (argc > 2) {
        switch_count = atoi(argv[2]);
    }

    size_t stack_size = 16 * 1024;
    if (argc > 3) {
        stack_size = atoi(argv[3]) * 1024;
    }

    time_t begin_time = time(NULL);
    clock_t begin_clock = clock();

    // create coroutines
    co_arr = new my_cotoutine_t[MAX_COROUTINE_NUMBER];
    runner = new my_runner[MAX_COROUTINE_NUMBER];

    time_t end_time = time(NULL);
    clock_t end_clock = clock();
    printf("allocate %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));

    // create a runner
    // bind runner to coroutine object
    for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
        co_arr[i].create(&runner[i], stack_size);
    }

    end_time = time(NULL);
    end_clock = clock();
    printf("create %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));

    begin_time = end_time;
    begin_clock = end_clock;

    // start a coroutine
    for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
        co_arr[i].start();
    }

    // yield & resume from runner
    bool continue_flag = true;
    long long real_switch_times = static_cast<long long>(0);

    while (continue_flag) {
        continue_flag = false;
        for (int i = 0; i < MAX_COROUTINE_NUMBER; ++i) {
            if (false == co_arr[i].is_finished()) {
                continue_flag = true;
                ++real_switch_times;
                co_arr[i].resume();
            }
        }
    }

    end_time = time(NULL);
    end_clock = clock();
    printf("switch %d coroutine contest %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
           real_switch_times, static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times));

    begin_time = end_time;
    begin_clock = end_clock;

    delete[] co_arr;
    delete[] runner;

    end_time = time(NULL);
    end_clock = clock();
    printf("remove %d coroutine, cost time: %d s, clock time: %d ms, avg: %lld ns\n", MAX_COROUTINE_NUMBER,
           static_cast<int>(end_time - begin_time), CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, MAX_COROUTINE_NUMBER));

    return 0;
}
int main(int argc, char* argv[]) {
    if (argc > 1) {
        max_task_number = atoi(argv[1]);
    }

    if (argc > 2) {
        switch_count = atoi(argv[2]);
    }

    if (argc > 3) {
        stack_size = atoi(argv[3]) * 1024;
    }

    time_t begin_time = time(NULL);
    clock_t begin_clock = clock();

    // create coroutines
    task_arr.reserve(static_cast<size_t>(max_task_number));
    while(task_arr.size() < static_cast<size_t>(max_task_number)) {
        task_arr.push_back(my_task_t::create(my_task_action, stack_size));
    }

    time_t end_time = time(NULL);
    clock_t end_clock = clock();
    printf("create %d task, cost time: %d s, clock time: %d ms, avg: %lld ns\n",
           max_task_number,
           static_cast<int>(end_time - begin_time),
           CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number)
          );

    begin_time = end_time;
    begin_clock = end_clock;

    // start a task
    for (int i = 0; i < max_task_number; ++ i) {
        task_arr[i]->start();
    }

    // yield & resume from runner
    bool continue_flag = true;
    long long real_switch_times = static_cast<long long>(0);

    while (continue_flag) {
        continue_flag = false;
        for (int i = 0; i < max_task_number; ++ i) {
            if (false == task_arr[i]->is_completed()) {
                continue_flag = true;
                ++ real_switch_times;
                task_arr[i]->resume();
            }
        }
    }

    end_time = time(NULL);
    end_clock = clock();
    printf("switch %d tasks %lld times, cost time: %d s, clock time: %d ms, avg: %lld ns\n",
           max_task_number,
           real_switch_times,
           static_cast<int>(end_time - begin_time),
           CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, real_switch_times)
          );

    begin_time = end_time;
    begin_clock = end_clock;

    task_arr.clear();

    end_time = time(NULL);
    end_clock = clock();
    printf("remove %d tasks, cost time: %d s, clock time: %d ms, avg: %lld ns\n",
           max_task_number,
           static_cast<int>(end_time - begin_time),
           CALC_MS_CLOCK(end_clock - begin_clock),
           CALC_NS_AVG_CLOCK(end_clock - begin_clock, max_task_number)
          );

    return 0;
}