GPU threads: block instead of spin, and stay on the GPU's NUMA node
- set_gpu_blocking_sync(): every device is put in cudaDeviceScheduleBlockingSync before its context exists, so a host thread waiting on the GPU sleeps instead of spinning on a core. On a 16M rotation run a fifth of all CPU time was that spinning; wall time unchanged within noise. Called first thing in rugnux. - enable_gpu_numa_binding(): from then on pin_gpu() (and the new pin_gpu(dev), used by the first-pass spot workers that take a card by index) also keeps the thread on the CPUs of the NUMA node the card hangs off. The node and its CPUs come from /sys (no libnuma), intersected with the process's own mask; Linux only, and nothing happens on a machine with a single node. rugnux turns it on; the broker does not. - A thread inherits its creator's affinity, so the shared ParallelFor pool would run every later pass on one socket if a pinned worker created it: its threads now reset to the mask the process started with (common/ThreadAffinity). Byte-identical output. The NUMA part is a no-op on the single-node test box and still has to be measured on a two-socket machine. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D1G8gJVAy6gp1K5Dz3NE5C
This commit is contained in:
1 parent
25ea9bf555
commit
4b1d7feebd
8 files changed
+212
-2
No files matched your search
@@ -13,6 +13,8 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "ThreadAffinity.h"
|
||||
|
||||
// Two shapes of "run this over a range on several threads", used by the analysis code. Both take the
|
||||
// worker count from the caller rather than asking the hardware, so a run that was told how many
|
||||
// threads to use keeps to it.
|
||||
@@ -58,7 +60,12 @@ namespace parallel_detail {
|
||||
const unsigned hw = std::max(1u, std::thread::hardware_concurrency());
|
||||
workers.reserve(hw - 1);
|
||||
for (unsigned i = 0; i + 1 < hw; i++) // the submitting thread takes a share too
|
||||
workers.emplace_back([this] { in_worker = true; Loop(); });
|
||||
workers.emplace_back([this] {
|
||||
// It inherited whatever CPUs the thread that first used the pool was kept to.
|
||||
RestoreThreadAffinity();
|
||||
in_worker = true;
|
||||
Loop();
|
||||
});
|
||||
}
|
||||
|
||||
~WorkerPool() {
|
||||
|
||||
Reference in new issue
Block a user