|
NUMA++ 0.11.0
|
Namespaces | |
| namespace | ll |
| Defines lowlevel functions that should not be used directly. | |
Classes | |
| class | Bitmask |
| Generic bitmask. More... | |
| class | CpuAffinity |
| Create CPU affinity and apply to current thread. More... | |
| class | Cpumask |
| Type-safe CPU mask. More... | |
| class | DynamicScheduler |
| Normal non-realtime scheduler that use dynamic priority (nice value). More... | |
| class | HugePageResource |
| Polymorphic memory resource allocating huge pages with specified NUMA policy. More... | |
| class | HugePageSize |
Describes a huge page size and maintains the invariant that page size is an integral power of 2, compatible with mmap() expectations. More... | |
| class | IdleScheduler |
Represents SCHED_IDLE scheduler policy. More... | |
| struct | IsFlagEnum |
| Trait type that should be specialized for an enumeration to enable use of bitwise operators. More... | |
| class | LockResource |
| Lock memory allocated from upstream memory resource using specified LockFlag. More... | |
| class | MemPolicy |
| Class representing a memory policy that can be modified and used to apply to the current thread or a memory range. More... | |
| struct | Nodemask |
| Type-safe NUMA node mask. More... | |
| class | NumaPolicies |
| Combines the the available NUMA policy types in one object. More... | |
| class | PageResource |
| Polymorphic memory resource allocating full system pages with specified NUMA policy. More... | |
| class | Scheduler |
| A sum-type of all supported schedulers. More... | |
| class | ScopedMemPolicy |
| Applies memory policy to this thread at construction and reverts to previous at destruction. More... | |
| class | StaticScheduler |
| Static priority scheduler (real-time). More... | |
Typedefs | |
| using | NumaBitmaskPtr = std::unique_ptr<struct bitmask, void (*)(struct bitmask*)> |
| Lowlevel bitmask type. | |
| using | SchedulerVariant = std::variant<DynamicScheduler, StaticScheduler, IdleScheduler> |
| Variant of possible schedulers. | |
Enumerations | |
| enum class | HugePagePreset : std::size_t { HugePagePreset::Huge8k = 8 * 1024 , HugePagePreset::Huge16k = 16 * 1024 , HugePagePreset::Huge64k = 64 * 1024 , HugePagePreset::Huge256k = 256 * 1024 , HugePagePreset::Huge1M = 1 * 1024 * 1024 , HugePagePreset::Huge2M = 2 * 1024 * 1024 , HugePagePreset::Huge4M = 4 * 1024 * 1024 , HugePagePreset::Huge16M = 16 * 1024 * 1024 , HugePagePreset::Huge256M = 256 * 1024 * 1024 , HugePagePreset::Huge1G = 1ul * 1024 * 1024 * 1024 } |
| Preset huge page sizes. More... | |
| enum class | MemPolicyFlag : unsigned |
| Flag that modify the behaviour of applying a memory policy to a range of memory. | |
Functions | |||||||||||||||
| std::ostream & | FormatBitmask (std::ostream &os, bitmask const *mask, int min_bits) | ||||||||||||||
| Formats mask and inserts it to os. | |||||||||||||||
| template<class Class, class F> | |||||||||||||||
| void | ForEach (Bitmask< Class > const &bitmask, F &&f, bool value=true) | ||||||||||||||
| Invoke function for each bit in mask that matches value. | |||||||||||||||
| template<class Class> | |||||||||||||||
| std::ostream & | FormatBitmask (std::ostream &os, Bitmask< Class > const &mask, int min_bits) | ||||||||||||||
| Formats mask and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, Cpumask const &mask) | ||||||||||||||
| Formats mask and inserts it to os. | |||||||||||||||
| auto | EncodeMmapFlags (HugePageSize page_size) noexcept -> int | ||||||||||||||
Encodes page size into bit representation expected by mmap(). | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, Nodemask const &mask) | ||||||||||||||
| Formats mask and inserts it to os. | |||||||||||||||
| bool | NumaAvailable () noexcept | ||||||||||||||
| Query whether system has NUMA support. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, NumaPolicies const &policies) | ||||||||||||||
| Formats policies and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, StaticScheduler::Policy const &policy) | ||||||||||||||
| Formats policy and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, SchedulerVariant const &scheduler) | ||||||||||||||
| Formats scheduler and inserts it to os. | |||||||||||||||
| template<class Class, class F> | |||||||||||||||
| void | ForEach (Bitmask< Class > const &bitmask, F &&f, bool value=true) | ||||||||||||||
| Invoke function for each bit in mask that matches value. | |||||||||||||||
| template<class Class> | |||||||||||||||
| std::ostream & | FormatBitmask (std::ostream &os, Bitmask< Class > const &mask, int min_bits) | ||||||||||||||
| Formats mask and inserts it to os. | |||||||||||||||
| std::ostream & | FormatBitmask (std::ostream &os, bitmask const *mask, int min_bits) | ||||||||||||||
| Formats mask and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, CpuAffinity const &affinity) | ||||||||||||||
| Formats affinity and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, MemPolicy::Mode const &mode) | ||||||||||||||
| Formats mode and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, MemPolicy const &mempolicy) | ||||||||||||||
| Formats mempolicy and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, IdleScheduler const &scheduler) | ||||||||||||||
| Formats scheduler and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, StaticScheduler const &scheduler) | ||||||||||||||
| Formats scheduler and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, DynamicScheduler const &scheduler) | ||||||||||||||
| Formats scheduler and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, DynamicScheduler const &policy) | ||||||||||||||
| Formats policy and inserts it to os. | |||||||||||||||
| std::ostream & | operator<< (std::ostream &os, Scheduler const &scheduler) | ||||||||||||||
| Formats scheduler and inserts it to os. | |||||||||||||||
Bitwise operators for enabled enums | |||||||||||||||
Convenience function to compose bit flags using bitwise OR and AND operators. Example: using numapp::operator|; // Bring in numapp::operator| in this scope
MyEnum f = MyEnum::A | MyEnum::B;
f &= MyEnum::A;
MyFunc(f);
MyFunc(MyEnum::A | MyEnum::B);
| |||||||||||||||
| template<class Enum, typename = typename std::enable_if<IsFlagEnum<Enum>::value>::type> | |||||||||||||||
| constexpr Enum | operator| (Enum lhs, Enum rhs) noexcept | ||||||||||||||
| template<class Enum, typename = typename std::enable_if<IsFlagEnum<Enum>::value>::type> | |||||||||||||||
| constexpr Enum & | operator|= (Enum &lhs, Enum rhs) noexcept | ||||||||||||||
| Sets lhs with logical OR between lhs and rhs. | |||||||||||||||
| template<class Enum, typename = typename std::enable_if<IsFlagEnum<Enum>::value>::type> | |||||||||||||||
| constexpr Enum | operator& (Enum lhs, Enum rhs) noexcept | ||||||||||||||
| template<class Enum, typename = typename std::enable_if<IsFlagEnum<Enum>::value>::type> | |||||||||||||||
| constexpr Enum & | operator&= (Enum &lhs, Enum rhs) noexcept | ||||||||||||||
| Sets lhs with logical AND between lhs and rhs. | |||||||||||||||
Hardware Queries | |||||||||||||||
Query host system/hardware. | |||||||||||||||
| std::size_t | GetPageSize () noexcept | ||||||||||||||
| Fast query of system page size. | |||||||||||||||
| int | GetNumNodes () noexcept | ||||||||||||||
| Query number of configured NUMA nodes. | |||||||||||||||
| std::optional< int > | GetNodeDistance (int node1, int node2) noexcept | ||||||||||||||
| Get NUMA distance between two nodes. | |||||||||||||||
| std::optional< int > | GetNodeOfCpu (int cpu) noexcept | ||||||||||||||
| Get NUMA node of the given CPU. | |||||||||||||||
Makes a std::thread or std::jthread with provided NUMA policies | |||||||||||||||
Create a named thread with optional CPU affinity, scheduler and memory policies. Function has the following effects in this thread
Minimum application example with a #include <chrono>
#include <iostream>
#include <numapp/numa.hpp>
#include <numapp/thread.hpp>
void ThreadFunc(std::chrono::milliseconds duration) {
std::cout << "Thread affinity: " << numapp::CpuAffinity::MakeFromActive() << std::endl;
std::this_thread::sleep_for(duration);
}
int main() {
using namespace numapp;
using namespace std::chrono_literals;
if (!NumaAvailable()) {
std::cout << "NUMA not available";
return -1;
}
NumaPolicies policies;
thread.join();
}
static CpuAffinity MakeFromCpuStringAll(char const *cpustring) Create CpuAffinity from `cpustring` without considering current cpuset. Definition cpuaffinity.cpp:47 Combines the the available NUMA policy types in one object. Definition numapolicies.hpp:49 void SetCpuAffinity(std::optional< CpuAffinity > affinity) noexcept Set CPU affinity. Definition numapolicies.hpp:114 std::thread MakeThread(std::string_view thread_name, NumaPolicies const &policies, Func &&func, Args &&... args) Primary overload accepting string-view for thread_name. Definition thread.hpp:144 Definition bitmask.cpp:11 Contains declarations for numapp thread utilities. Example function that create pinned thread with local NUMA node memory policy: #include <numapp/memory.hpp>
#include <numapp/thread.hpp>
template <class F, class... Args>
auto MakePinnedThread(int cpu, std::string_view name, F&& f, Args... args) -> std::thread {
using namespace numapp;
NumaPolicies policies;
policies.SetCpuAffinity(CpuAffinity::MakeBindCpu(cpu));
auto node = GetNodeOfCpu(cpu);
if (!node.has_value()) {
throw std::invalid_argument("cpu invalid");
}
policies.SetMemPolicy(MemPolicy::MakeBindNode(*node));
return MakeThread(name, policies, std::forward<F>(f), std::forward<Args>(args)...);
}
static CpuAffinity MakeBindCpu(int cpu) Create CpuAffinity bound to the specified CPU. Definition cpuaffinity.cpp:59 static MemPolicy MakeBindNode(int node) Creates a strict policy (using MPOL_BIND) to allocate all memory to the specified node. void SetMemPolicy(std::optional< MemPolicy > policy) noexcept Set memory policy. Definition numapolicies.hpp:138 std::optional< int > GetNodeOfCpu(int cpu) noexcept Get NUMA node of the given CPU. Definition memory.cpp:53 Contains memory function declarations. Similar to first example, but uses member function instead: #include <chrono>
#include <iostream>
#include <numapp/numa.hpp>
#include <numapp/thread.hpp>
struct Example {
Example(std::chrono::milliseconds duration) : m_duration(duration) {
}
Example(Example&&) = default;
void ThreadFunc() {
std::cout << "Thread affinity: "
<< numapp::CpuAffinity::MakeFromActive() << std::endl;
std::this_thread::sleep_for(m_duration);
}
std::chrono::milliseconds m_duration;
};
int main() {
using namespace numapp;
using namespace std::chrono_literals;
if (!NumaAvailable()) {
std::cout << "NUMA not available";
return -1;
}
NumaPolicies policies;
auto thread =
MakeJthread("myThread", policies, &Example::ThreadFunc, Example{500ms});
}
| |||||||||||||||
| template<class Func, class... Args> | |||||||||||||||
| std::thread | MakeThread (std::string_view thread_name, NumaPolicies const &policies, Func &&func, Args &&... args) | ||||||||||||||
Primary overload accepting string-view for thread_name. | |||||||||||||||
| template<class Func, class... Args> | |||||||||||||||
| std::thread | MakeThread (char const *thread_name, NumaPolicies const &policies, Func &&func, Args &&... args) | ||||||||||||||
| Compatibility overload accepting null terminated C string for thread_name. | |||||||||||||||
Memory Locking | |
These functions provide the means to prevent memory from being paged to the swap area.
Locking may require additional permissions if it exceeds resource limits (- See also page section Memory Locking. | |
| enum class | LockFlag : unsigned int { LockFlag::PreFault = 0u , LockFlag::OnFault = MLOCK_ONFAULT } |
| Mutually exclusive flags that modifies behaviour of MemLock(). More... | |
| enum class | LockAllFlag : int { LockAllFlag::Current = MCL_CURRENT , LockAllFlag::Future = MCL_FUTURE , LockAllFlag::OnFault = MCL_ONFAULT } |
| Flags that are combined to modify behaviour of MemLockAll(). More... | |
| std::error_code | MemLock (void const *addr, std::size_t len, LockFlag flag) noexcept |
| Lock memory pages in the specified address range. | |
| std::error_code | MemUnlock (void const *addr, std::size_t len) noexcept |
| Unlock memory pages in the specified address range. | |
| std::error_code | MemLockAll (LockAllFlag flags) noexcept |
| Lock all memory pages as specified by provided flags. | |
| std::error_code | MemUnlockAll () noexcept |
| Unlock all locked memory in this process. | |
Apply CPU Affinity to Specific Thread | |
Applies specified policy to calling thread. | |
| std::error_code | Apply (pid_t thread, CpuAffinity const &affinity) noexcept |
| Apply policy to specified thread. | |
| std::error_code | Apply (pid_t thread, CpuAffinity const &affinity) noexcept |
| Apply policy to specified thread. | |
Allocate and free memory with specified memory policy | ||||||||||||||||||
(1) Overloads without
Example allocating with bind policy and then lock and pre-fault the newly allocated memory: #include <numapp/memory.hpp>
#include <numapp/mempolicy.hpp>
void* BindAlloc(std::size_t size, int node, std::error_code& ec) {
using namespace numapp;
MemPolicy policy = MemPolicy::MakeBindNode(node);
void* ptr = Allocate(size, policy, MemPolicyFlag::Strict, ec);
if (ec) {
return nullptr;
}
ec = MemLock(ptr, size, LockFlag::PreFault);
if (ec) {
return nullptr;
}
return ptr;
}
Class representing a memory policy that can be modified and used to apply to the current thread or a ... Definition mempolicy.hpp:174 std::error_code MemLock(void const *addr, std::size_t len, LockFlag flag) noexcept Lock memory pages in the specified address range. Definition memory.cpp:58 void * Allocate(std::size_t size, MemPolicy const &policy, std::error_code &ec) noexcept See group for details. Definition memory.cpp:87 Contains declarations for numapp::MemPolicy. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy, std::error_code &ec) noexcept | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy, MemPolicyFlag flags, std::error_code &ec) noexcept | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy) | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy, MemPolicyFlag flags) | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void | Free (void *ptr, std::size_t size, std::error_code &ec) noexcept | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void | Free (void *ptr, std::size_t size) | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy, std::error_code &ec) noexcept | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy, MemPolicyFlag flags, std::error_code &ec) noexcept | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy) | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void * | Allocate (std::size_t size, MemPolicy const &policy, MemPolicyFlag flags) | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void | Free (void *ptr, std::size_t size, std::error_code &ec) noexcept | |||||||||||||||||
| See group for details. | ||||||||||||||||||
| void | Free (void *ptr, std::size_t size) | |||||||||||||||||
| See group for details. | ||||||||||||||||||
Allocate and free huge pages | |||||||||||||||||||||
Allocation is similar to Allocate and free but with the additional argument specifying the (huge) page size. Like non-huge allocations the pages are not pre-faulted by the functions so to avoid page fault failurs it is recommended to do that before use. #include <numapp/memory.hpp>
void Example() {
// Allocate 16MiB from NUMA node 1 in 2MiB pages.
auto const size = 16 * 1024 * 1024;
// 1) AllocateHuge will allocate size, rounding up to nearest page_size
// multiple
void* ptr = numapp::AllocateHuge(size,
page_size,
numapp::MemPolicyFlag::Strict);
// 2) It is particularly important to pre-fault huge-pages as the likelihood
// for failure is higher. If page-fault would fail when memory is accessed
// the result is a segmentation fault.
// Page-fault failed; this would have caused a segmentation fault if not
// for `numapp::MemLock()`.
throw std::system_error(ec, "Page fault failed");
}
// 3) FreeHuge will free memory, rounding up to nearest page_size multiple
// as required by mmap.
numapp::FreeHuge(ptr, size, page_size);
}
void FreeHuge(void *ptr, std::size_t size, HugePageSize page_size, std::error_code &ec) noexcept Free huge pages previously allocated with AllocateHuge. Definition memory.cpp:205 void * AllocateHuge(std::size_t size, HugePageSize page_size, MemPolicy const &policy, MemPolicyFlag flags, std::error_code &ec) noexcept Non-throwing version of AllocateHuge() Definition memory.cpp:165
| |||||||||||||||||||||
| void * | AllocateHuge (std::size_t size, HugePageSize page_size, MemPolicy const &policy, MemPolicyFlag flags, std::error_code &ec) noexcept | ||||||||||||||||||||
| Non-throwing version of AllocateHuge() | |||||||||||||||||||||
| void * | AllocateHuge (std::size_t size, HugePageSize page_size, MemPolicy const &policy, MemPolicyFlag flags) | ||||||||||||||||||||
| Throwing version of AllocateHuge() | |||||||||||||||||||||
| void | FreeHuge (void *ptr, std::size_t size, HugePageSize page_size, std::error_code &ec) noexcept | ||||||||||||||||||||
| Free huge pages previously allocated with AllocateHuge. | |||||||||||||||||||||
| void | FreeHuge (void *ptr, std::size_t size, HugePageSize page_size) | ||||||||||||||||||||
Throwing version of FreeHuge(). | |||||||||||||||||||||
| void * | AllocateHuge (std::size_t size, HugePageSize page_size, MemPolicy const &policy, MemPolicyFlag flags, std::error_code &ec) noexcept | ||||||||||||||||||||
| Non-throwing version of AllocateHuge() | |||||||||||||||||||||
| void * | AllocateHuge (std::size_t size, HugePageSize page_size, MemPolicy const &policy, MemPolicyFlag flags) | ||||||||||||||||||||
| Throwing version of AllocateHuge() | |||||||||||||||||||||
Apply Memory Policy to Memory Range | |
| std::error_code | Apply (void *address, std::size_t length, MemPolicy const &policy, MemPolicyFlag flags) noexcept |
| Applies memory policy to the memory pages that spans the range [address, adress + length]. | |
| std::error_code | Apply (void *address, std::size_t length, MemPolicy const &policy, MemPolicyFlag flags) noexcept |
| Applies memory policy to the memory pages that spans the range [address, adress + length]. | |
Apply Scheduler to Specified Thread | |
Applies scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, IdleScheduler const &scheduler) noexcept |
| Apply idle scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, DynamicScheduler const &scheduler) noexcept |
| Apply dynamic scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, StaticScheduler const &scheduler) noexcept |
| Apply static scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, Scheduler const &scheduler) noexcept |
| Apply variadic scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, IdleScheduler const &scheduler) noexcept |
| Apply idle scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, DynamicScheduler const &scheduler) noexcept |
| Apply dynamic scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, StaticScheduler const &scheduler) noexcept |
| Apply static scheduler to specified thread. | |
| std::error_code | Apply (pid_t thread, Scheduler const &scheduler) noexcept |
| Apply variadic scheduler to specified thread. | |
|
nodiscardnoexcept |
Applies memory policy to the memory pages that spans the range [address, adress + length].
Read related man-page of mbind() to understand the various behaviours if memory is mapped or shared.
| address | start of address range. |
| length | length of range. |
| policy | Policy to apply. |
| flags | combination of MemPolicyFlag values that modify the behaviour. |
|
nodiscardconstexprnoexcept |
| std::ostream & numapp::operator<< | ( | std::ostream & | os, |
| NumaPolicies const & | policies ) |
Formats policies and inserts it to os.
| os | output stream to insert into. |
| policies | policy to format. |
Definition at line 36 of file numapolicies.cpp.
| std::ostream & numapp::operator<< | ( | std::ostream & | os, |
| StaticScheduler::Policy const & | policy ) |
Formats policy and inserts it to os.
| os | output stream to insert into. |
| policy | Policy to format. |