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