2 // Copyright Oliver Kowalke 2017.
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 #include "boost/fiber/numa/topology.hpp"
15 #include <system_error>
18 #include <boost/assert.hpp>
20 #ifdef BOOST_HAS_ABI_HEADERS
21 # include BOOST_ABI_PREFIX
26 class procinfo_iterator
{
28 using SLPI
= SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
;
30 SLPI
* buffer_
{ nullptr };
31 SLPI
* procinfo_
{ nullptr };
35 procinfo_iterator() = default;
37 procinfo_iterator( LOGICAL_PROCESSOR_RELATIONSHIP relship
) {
38 if ( ::GetLogicalProcessorInformationEx( relship
, nullptr, & length_
) ) {
41 if ( BOOST_UNLIKELY( ERROR_INSUFFICIENT_BUFFER
!= ::GetLastError() ) ) {
42 throw std::system_error
{
43 std::error_code
{ static_cast< int >( ::GetLastError() ), std::system_category() },
44 "::GetLogicalProcessorInformation() failed" };
46 buffer_
= reinterpret_cast< SLPI
* >( LocalAlloc( LMEM_FIXED
, length_
) );
47 if ( BOOST_UNLIKELY( nullptr == buffer_
) ) {
48 throw std::bad_alloc();
50 if ( BOOST_UNLIKELY( ! ::GetLogicalProcessorInformationEx( relship
, buffer_
, & length_
) ) ) {
51 throw std::system_error
{
52 std::error_code
{ static_cast< int >( ::GetLastError() ), std::system_category() },
53 "::GetLogicalProcessorInformation() failed" };
58 procinfo_iterator
& operator++() noexcept
{
59 if ( nullptr != procinfo_
) {
60 length_
-= procinfo_
->Size
;
62 procinfo_
= reinterpret_cast< SLPI
* >( reinterpret_cast< BYTE
* >( procinfo_
) + procinfo_
->Size
);
72 procinfo_iterator
operator++( int) {
73 procinfo_iterator
tmp( * this);
78 SLPI
* operator->() noexcept
{
82 bool operator==( procinfo_iterator
const& other
) const noexcept
{
83 return other
.buffer_
== buffer_
&& other
.procinfo_
== procinfo_
&& other
.length_
== length_
;
86 bool operator!=( procinfo_iterator
const& other
) const noexcept
{
87 return ! ( * this == other
);
91 std::set
< std::uint32_t > compute_cpu_set( WORD group_id
, KAFFINITY mask
) {
92 std::set
< std::uint32_t > cpus
;
93 for ( int i
= 0; i
< sizeof( mask
) * 8; ++i
) {
94 if ( mask
& ( static_cast< KAFFINITY
>( 1) << i
) ) {
95 cpus
.insert( static_cast< std::uint32_t >( 64 * group_id
+ i
) );
107 std::vector
< node
> topology() {
108 std::vector
< node
> topo
;
110 for ( procinfo_iterator i
{ RelationNumaNode
}; i
!= e
; ++i
) {
112 n
.id
= static_cast< std::uint32_t >( i
->NumaNode
.NodeNumber
);
113 auto cpus
= compute_cpu_set( i
->NumaNode
.GroupMask
.Group
, i
->NumaNode
.GroupMask
.Mask
);
114 for ( auto cpu_id
: cpus
) {
115 n
.logical_cpus
.insert( static_cast< std::uint32_t >( cpu_id
) );
119 // fake NUMA distance
120 std::size_t size
= topo
.size();
121 for ( auto & n
: topo
) {
122 for ( std::size_t i
= 0; i
< size
; ++i
) {
123 n
.distance
.push_back( n
.id
== i
? 10 : 20);
131 #ifdef BOOST_HAS_ABI_HEADERS
132 # include BOOST_ABI_SUFFIX