mirror of
https://github.com/boostorg/fiber.git
synced 2026-01-19 16:22:11 +00:00
NUMA: pin thread to CPU via std::thread::native_handle()
- in context of #148
This commit is contained in:
10
doc/numa.qbk
10
doc/numa.qbk
@@ -173,6 +173,7 @@ memory access).
|
||||
std::vector< node > topology();
|
||||
|
||||
void pin_thread( std::uint32_t);
|
||||
void pin_thread( std::uint32_t, std::thread::native_handle_type);
|
||||
|
||||
}}}
|
||||
|
||||
@@ -275,14 +276,15 @@ system (each element represents a NUMA-node).]]
|
||||
namespace fibers {
|
||||
namespace numa {
|
||||
|
||||
void pin_thread( std::uint32_t);
|
||||
void pin_thread( std::uint32_t cpu_id);
|
||||
void pin_thread( std::uint32_t cpu_id, std::thread::native_handle_type h);
|
||||
|
||||
}}}
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Pins `this thread` to the logical cpu with ID `cpu_id`, e.g.
|
||||
the operating system scheduler will not migrate the thread to another
|
||||
logical cpu.]]
|
||||
[[Effects:] [First version pins `this thread` to the logical cpu with ID `cpu_id`, e.g.
|
||||
the operating system scheduler will not migrate the thread to another logical cpu.
|
||||
The second variant pins the thread with the native ID `h` to logical cpu with ID `cpu_id`.]]
|
||||
[[Throws:] [`system_error`]]
|
||||
]
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define BOOST_FIBERS_NUMA_PIN_THREAD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
@@ -22,7 +23,10 @@ namespace fibers {
|
||||
namespace numa {
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t);
|
||||
void pin_thread( std::uint32_t, std::thread::native_handle_type);
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid);
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
@@ -24,7 +24,12 @@ namespace numa {
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid) {
|
||||
if ( BOOST_UNLIKELY( -1 == ::bindprocessor( BINDTHREAD, ::thread_self(), static_cast< cpu_t >( cpuid) ) ) ) {
|
||||
pin_thread( cpuid, ::thread_self() );
|
||||
}
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid, std::thread::native_handle_type h) {
|
||||
if ( BOOST_UNLIKELY( -1 == ::bindprocessor( BINDTHREAD, h, static_cast< cpu_t >( cpuid) ) ) ) {
|
||||
throw std::system_error(
|
||||
std::error_code( errno, std::system_category() ),
|
||||
"bindprocessor() failed");
|
||||
|
||||
@@ -10,6 +10,7 @@ extern "C" {
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/thread.h>
|
||||
}
|
||||
|
||||
#include <system_error>
|
||||
@@ -23,11 +24,16 @@ namespace fibers {
|
||||
namespace numa {
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpu_id) {
|
||||
void pin_thread( std::uint32_t cpuid) {
|
||||
pin_thread( cpuid, ::thr_self() );
|
||||
}
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid, std::thread::native_handle_type h) {
|
||||
cpuset_t mask;
|
||||
CPU_ZERO( & mask);
|
||||
CPU_SET( cpu_id, & mask);
|
||||
if ( BOOST_UNLIKELY( 0 != ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( mask), & mask) ) ) {
|
||||
CPU_SET( cpuid, & mask);
|
||||
if ( BOOST_UNLIKELY( 0 != ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, h, sizeof( mask), & mask) ) ) {
|
||||
throw std::system_error(
|
||||
std::error_code( errno, std::system_category() ),
|
||||
"::cpuset_setaffinity() failed");
|
||||
|
||||
@@ -22,11 +22,16 @@ namespace numa {
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid) {
|
||||
pin_thread( cpuid, PTHREAD_SELFTID_NP);
|
||||
}
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid, std::thread::native_handle_type h) {
|
||||
pthread_spu_t spu;
|
||||
int err = ::pthread_processor_bind_np( PTHREAD_BIND_FORCED_NP,
|
||||
& spu,
|
||||
static_cast< pthread_spu_t >( cpuid),
|
||||
PTHREAD_SELFTID_NP);
|
||||
h);
|
||||
if ( BOOST_UNLIKELY( 0 != err) )
|
||||
throw std::system_error(
|
||||
std::error_code( err, std::system_category() ),
|
||||
|
||||
@@ -23,11 +23,16 @@ namespace numa {
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid) {
|
||||
pin_thread( cpuid, ::pthread_self() );
|
||||
}
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid, std::thread::native_handle_type h) {
|
||||
cpu_set_t set;
|
||||
CPU_ZERO( & set);
|
||||
CPU_SET( cpuid, & set);
|
||||
int err = 0;
|
||||
if ( BOOST_UNLIKELY( 0 != ( err = ::pthread_setaffinity_np( ::pthread_self(), sizeof( set), & set) ) ) ) {
|
||||
if ( BOOST_UNLIKELY( 0 != ( err = ::pthread_setaffinity_np( h, sizeof( set), & set) ) ) ) {
|
||||
throw std::system_error(
|
||||
std::error_code( err, std::system_category() ),
|
||||
"pthread_setaffinity_np() failed");
|
||||
|
||||
@@ -32,6 +32,13 @@ void pin_thread( std::uint32_t) {
|
||||
"boost fiber: pin_thread() not supported" };
|
||||
}
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid, std::thread::native_handle_type h) {
|
||||
throw fiber_error{
|
||||
std::make_error_code( std::errc::function_not_supported),
|
||||
"boost fiber: pin_thread() not supported" };
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
|
||||
@@ -25,8 +25,13 @@ namespace numa {
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid) {
|
||||
pin_thread( cpuid, P_MYID);
|
||||
}
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid, std::thread::native_handle_type h) {
|
||||
if ( BOOST_UNLIKELY( -1 == ::processor_bind( P_LWPID,
|
||||
P_MYID,
|
||||
h,
|
||||
static_cast< processorid_t >( cpuid),
|
||||
0) ) ) {
|
||||
throw std::system_error(
|
||||
|
||||
@@ -23,6 +23,11 @@ namespace numa {
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid) {
|
||||
pin_thread( cpuid, ::GetCurrentThread() );
|
||||
}
|
||||
|
||||
BOOST_FIBERS_DECL
|
||||
void pin_thread( std::uint32_t cpuid, std::thread::native_handle_type h) {
|
||||
GROUP_AFFINITY affinity;
|
||||
std::memset( & affinity, 0, sizeof( affinity) );
|
||||
// compute processor group
|
||||
@@ -32,7 +37,7 @@ void pin_thread( std::uint32_t cpuid) {
|
||||
uint32_t id = cpuid % 64;
|
||||
// set the bit mask of the logical CPU
|
||||
affinity.Mask = static_cast< KAFFINITY >( 1) << id;
|
||||
if ( BOOST_UNLIKELY( 0 == ::SetThreadGroupAffinity( ::GetCurrentThread(), & affinity, nullptr) ) ) {
|
||||
if ( BOOST_UNLIKELY( 0 == ::SetThreadGroupAffinity( h, & affinity, nullptr) ) ) {
|
||||
throw std::system_error(
|
||||
std::error_code( ::GetLastError(), std::system_category() ),
|
||||
"::SetThreadiGroupAffinity() failed");
|
||||
|
||||
@@ -34,7 +34,7 @@ project boost/fiber/test
|
||||
;
|
||||
|
||||
|
||||
rule topology-impl ( properties * )
|
||||
rule numa-impl ( properties * )
|
||||
{
|
||||
local result ;
|
||||
if ( <target-os>darwin in $(properties) )
|
||||
@@ -64,9 +64,9 @@ rule native-impl ( properties * )
|
||||
|
||||
# NUMA tests
|
||||
test-suite numa :
|
||||
[ run test_topology.cpp :
|
||||
[ run test_numa.cpp :
|
||||
: :
|
||||
<conditional>@topology-impl
|
||||
<conditional>@numa-impl
|
||||
[ requires cxx11_auto_declarations
|
||||
cxx11_constexpr
|
||||
cxx11_defaulted_functions
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/array.hpp>
|
||||
@@ -15,6 +17,7 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <boost/fiber/numa/pin_thread.hpp>
|
||||
#include <boost/fiber/numa/topology.hpp>
|
||||
|
||||
void test_topology() {
|
||||
@@ -22,11 +25,29 @@ void test_topology() {
|
||||
BOOST_CHECK( ! empty);
|
||||
}
|
||||
|
||||
void test_pin_self() {
|
||||
auto topo = boost::fibers::numa::topology();
|
||||
BOOST_CHECK( ! topo.empty() );
|
||||
BOOST_CHECK( ! topo[0].logical_cpus.empty() );
|
||||
boost::fibers::numa::pin_thread( * topo[0].logical_cpus.begin() );
|
||||
}
|
||||
|
||||
void test_pin() {
|
||||
auto topo = boost::fibers::numa::topology();
|
||||
BOOST_CHECK( ! topo.empty() );
|
||||
BOOST_CHECK( ! topo[0].logical_cpus.empty() );
|
||||
std::thread t{ []{ std::this_thread::sleep_for( std::chrono::seconds( 1) ); } };
|
||||
boost::fibers::numa::pin_thread( * topo[0].logical_cpus.begin(), t.native_handle() );
|
||||
t.join();
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
|
||||
boost::unit_test::test_suite * test =
|
||||
BOOST_TEST_SUITE("Boost.Fiber: numa topology test suite");
|
||||
|
||||
test->add( BOOST_TEST_CASE( & test_topology) );
|
||||
test->add( BOOST_TEST_CASE( & test_pin_self) );
|
||||
test->add( BOOST_TEST_CASE( & test_pin) );
|
||||
|
||||
return test;
|
||||
}
|
||||
Reference in New Issue
Block a user