Skip to content

ForkUnion v3

v2.0.0 Breaking

This release includes 2 breaking changes for platform teams planning a safe upgrade.

✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

arm atomics compare-and-swap concurrency memory-model mpi
+9 more
multithreading numa openmp parallel-computing parallel-stl parallelism rayon thread-pool threadpool

Affected surfaces

breaking_upgrade

Summary

AI summary

Broad release touches Patch, Minor, Add, and Fix.

Full changelog

Much of the new functionality would require tuning, but the ground work for NUMA-aware efficient simultaneous multithreading in C++, C, and Rust on Linux is here 🥳

Breaking Changes

The default thread-pool class now splits its broadcasting logic into the actual "broadcast" and a "join". It also adds support for "exclusive spawns" when the current thread is not collaborating with the $N$ workers on a given task. It allows more fine-grained control, with one thread simultaneously participating in one pool and managing others.

Moreover, now the library supports "mood swings". By default, it's ready to grind_k. However, if you want to consume fewer resources and don't anticipate any additional work for a few milliseconds, consider marking it as lazy_k. It will negatively affect the latency of your next call.

NUMA Support On Linux

On Linux, several new core classes are available, powered by two optional dependencies: libnuma and pthreads. The first helps us relate colocated CPU cores and their associated memory banks, and the latter facilitates pinning, naming, and scheduling logical execution threads.

  • linux_numa_allocator - a stateful allocator tied to a particular NUMA node,
  • linux_colocated_pool - a thread pool with all threads running on the same NUMA node,
  • linux_distributed_pool - a thread-pool spanning & balancing many colocated pools.

The allocator can and should be used with the new C++23-like but backward-compatible allocate_at_least interface:

fu::linux_numa_allocator<int> allocator(1, 1024*1024*1024); // node_id=1, page_size=1GB
auto [ptr, count] = allocator.allocate_at_least(256*1024*1024); // 256M = 1GB of integers

Huge Pages Functionality

To further reduce the memory access latency for user-space applications, one can update the "Huge Page" settings of the Operating System for a more coarse-grained virtual address range allocation. Those "virtual" addresses need to be mapped to "physical" ones, and to accelerate operations, the CPU maintains a small cache known as the Translation Lookaside Buffer (TLB). The fewer addresses it needs to map, the more likely it is to stay relevant, and global memory accesses - are avoided.

Linux typically supports optional 2 MB and 1 GB pages (512 times and ~260,000 times larger than the standard 4 KB pages), thus allowing us to reduce the TLB load by 5 orders of magnitude. It even comes with a HugeTLBfs library for querying some of those settings, but linking to it isn't trivial, and the functionality is minimal. So instead, Fork Union now directly queries the /sysfs and allows overwriting it if the application is granted sufficient permissions.

New Function on x86, Arm, and RISC-V

Beyond the basic std::this_thread::yield(), the library now leverages architecture-specific instructions for more efficient busy-waiting:

  • x86_pause_t - uses the PAUSE instruction for better SMT performance during spin-waits.
  • x86_tpause_t - employs the newer TPAUSE instruction for timed microsecond-precision waits, transitioning the CPU into the C0.2 power-saving state.
  • arm64_yield_t - utilizes the YIELD hint instruction for better power efficiency.
  • arm64_wfet_t - leverages "Wait For Event Timed" WFET for event-driven sleeping with precise timeout control.
  • risc5_pause_t - uses the Zihintpause extension's PAUSE instruction for efficient spin-loop hints.

Similar to SimSIMD and StringZilla, the library precompiles all relevant binaries and selects the best-supported variant at runtime. You can query supported features and log them with the provided functionality in C++:

fu::capabilities_t cpu_caps = fu::cpu_capabilities(); // Depends mostly on the CPU model
fu::capabilities_t ram_caps = fu::ram_capabilities(); // Depends mostly on the OS settings
bool has_waitpkg = cpu_caps & fu::capability_x86_tpause_k; // Check for something specific
fu::log_capabilities_t {}(cpu_caps | ram_caps, colors); // Print to console
fu::log_numa_topology_t {}(numa_topology, colors); // Print the entire topology

New C Library

To avoid reimplementing all this logic in every programming language, a stable C API for core functionality is provided, covering both safe and unsafe operations — perfect for creating higher-level wrappers and parallel runtimes for other programming languages, such as Rust, Python, or Java.


Major

  • Break: Drop unsafe_for_n* APIs (3a168b3)
  • Break: Exclusive spawn, unsafe APIs (287502f)

