]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
b32b8144 FG |
7 | // based on https://github.com/atemerev/skynet from Alexander Temerev |
8 | ||
7c673cae FG |
9 | #include <algorithm> |
10 | #include <cassert> | |
11 | #include <chrono> | |
b32b8144 | 12 | #include <cmath> |
7c673cae FG |
13 | #include <condition_variable> |
14 | #include <cstddef> | |
15 | #include <cstdint> | |
16 | #include <cstdlib> | |
b32b8144 | 17 | #include <queue> |
7c673cae FG |
18 | #include <iostream> |
19 | #include <memory> | |
20 | #include <mutex> | |
21 | #include <numeric> | |
b32b8144 FG |
22 | #include <random> |
23 | #include <sstream> | |
7c673cae FG |
24 | #include <vector> |
25 | ||
26 | #include <boost/fiber/all.hpp> | |
b32b8144 | 27 | #include <boost/predef.h> |
7c673cae FG |
28 | |
29 | #include "barrier.hpp" | |
7c673cae | 30 | |
7c673cae FG |
31 | using clock_type = std::chrono::steady_clock; |
32 | using duration_type = clock_type::duration; | |
7c673cae | 33 | using time_point_type = clock_type::time_point; |
b32b8144 FG |
34 | using channel_type = boost::fibers::buffered_channel< std::uint64_t >; |
35 | using allocator_type = boost::fibers::fixedsize_stack; | |
36 | using lock_type = std::unique_lock< std::mutex >; | |
7c673cae FG |
37 | |
38 | static bool done = false; | |
39 | static std::mutex mtx{}; | |
40 | static boost::fibers::condition_variable_any cnd{}; | |
41 | ||
42 | // microbenchmark | |
43 | void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { | |
44 | if ( 1 == size) { | |
45 | c.push( num); | |
46 | } else { | |
b32b8144 FG |
47 | channel_type rc{ 16 }; |
48 | std::vector< boost::fibers::fiber > fibers; | |
7c673cae FG |
49 | for ( std::size_t i = 0; i < div; ++i) { |
50 | auto sub_num = num + i * size / div; | |
b32b8144 FG |
51 | fibers.emplace_back( boost::fibers::launch::dispatch, |
52 | std::allocator_arg, salloc, | |
53 | skynet, | |
54 | std::ref( salloc), std::ref( rc), sub_num, size / div, div); | |
7c673cae FG |
55 | } |
56 | std::uint64_t sum{ 0 }; | |
57 | for ( std::size_t i = 0; i < div; ++i) { | |
58 | sum += rc.value_pop(); | |
59 | } | |
60 | c.push( sum); | |
b32b8144 FG |
61 | for ( auto & f : fibers) { |
62 | f.join(); | |
63 | } | |
7c673cae FG |
64 | } |
65 | } | |
66 | ||
92f5a8d4 | 67 | void thread( std::uint32_t thread_count) { |
b32b8144 FG |
68 | // thread registers itself at work-stealing scheduler |
69 | boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); | |
7c673cae FG |
70 | lock_type lk( mtx); |
71 | cnd.wait( lk, [](){ return done; }); | |
72 | BOOST_ASSERT( done); | |
73 | } | |
74 | ||
75 | int main() { | |
76 | try { | |
b32b8144 FG |
77 | // count of logical cpus |
78 | std::uint32_t thread_count = std::thread::hardware_concurrency(); | |
b32b8144 | 79 | std::size_t size{ 1000000 }; |
7c673cae | 80 | std::size_t div{ 10 }; |
b32b8144 | 81 | allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; |
7c673cae | 82 | std::uint64_t result{ 0 }; |
b32b8144 FG |
83 | channel_type rc{ 2 }; |
84 | std::vector< std::thread > threads; | |
85 | for ( std::uint32_t i = 1 /* count main-thread */; i < thread_count; ++i) { | |
86 | // spawn thread | |
92f5a8d4 | 87 | threads.emplace_back( thread, thread_count); |
b32b8144 | 88 | } |
92f5a8d4 TL |
89 | // main-thread registers itself at work-stealing scheduler |
90 | boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); | |
7c673cae FG |
91 | time_point_type start{ clock_type::now() }; |
92 | skynet( salloc, rc, 0, size, div); | |
93 | result = rc.value_pop(); | |
b32b8144 FG |
94 | if ( 499999500000 != result) { |
95 | throw std::runtime_error("invalid result"); | |
96 | } | |
97 | auto duration = clock_type::now() - start; | |
7c673cae FG |
98 | lock_type lk( mtx); |
99 | done = true; | |
100 | lk.unlock(); | |
101 | cnd.notify_all(); | |
102 | for ( std::thread & t : threads) { | |
103 | t.join(); | |
104 | } | |
b32b8144 | 105 | std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; |
7c673cae FG |
106 | return EXIT_SUCCESS; |
107 | } catch ( std::exception const& e) { | |
108 | std::cerr << "exception: " << e.what() << std::endl; | |
109 | } catch (...) { | |
110 | std::cerr << "unhandled exception" << std::endl; | |
111 | } | |
112 | return EXIT_FAILURE; | |
113 | } |