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)
7 // based on https://github.com/atemerev/skynet from Alexander Temerev
13 #include <condition_variable>
26 #include <boost/fiber/all.hpp>
27 #include <boost/predef.h>
29 #include "barrier.hpp"
31 using clock_type
= std::chrono::steady_clock
;
32 using duration_type
= clock_type::duration
;
33 using time_point_type
= clock_type::time_point
;
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
>;
38 static bool done
= false;
39 static std::mutex mtx
{};
40 static boost::fibers::condition_variable_any cnd
{};
43 std::uint64_t skynet(allocator_type
& salloc
, std::uint64_t num
, std::uint64_t size
, std::uint64_t div
) {
47 std::vector
<boost::fibers::future
<std::uint64_t> > results
;
48 results
.reserve( div
);
50 for ( std::uint64_t i
= 0; i
!= div
; ++i
) {
51 std::uint64_t sub_num
= num
+ i
* size
;
52 results
.emplace_back(boost::fibers::async(
53 boost::fibers::launch::dispatch
54 , std::allocator_arg
, salloc
56 , std::ref( salloc
), sub_num
, size
, div
));
59 std::uint64_t sum
= 0;
60 for ( auto& f
: results
)
69 void thread( std::uint32_t thread_count
) {
70 // thread registers itself at work-stealing scheduler
71 boost::fibers::use_scheduling_algorithm
< boost::fibers::algo::work_stealing
>( thread_count
);
73 cnd
.wait( lk
, [](){ return done
; });
79 // count of logical ids
80 std::uint32_t thread_count
= std::thread::hardware_concurrency();
81 std::size_t size
{ 1000000 };
82 std::size_t div
{ 10 };
83 allocator_type salloc
{ 2*allocator_type::traits_type::page_size() };
84 std::uint64_t result
{ 0 };
86 std::vector
< std::thread
> threads
;
87 for ( std::uint32_t i
= 1 /* count main-thread */; i
< thread_count
; ++i
) {
89 threads
.emplace_back( thread
, thread_count
);
91 // main-thread registers itself at work-stealing scheduler
92 boost::fibers::use_scheduling_algorithm
< boost::fibers::algo::work_stealing
>( thread_count
);
93 time_point_type start
{ clock_type::now() };
94 result
= skynet( salloc
, 0, size
, div
);
95 if ( 499999500000 != result
) {
96 throw std::runtime_error("invalid result");
98 auto duration
= clock_type::now() - start
;
103 for ( std::thread
& t
: threads
) {
106 std::cout
<< "duration: " << duration
.count() / 1000000 << " ms" << std::endl
;
108 } catch ( std::exception
const& e
) {
109 std::cerr
<< "exception: " << e
.what() << std::endl
;
111 std::cerr
<< "unhandled exception" << std::endl
;