mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
fix(job-manager): wake runnable work before a worker waits
This commit is contained in:
1 parent
fc8f03594d
commit
dca749aaa0
4 files changed
+67
-4
No files matched your search
@@ -19,7 +19,7 @@ if(BUILD_TESTING)
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests)
|
||||
configure_windows_unwind(job_manager_reference)
|
||||
endif()
|
||||
foreach(testCase IN ITEMS memory validation dispatch ordering nested limits node_pool priority shutdown worker_policy worker_wake worker_count worker_spin)
|
||||
foreach(testCase IN ITEMS memory validation dispatch ordering nested limits node_pool priority shutdown worker_policy worker_wake worker_wait worker_count worker_spin)
|
||||
add_test(NAME guest_job_manager_${testCase} COMMAND guest_job_manager_tests ${testCase})
|
||||
set_tests_properties(guest_job_manager_${testCase} PROPERTIES TIMEOUT 20)
|
||||
if(WIN32)
|
||||
|
||||
@@ -247,8 +247,8 @@ struct Manager {
|
||||
|
||||
thread_local Manager* currentWorker = nullptr;
|
||||
|
||||
void WakeWorkers(Manager& manager, std::uint32_t invocations) {
|
||||
const std::uint32_t available = invocations - (currentWorker == &manager ? 1u : 0u);
|
||||
void WakeWorkers(Manager& manager, std::uint32_t invocations, bool publisherCanRun = true) {
|
||||
const std::uint32_t available = invocations - (publisherCanRun && currentWorker == &manager ? 1u : 0u);
|
||||
manager.wakeTokens += std::min(available, manager.sleepingWorkers - manager.wakeTokens);
|
||||
if (manager.wakeTokens != 0) manager.work.notify_all();
|
||||
}
|
||||
@@ -477,6 +477,13 @@ int Sequence::WaitLocked(std::unique_lock<std::mutex>& guard) {
|
||||
bool done = false;
|
||||
items.push_back({ItemType::Wait, this, nullptr, nullptr, 0, 0, 0, &done});
|
||||
Advance();
|
||||
if (!done && currentWorker == manager) {
|
||||
std::uint64_t runnable = 0;
|
||||
for (const auto& queue : manager->runQueues) {
|
||||
for (const Item* item : queue) runnable += item->count - item->handedOut;
|
||||
}
|
||||
WakeWorkers(*manager, static_cast<std::uint32_t>(std::min(runnable, std::uint64_t{manager->workerCount})), false);
|
||||
}
|
||||
passed.wait(guard, [&done] { return done; });
|
||||
--manager->blockedWaiters;
|
||||
return result;
|
||||
|
||||
@@ -303,6 +303,61 @@ static void APS5_VABI LeaderJob(void* argument, std::uint32_t) {
|
||||
nested.leaderFinished = true;
|
||||
}
|
||||
|
||||
static void RequireParked(int clock);
|
||||
|
||||
struct WorkerWait {
|
||||
int spareClock = 0;
|
||||
Sequence* child;
|
||||
std::atomic<bool> publisherEntered{false};
|
||||
std::atomic<bool> spareEntered{false};
|
||||
std::atomic<bool> publish{false};
|
||||
std::atomic<bool> finished{false};
|
||||
std::atomic<unsigned> childCalls{0};
|
||||
};
|
||||
|
||||
static void APS5_VABI WorkerWaitChild(void* argument, std::uint32_t) {
|
||||
++static_cast<WorkerWait*>(argument)->childCalls;
|
||||
}
|
||||
|
||||
static void APS5_VABI WorkerWaitPublisher(void* argument, std::uint32_t index) {
|
||||
auto& state = *static_cast<WorkerWait*>(argument);
|
||||
if (index != 0) {
|
||||
Require(pthread_getcpuclockid_nid_postfix(scePthreadSelf(), &state.spareClock) == 0);
|
||||
state.spareEntered = true;
|
||||
return;
|
||||
}
|
||||
state.publisherEntered = true;
|
||||
while (!state.publish) std::this_thread::yield();
|
||||
Require(state.child->Dispatch(WorkerWaitChild, &state, 1, "child") == 0);
|
||||
Require(state.child->Wait() == 0);
|
||||
state.finished = true;
|
||||
}
|
||||
|
||||
static void WorkerWaitCase() {
|
||||
Block block(SizeFor(2, 2, 4, 0, 4));
|
||||
ManagerObject manager;
|
||||
const ConfigParams config{0, 0x21fff, 0x10000, 0x2bc, "WorkerWait", 0, 0, 0, 0};
|
||||
Require(Initialize(manager.storage, block.memory, block.bytes, 2, 2, &config) == 0);
|
||||
Require(SetPersistentThreadCount(manager.storage, 0) == 0);
|
||||
SequenceFactory* factory = Factories(manager.storage, 0);
|
||||
Sequence* publisher = nullptr;
|
||||
WorkerWait state{};
|
||||
Require(factory->Create(&publisher, 2, 1, 0, 1, "publisher") == 0);
|
||||
Require(factory->Create(&state.child, 1, 1, 0, 1, "child") == 0);
|
||||
Require(publisher->Dispatch(WorkerWaitPublisher, &state, 2, "park spare") == 0);
|
||||
auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(3);
|
||||
while ((!state.publisherEntered || !state.spareEntered) && std::chrono::steady_clock::now() < deadline) std::this_thread::yield();
|
||||
Require(state.publisherEntered && state.spareEntered);
|
||||
RequireParked(state.spareClock);
|
||||
state.publish = true;
|
||||
deadline = std::chrono::steady_clock::now() + std::chrono::seconds(3);
|
||||
while (!state.finished && std::chrono::steady_clock::now() < deadline) std::this_thread::yield();
|
||||
Require(state.finished && state.childCalls == 1);
|
||||
Require(publisher->Wait() == 0);
|
||||
Require(factory->Destroy(publisher) == 0 && factory->Destroy(state.child) == 0);
|
||||
Require(Shutdown(manager.storage) == 0);
|
||||
}
|
||||
|
||||
static void NestedCase() {
|
||||
Block block(SizeFor(2, 1, 4, 2, 2));
|
||||
ManagerObject manager;
|
||||
@@ -711,6 +766,7 @@ int RunJobManagerCase(const char* caseName) {
|
||||
else if (name == "priority") PriorityCase();
|
||||
else if (name == "shutdown") ShutdownCase();
|
||||
else if (name == "worker_policy") WorkerPolicyCase();
|
||||
else if (name == "worker_wait") WorkerWaitCase();
|
||||
else if (name == "worker_wake") WorkerWakeCase();
|
||||
else if (name == "worker_spin") WorkerSpinCase();
|
||||
else if (name == "worker_count") WorkerCountCase();
|
||||
|
||||
@@ -15,7 +15,7 @@ ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "core/relinker/relinker/tests"))
|
||||
from guest_import_fixtures import executable
|
||||
|
||||
CASES = ("memory", "validation", "dispatch", "ordering", "nested", "limits", "node_pool", "priority", "shutdown", "worker_policy", "worker_wake", "worker_count", "worker_spin")
|
||||
CASES = ("memory", "validation", "dispatch", "ordering", "nested", "limits", "node_pool", "priority", "shutdown", "worker_policy", "worker_wake", "worker_wait", "worker_count", "worker_spin")
|
||||
|
||||
|
||||
def stage_libraries(directory, build, toolchain, dependencies):
|
||||
|
||||
Reference in new issue
Block a user