Modules/Threading/tests/ThreadPinningTests.cpp
agent 15b18a8f1f Threading: cpu topology and thread pinning
ThreadPinning reads the sibling groups from the kernel topology and pins the
calling thread to a cpu set. It is stateless and per-thread: a caller reads the
groups, picks the cpus for a thread and pins it, so any mapping of threads to
cpus is expressible.
2026-10-27 01:16:26 +03:00

56 lines
1.5 KiB
C++

#include "ThreadPinning.hpp"
#include "UnitTest++/UnitTest++.h"
#include <algorithm>
#include <thread>
#include <vector>
using namespace tp;
namespace {
std::vector<int> sorted(std::vector<int> values) {
std::sort(values.begin(), values.end());
return values;
}
}
SUITE(ThreadPinning) {
TEST(SiblingGroupsCoverEveryAllowedCpuExactlyOnce) {
const std::vector<int> allowed = ThreadPinning::allowedCpus();
if (allowed.empty()) return;
const auto groups = ThreadPinning::siblingGroups(allowed);
std::vector<int> seen;
for (const auto& group : groups)
seen.insert(seen.end(), group.begin(), group.end());
CHECK(sorted(seen) == sorted(allowed));
}
TEST(PinningRestrictsTheCallingThread) {
const std::vector<int> allowed = ThreadPinning::allowedCpus();
const auto groups = ThreadPinning::siblingGroups(allowed);
if (groups.size() < 2) return;
ThreadPinning::pinCallingThread(groups.front());
CHECK(sorted(ThreadPinning::allowedCpus()) == sorted(groups.front()));
}
TEST(TwoThreadsCanBePinnedToDifferentGroups) {
const auto groups = ThreadPinning::siblingGroups();
if (groups.size() < 2) return;
std::vector<int> first, second;
std::thread left([&]() {
ThreadPinning::pinCallingThread(groups[0]);
first = ThreadPinning::allowedCpus();
});
std::thread right([&]() {
ThreadPinning::pinCallingThread(groups[1]);
second = ThreadPinning::allowedCpus();
});
left.join();
right.join();
CHECK(sorted(first) == sorted(groups[0]));
CHECK(sorted(second) == sorted(groups[1]));
}
}