mirror of
https://github.com/boostorg/atomic.git
synced 2026-01-19 04:02:09 +00:00
Expose pause() as smt_pause().
The smt_pause() operation may be useful in spin loops to release CPU resources for use in simpling threads on SMT-capable CPUs. Compared to the previous pause() implementation, added support for PowerPC and Solaris and use isb instruction on AArch64, which seems to be used in various open source projects instead of yield.
This commit is contained in:
@@ -1410,6 +1410,24 @@ compiler to reorder code.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:smt_pause SMT Pause Hint]
|
||||
|
||||
#include <boost/atomic/smt_pause.hpp>
|
||||
|
||||
Atomic operations are often used in tight loops, also called spin loops, where the same sequence of operations is attempted repeatedly until the atomic object is successfully updated. On modern processors with [@https://en.wikipedia.org/wiki/Simultaneous_multithreading SMT] such tight loops may result in suboptimal performance as they may be utilizing CPU core resources that could otherwise be used by a sibling thread of the same core. The `smt_pause` operation that is described in this section may help in this case:
|
||||
|
||||
[table
|
||||
[[Syntax] [Description]]
|
||||
[
|
||||
[`void smt_pause()`]
|
||||
[Hint the CPU core to reallocate hardware resources to favor other sibling threads it is currently running.]
|
||||
]
|
||||
]
|
||||
|
||||
The intended use case of `smt_pause` is to call it within a spin loop, after a failed iteration, as a backoff measure. The effects of this hint are CPU architecture dependent and may vary between CPU models and manufacturers. It may also be a no-op. When not a no-op, it will typically suspend the calling therad execution for a number of CPU clock cycles, giving the sibling threads the opportunity to use the freed hardware resources to progress further and possibly allow the calling thread to succeed on the next spin loop iteration. From the operating system perspective, `smt_pause` does not block the thread.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:feature_macros Feature testing macros]
|
||||
|
||||
#include <boost/atomic/capabilities.hpp>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* Following the announcement in Boost 1.84, removed support for Windows versions older than Windows 10.
|
||||
* A note to MinGW-w64 users. Since Windows SDK headers on MinGW-w64 define `_WIN32_WINNT` to an older Windows version by default, you may need to define `_WIN32_WINNT=0x0A00` or `BOOST_USE_WINAPI_VERSION=0x0A00` when compiling Boost.Atomic and the code that uses Boost.Atomic.
|
||||
* Added support for timed waiting operations.
|
||||
* Exposed `smt_pause` operation, which can be used as a backoff measure in spin loops. Added support for PowerPC and improved support for AArch64 in `smt_pause`.
|
||||
|
||||
[heading Boost 1.87]
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* (C) Copyright 2013 Tim Blechmann
|
||||
* (C) Copyright 2013, 2020 Andrey Semashev
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_
|
||||
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_M_AMD64) || defined(_M_IX86)
|
||||
extern "C" void _mm_pause(void);
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma intrinsic(_mm_pause)
|
||||
#endif
|
||||
#elif defined(_M_ARM64) || defined(_M_ARM)
|
||||
extern "C" void __yield(void);
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma intrinsic(__yield)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
BOOST_FORCEINLINE void pause() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_M_AMD64) || defined(_M_IX86)
|
||||
_mm_pause();
|
||||
#elif defined(_M_ARM64) || defined(_M_ARM)
|
||||
__yield();
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__("pause;" : : : "memory");
|
||||
#elif (defined(__ARM_ARCH) && __ARM_ARCH >= 8) || defined(__ARM_ARCH_8A__) || defined(__aarch64__)
|
||||
__asm__ __volatile__("yield;" : : : "memory");
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#if defined(__riscv_zihintpause)
|
||||
__asm__ __volatile__("pause" : : : "memory");
|
||||
#else
|
||||
// Encoding of the pause instruction
|
||||
__asm__ __volatile__ (".4byte 0x100000F" : : : "memory");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/atomic/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <cstddef>
|
||||
#include <chrono>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/smt_pause.hpp>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#if !defined(BOOST_WINDOWS)
|
||||
#include <time.h>
|
||||
@@ -27,7 +28,6 @@
|
||||
#include <boost/atomic/detail/has_posix_clock_traits.hpp>
|
||||
#endif
|
||||
#include <boost/atomic/detail/chrono.hpp>
|
||||
#include <boost/atomic/detail/pause.hpp>
|
||||
#include <boost/atomic/detail/lock_pool.hpp>
|
||||
#include <boost/atomic/detail/wait_operations_fwd.hpp>
|
||||
#include <boost/atomic/detail/header.hpp>
|
||||
@@ -263,7 +263,7 @@ public:
|
||||
{
|
||||
for (unsigned int i = 0u; i < fast_loop_count; ++i)
|
||||
{
|
||||
atomics::detail::pause();
|
||||
atomics::smt_pause();
|
||||
new_val = base_type::load(storage, order);
|
||||
if (new_val != old_val)
|
||||
goto finish;
|
||||
@@ -304,7 +304,7 @@ private:
|
||||
goto finish;
|
||||
}
|
||||
|
||||
atomics::detail::pause();
|
||||
atomics::smt_pause();
|
||||
now = Clock::now();
|
||||
|
||||
new_val = base_type::load(storage, order);
|
||||
|
||||
102
include/boost/atomic/smt_pause.hpp
Normal file
102
include/boost/atomic/smt_pause.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* (C) Copyright 2013 Tim Blechmann
|
||||
* (C) Copyright 2013, 2020-2025 Andrey Semashev
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_SMT_PAUSE_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_SMT_PAUSE_HPP_INCLUDED_
|
||||
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#if defined(_MSC_VER)
|
||||
#include <boost/atomic/detail/ops_msvc_common.hpp>
|
||||
#endif
|
||||
#include <boost/atomic/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// (sigh, shake head) _M_ARM64EC and _M_AMD64 may be defined both
|
||||
// https://learn.microsoft.com/en-us/windows/arm/arm64ec-abi
|
||||
#if defined(_M_ARM64) || defined(_M_ARM64EC)
|
||||
extern "C" void __isb(void);
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma intrinsic(__isb)
|
||||
#endif
|
||||
#elif defined(_M_ARM) || defined(_M_ARMT)
|
||||
extern "C" void __yield(void);
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma intrinsic(__yield)
|
||||
#endif
|
||||
#elif defined(_M_AMD64) || defined(_M_IX86)
|
||||
extern "C" void _mm_pause(void);
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma intrinsic(_mm_pause)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(sun) || defined(__sun)
|
||||
// Avoid including synch.h
|
||||
extern "C" void smt_pause(void);
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
|
||||
//! The function pauses for a number of CPU cycles, potentially freeing CPU resources, allowing sibling threads to progress. May be a no-op.
|
||||
BOOST_FORCEINLINE void smt_pause() noexcept
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
|
||||
#if defined(_M_ARM64) || defined(_M_ARM64EC)
|
||||
__isb();
|
||||
#elif defined(_M_ARM) || defined(_M_ARMT)
|
||||
__yield();
|
||||
#elif defined(_M_AMD64) || defined(_M_IX86)
|
||||
_mm_pause();
|
||||
#endif
|
||||
BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__("pause" : : : "memory");
|
||||
#elif defined(__aarch64__)
|
||||
// https://github.com/rust-lang/rust/commit/c064b6560b7ce0adeb9bbf5d7dcf12b1acb0c807
|
||||
// https://web.archive.org/web/20231004132033/https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8258604
|
||||
__asm__ __volatile__("isb" : : : "memory");
|
||||
#elif (defined(__ARM_ARCH) && __ARM_ARCH >= 8) || defined(__ARM_ARCH_8A__)
|
||||
__asm__ __volatile__("yield" : : : "memory");
|
||||
#elif (defined(__POWERPC__) || defined(__PPC__))
|
||||
__asm__ __volatile__("or 27,27,27" : : : "memory"); // yield pseudo-instruction
|
||||
#elif defined(__riscv) && (__riscv_xlen == 64)
|
||||
#if defined(__riscv_zihintpause)
|
||||
__asm__ __volatile__("pause" : : : "memory");
|
||||
#else
|
||||
// Encoding of the pause instruction
|
||||
__asm__ __volatile__ (".4byte 0x100000F" : : : "memory");
|
||||
#endif
|
||||
#elif defined(sun) || defined(__sun)
|
||||
::smt_pause();
|
||||
#endif
|
||||
|
||||
#elif defined(sun) || defined(__sun)
|
||||
|
||||
::smt_pause();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/atomic/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_ATOMIC_SMT_PAUSE_HPP_INCLUDED_
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/smt_pause.hpp>
|
||||
#include <boost/atomic/capabilities.hpp>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/intptr.hpp>
|
||||
@@ -39,7 +40,6 @@
|
||||
#include <boost/atomic/detail/extra_operations.hpp>
|
||||
#include <boost/atomic/detail/fence_operations.hpp>
|
||||
#include <boost/atomic/detail/lock_pool.hpp>
|
||||
#include <boost/atomic/detail/pause.hpp>
|
||||
#include <boost/atomic/detail/once_flag.hpp>
|
||||
#include <boost/atomic/detail/type_traits/alignment_of.hpp>
|
||||
|
||||
@@ -421,7 +421,7 @@ struct lock_state
|
||||
if (BOOST_LIKELY(pthread_mutex_trylock(&m_mutex) == 0))
|
||||
return;
|
||||
|
||||
atomics::detail::pause();
|
||||
atomics::smt_pause();
|
||||
}
|
||||
|
||||
BOOST_VERIFY(pthread_mutex_lock(&m_mutex) == 0);
|
||||
@@ -581,7 +581,7 @@ struct lock_state
|
||||
return;
|
||||
}
|
||||
|
||||
atomics::detail::pause();
|
||||
atomics::smt_pause();
|
||||
}
|
||||
|
||||
lock_slow_path();
|
||||
|
||||
Reference in New Issue
Block a user