Minor

  • Add: named_spawn for Rust (61cecb5)
  • Add: Missing metadata methods in Rust (951e216)
  • Add: unique_padded_buffer to manage padded allocations (b93ffff)
  • Add: Capabilities logging (afe96f5)
  • Add: Shared library logic (4a1608f)
  • Add: APIs to check the library version (e0e156c)
  • Add: Logging CPU details (b976cab)
  • Add: ram_page_settings::try_change (9d8c6e5)
  • Add: Store numa_node::socket_id (ebdd4b6)
  • Add: Fetching cpu_capabilities() (76c5618)
  • Add: WFET variant for Arm64 (c65a9b9)
  • Add: Draft C library (ac19713)
  • Add: Tests for helpers (04f98f8)
  • Add: Co-prime permutation ranges (a5be78f)
  • Add: numa_topology move & copy-like funcs (89556c3)
  • Add: invoke_distributed_for_slices draft (d659280)
  • Add: unsafe_for_n APIs (cb334c4)
  • Add: NUMA-aware N-Body benchmarks (51c1e9e)
  • Add: QoS levels and allocation_result (7eaab59)
  • Add: Draft new NUMA design (ec090cb)
  • Add: Draft C API (2906295)
  • Add: Draft numa_thread_pool (150220a)
  • Add: Platform-specific yields (81f0812)
  • Add: NUMA allocator (291f3eb)
  • Add: Sleeping mood (8759a08)
  • Add: C++ 20 concepts (e6d62aa)
  • Add: Draft exclusive spawning (a1eb5b9)

Patch

  • Improve: Allow naming pools in C (751cbe5)
  • Docs: Add Rust docs (0386b7d)
  • Fix: Rust bindings (b3464c5)
  • Fix: Non-NUMA C builds metadata APIs (339464a)
  • Improve: Check every HP size for NUMA allocs (275b18d)
  • Fix: Compilation issues (4fd324d)
  • Improve: Redo the Rust lib as a binding (dd4671f)
  • Docs: Naming HW-specific "yielders" (60bce68)
  • Improve: Avoid HugeTLBfs (c496dfe)
  • Fix: colocated_thread_t explicit construction (1b8568c)
  • Docs: Document the C 99 API (8655753)
  • Improve: Propagate colocated_thread (be060aa)
  • Fix: Missing <cstdio> include (eca3f5d)
  • Make: Pre-compile the C library (76c22a1)
  • Improve: New "arch" detection macros (4abd1b6)
  • Fix: Working TPAUSE implementation (662b74d)
  • Make: Disable TSan to avoid stalls on NUMA machines (c5f49e5)
  • Fix: Missing shift to thread-local range (e1d7eac)
  • Fix: Using sized CPU_SET operations (00b56c8)
  • Fix Resetting counters between distributed dynamic runs (432608a)
  • Fix: Compiling distributed pools (5d8a597)
  • Make: Simpler HugeTLB-FS lookups (25874c9)
  • Improve: Separate UMA colocation & NUMA distributed tests (2000849)
  • Fix: Thread ID offset for colocated_pool (240a3f2)
  • Fix: Require passing callbacks by reference (cae247a)
  • Docs: New distributed pool API draft (13d7d2a)
  • Docs: HugeTLB & NUMA deps (54542fa)
  • Fix: Passing compilation & non-NUMA tests (d639085)
  • Improve: Move unsafe_broadcast call into "joiner" (881eb54)
  • Improve: Locate "joiner" lifetime issue (e47d37c)
  • Make: Include missing HugeTLB deps (00c4a5c)
  • Fix: Switch from fu:: global funcs to members (0e9036f)
  • Improve: Print RAM page settings (0ae1bcc)
  • Improve: Better requires constraints (783894c)
  • Improve: Enforce atomics align in for_n_dynamic (2a19ea8)
  • Improve: Move main-thread loop into join (e79579b)
  • Make: Drop C++11 compatibility (7f1a52a)
  • Improve: Return for_n joins (e4d8901)
  • Improve: Minimalistic C interface (c05dc88)
  • Docs: Draft NUMA design (e7646ad)
  • Improve: Addressing global symbols (6e259e5)
  • Fix: Reset main thread affinity (91e1b3b)
  • Improve: Instantiate the templates (0c0ab7a)
  • Make: Disable 128-byte arg ABI warning (d1539a3)
  • Improve: Extend tests to NUMA pools (55003ba)
  • Fix: Partial initialization failure paths (0df0011)
  • Fix: Loading with release semantics (0313ee7)
  • Fix: Extend lifetime of joins (996925c)
  • Fix: Sleeping logic in the default pool (0602965)
  • Fix: Compilation errors (90c8df1)
  • Fix: Passing thread ID to workers (d98ca88)
  • Improve: Freeze 128-byte alignment (8ad5f70)
  • Make: Link & set FU_ENABLE_NUMA from CMake (b6dc5a3)
  • ImprovE: Log NUMA topology in tests (6444972)

Breaking Changes

  • Drop `unsafe_for_n*` APIs
  • Exclusive spawn, unsafe APIs

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track ForkUnion v3

Get notified when new releases ship.

Sign up free

About ForkUnion v3

All releases →

Related context

Earlier breaking changes

  • v3.0.0 Introduces generation tokens for non‑blocking multi‑pool coordination
  • v3.0.0 Splits topology into separate compute and memory domains
  • v3.0.0 Makes `RoundRobinVec` bulk operations allocation‑free and sound
  • v3.0.0 Layers capability macros and splits the umbrella header file
  • v3.0.0 Removes all back‑compatibility shims

Beta — feedback welcome: [email protected]