]>
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 | ||
7 | #include <algorithm> | |
8 | #include <cassert> | |
9 | #include <chrono> | |
10 | #include <condition_variable> | |
11 | #include <cstddef> | |
12 | #include <cstdint> | |
13 | #include <cstdlib> | |
14 | #include <deque> | |
15 | #include <iostream> | |
16 | #include <memory> | |
17 | #include <mutex> | |
18 | #include <numeric> | |
19 | #include <vector> | |
20 | ||
21 | #include <boost/fiber/all.hpp> | |
22 | ||
23 | #include "barrier.hpp" | |
24 | #include "bind/bind_processor.hpp" | |
25 | ||
26 | using allocator_type = boost::fibers::fixedsize_stack; | |
27 | using channel_type = boost::fibers::unbounded_channel< std::uint64_t >; | |
28 | using clock_type = std::chrono::steady_clock; | |
29 | using duration_type = clock_type::duration; | |
30 | using lock_type = std::unique_lock< std::mutex >; | |
31 | using time_point_type = clock_type::time_point; | |
32 | ||
33 | static bool done = false; | |
34 | static std::mutex mtx{}; | |
35 | static boost::fibers::condition_variable_any cnd{}; | |
36 | ||
37 | // microbenchmark | |
38 | void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { | |
39 | if ( 1 == size) { | |
40 | c.push( num); | |
41 | } else { | |
42 | channel_type rc; | |
43 | for ( std::size_t i = 0; i < div; ++i) { | |
44 | auto sub_num = num + i * size / div; | |
45 | boost::fibers::fiber{ boost::fibers::launch::dispatch, | |
46 | std::allocator_arg, salloc, | |
47 | skynet, | |
48 | std::ref( salloc), std::ref( rc), sub_num, size / div, div }.detach(); | |
49 | } | |
50 | std::uint64_t sum{ 0 }; | |
51 | for ( std::size_t i = 0; i < div; ++i) { | |
52 | sum += rc.value_pop(); | |
53 | } | |
54 | c.push( sum); | |
55 | } | |
56 | } | |
57 | ||
58 | void thread( unsigned int i, barrier * b) { | |
59 | bind_to_processor( i); | |
60 | boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); | |
61 | b->wait(); | |
62 | lock_type lk( mtx); | |
63 | cnd.wait( lk, [](){ return done; }); | |
64 | BOOST_ASSERT( done); | |
65 | } | |
66 | ||
67 | int main() { | |
68 | try { | |
69 | boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); | |
70 | unsigned int n = std::thread::hardware_concurrency(); | |
71 | barrier b( n); | |
72 | bind_to_processor( n - 1); | |
73 | std::size_t stack_size{ 4048 }; | |
74 | std::size_t size{ 100000 }; | |
75 | std::size_t div{ 10 }; | |
76 | std::vector< std::thread > threads; | |
77 | for ( unsigned int i = 1; i < n; ++i) { | |
78 | threads.push_back( std::thread( thread, i - 1, & b) ); | |
79 | }; | |
80 | allocator_type salloc{ stack_size }; | |
81 | std::uint64_t result{ 0 }; | |
82 | duration_type duration{ duration_type::zero() }; | |
83 | channel_type rc; | |
84 | b.wait(); | |
85 | time_point_type start{ clock_type::now() }; | |
86 | skynet( salloc, rc, 0, size, div); | |
87 | result = rc.value_pop(); | |
88 | duration = clock_type::now() - start; | |
89 | std::cout << "Result: " << result << " in " << duration.count() / 1000000 << " ms" << std::endl; | |
90 | lock_type lk( mtx); | |
91 | done = true; | |
92 | lk.unlock(); | |
93 | cnd.notify_all(); | |
94 | for ( std::thread & t : threads) { | |
95 | t.join(); | |
96 | } | |
97 | std::cout << "done." << std::endl; | |
98 | return EXIT_SUCCESS; | |
99 | } catch ( std::exception const& e) { | |
100 | std::cerr << "exception: " << e.what() << std::endl; | |
101 | } catch (...) { | |
102 | std::cerr << "unhandled exception" << std::endl; | |
103 | } | |
104 | return EXIT_FAILURE; | |
105 | } |