Threading: cpu topology, worker lanes and parallel for #3

Open
ilusha wants to merge 3 commits from threading into master
Owner

Base: master @ e63b7dd (rebased after #2 merged). Three primitives, no caller context — they know CPUs, queues and loops, nothing about which thread is the foreground thread.

  1. ThreadPlacement — reads sibling groups from the kernel topology, splits them into the group of a chosen cpu and the rest, and pins a thread to a cpu set. Stateless: the caller picks a cpu, takes the layout and pins its own threads.
  2. WorkerLanes — one queue per lane, one thread per lane, pause() to drain on the calling thread. An optional thread-start hook runs once per lane so a caller can pin or name it.
  3. ParallelFor — a counted loop over a fixed pool with atomic index hand-out, so the calling thread shares the work. An optional thread-start hook runs once per helper thread.
**Base:** `master` @ `e63b7dd` (rebased after #2 merged). Three primitives, no caller context — they know CPUs, queues and loops, nothing about which thread is the foreground thread. 1. **ThreadPlacement** — reads sibling groups from the kernel topology, splits them into the group of a chosen cpu and the rest, and pins a thread to a cpu set. Stateless: the caller picks a cpu, takes the layout and pins its own threads. 2. **WorkerLanes** — one queue per lane, one thread per lane, `pause()` to drain on the calling thread. An optional thread-start hook runs once per lane so a caller can pin or name it. 3. **ParallelFor** — a counted loop over a fixed pool with atomic index hand-out, so the calling thread shares the work. An optional thread-start hook runs once per helper thread.
ilusha added 3 commits 2026-10-27 01:03:51 +03:00
A new library module for the project's threading primitives. ThreadPlacement
reads the CPU topology from the kernel, keeps the calling thread's physical
core for the thread that reserved it, and spreads the remaining threads over
the other cores. It knows nothing about UI or applications: the caller decides
which thread reserves a core, and everything else is expressed as CPU groups.
WorkerLanes keeps a job queue per lane, pins each lane's thread off the
reserved core, and can pause every lane and drain the queued jobs on the
calling thread.
Threading: parallel for over a fixed worker pool
Some checks are pending
Windows / build (pull_request) Waiting to run
CMake on a single platform / build (pull_request) Waiting to run
CMake / build (pull_request) Waiting to run
a75fdc610e
ParallelFor runs a counted loop across a fixed set of worker threads created
up front, pins them off the reserved core, and hands out indices from an atomic
counter so the calling thread participates in the same loop.
agent force-pushed threading from a75fdc610e to b03e478afd 2026-10-27 01:16:55 +03:00 Compare
agent force-pushed threading from b03e478afd to df3dcbe5b1 2026-10-27 02:00:37 +03:00 Compare
agent changed title from Threading: a library module for thread placement, worker lanes and parallel for to Threading: cpu topology, worker lanes and parallel for 2026-10-27 02:00:50 +03:00
ilusha reviewed 2026-10-27 02:05:50 +03:00
@ -0,0 +1,43 @@
#pragma once
Author
Owner

r u sure there is no implementation of that in the latest c++ standard?

r u sure there is no implementation of that in the latest c++ standard?
@ -0,0 +1,21 @@
#pragma once
Author
Owner

r u sure there is no implementation of that in the latest c++ standard?

also what configurations does that interface support
can i pin n threads to i hardware thread and k threads to j hardrare thread?
that is the limit?

also name it thread pinning

r u sure there is no implementation of that in the latest c++ standard? also what configurations does that interface support can i pin n threads to i hardware thread and k threads to j hardrare thread? that is the limit? also name it thread pinning
@ -0,0 +1,219 @@
#pragma once
Author
Owner

r u sure there is no implementation of that in the latest c++ standard?

r u sure there is no implementation of that in the latest c++ standard?
agent force-pushed threading from df3dcbe5b1 to 40a3535393 2026-10-27 02:07:03 +03:00 Compare
agent reviewed 2026-10-27 02:07:07 +03:00
agent left a comment
Collaborator

Answers, and the code changed accordingly (15b18a8 instead of the placement commit; still three commits).

Is there a standard implementation?

  • Pinning — no. C++26 std::execution standardises schedulers, not affinity. std::thread::native_handle() is the only escape hatch, so sched_setaffinity / SetThreadAffinityMask stay in our hands.
  • WorkerLanes — no. Nothing in the standard gives per-lane queues with pause()/drain.
  • ParallelFor — yes, partly. std::for_each(std::execution::par, ...) exists since C++17. It gives no control over the thread count, no thread-start hook (so no pinning) and no guarantee about who takes part. That is what ParallelFor adds. Say the word if you would rather drop it and use the standard algorithms.

What configurations does pinning support? Any mapping, one thread at a time: pinCallingThread(cpus) sets the affinity of the calling thread to an arbitrary cpu set. So "n threads on cpu group i, k on group j" is expressible — each thread pins itself (or is pinned from outside via its thread-start hook). What the interface does not have is a declarative n-to-m configuration; siblingGroups() only tells you which cpus share a physical core.

Renamed to ThreadPinning, and the Layout/layoutFor split ("pinned group vs the rest") is gone — that was caller policy, not a primitive. What is left is allowedCpus(), siblingGroups(), pinCallingThread(), with a test that pins two threads to two different groups.

Answers, and the code changed accordingly (`15b18a8` instead of the placement commit; still three commits). **Is there a standard implementation?** - **Pinning — no.** C++26 `std::execution` standardises schedulers, not affinity. `std::thread::native_handle()` is the only escape hatch, so `sched_setaffinity` / `SetThreadAffinityMask` stay in our hands. - **WorkerLanes — no.** Nothing in the standard gives per-lane queues with `pause()`/drain. - **ParallelFor — yes, partly.** `std::for_each(std::execution::par, ...)` exists since C++17. It gives no control over the thread count, no thread-start hook (so no pinning) and no guarantee about who takes part. That is what `ParallelFor` adds. Say the word if you would rather drop it and use the standard algorithms. **What configurations does pinning support?** Any mapping, one thread at a time: `pinCallingThread(cpus)` sets the affinity of the calling thread to an arbitrary cpu set. So "n threads on cpu group i, k on group j" is expressible — each thread pins itself (or is pinned from outside via its thread-start hook). What the interface does *not* have is a declarative n-to-m configuration; `siblingGroups()` only tells you which cpus share a physical core. Renamed to **`ThreadPinning`**, and the `Layout`/`layoutFor` split ("pinned group vs the rest") is gone — that was caller policy, not a primitive. What is left is `allowedCpus()`, `siblingGroups()`, `pinCallingThread()`, with a test that pins two threads to two different groups.
Some checks are pending
Windows / build (pull_request) Waiting to run
CMake on a single platform / build (pull_request) Waiting to run
CMake / build (pull_request) Waiting to run
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin threading:threading
git checkout threading

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git checkout master
git merge --no-ff threading
git checkout threading
git rebase master
git checkout master
git merge --ff-only threading
git checkout threading
git rebase master
git checkout master
git merge --no-ff threading
git checkout master
git merge --squash threading
git checkout master
git merge --ff-only threading
git checkout master
git merge threading
git push origin master
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: ilusha/Modules#3
No description provided.