Imported Upstream version 1.63.0
[platform/upstream/boost.git] / libs / fiber / performance / fiber / skynet_stealing.cpp
1
2 //          Copyright Oliver Kowalke 2015.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6
7 #include <algorithm>
8 #include <cassert>
9 #include <chrono>
10 #include <condition_variable>
11 #include <cstddef>
12 #include <cstdint>
13 #include <cstdlib>
14 #include <queue>
15 #include <iostream>
16 #include <memory>
17 #include <mutex>
18 #include <numeric>
19 #include <random>
20 #include <sstream>
21 #include <vector>
22
23 #include <boost/fiber/all.hpp>
24
25 #include "barrier.hpp"
26 #include "bind/bind_processor.hpp"
27
28 using clock_type = std::chrono::steady_clock;
29 using duration_type = clock_type::duration;
30 using time_point_type = clock_type::time_point;
31 using channel_type = boost::fibers::buffered_channel< std::uint64_t >;
32 using allocator_type = boost::fibers::fixedsize_stack;
33 using lock_type = std::unique_lock< std::mutex >;
34
35 static bool done = false;
36 static std::mutex mtx{};
37 static boost::fibers::condition_variable_any cnd{};
38
39 // microbenchmark
40 void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) {
41     if ( 1 == size) {
42         c.push( num);
43     } else {
44         channel_type rc{ 16 };
45         for ( std::size_t i = 0; i < div; ++i) {
46             auto sub_num = num + i * size / div;
47             boost::fibers::fiber{ boost::fibers::launch::dispatch,
48                                   std::allocator_arg, salloc,
49                                   skynet,
50                                   std::ref( salloc), std::ref( rc), sub_num, size / div, div }.detach();
51         }
52         std::uint64_t sum{ 0 };
53         for ( std::size_t i = 0; i < div; ++i) {
54             sum += rc.value_pop();
55         }
56         c.push( sum);
57     }
58 }
59
60 void thread( unsigned int max_idx, unsigned int idx, barrier * b) {
61     bind_to_processor( idx);
62     boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( max_idx, idx);
63     b->wait();
64     lock_type lk( mtx);
65     cnd.wait( lk, [](){ return done; });
66     BOOST_ASSERT( done);
67 }
68
69 int main() {
70     try {
71         unsigned int cpus = std::thread::hardware_concurrency();
72         barrier b( cpus);
73         unsigned int max_idx = cpus - 1;
74         boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( max_idx, max_idx);
75         bind_to_processor( max_idx);
76         std::size_t stack_size{ 4048 };
77         std::size_t size{ 100000 };
78         std::size_t div{ 10 };
79         std::vector< std::thread > threads;
80         for ( unsigned int idx = 0; idx < max_idx; ++idx) {
81             threads.push_back( std::thread( thread, max_idx, idx, & b) );
82         };
83         allocator_type salloc{ stack_size };
84         std::uint64_t result{ 0 };
85         duration_type duration{ duration_type::zero() };
86         channel_type rc{ 2 };
87         b.wait();
88         time_point_type start{ clock_type::now() };
89         skynet( salloc, rc, 0, size, div);
90         result = rc.value_pop();
91         duration = clock_type::now() - start;
92         std::cout << "Result: " << result << " in " << duration.count() / 1000000 << " ms" << std::endl;
93         lock_type lk( mtx);
94         done = true;
95         lk.unlock();
96         cnd.notify_all();
97         for ( std::thread & t : threads) {
98             t.join();
99         }
100         std::cout << "done." << std::endl;
101         return EXIT_SUCCESS;
102     } catch ( std::exception const& e) {
103         std::cerr << "exception: " << e.what() << std::endl;
104     } catch (...) {
105         std::cerr << "unhandled exception" << std::endl;
106     }
107         return EXIT_FAILURE;
108 }