Files
Nicolas AboschandClaude Opus 5.5 82dd286192 perf(libkernel): end short sleeps when the GPU or a flip completes
A sleep of 1 ms or less returns once the AGC driver sees a GPU batch
complete (a thread waits on the recorder's timeline semaphore), runs a
batch's completion actions, or VideoOut completes a flip. A thread
returns early at most 8 times in a run of back-to-back sleeps; the run
restarts when the thread submits AGC work or did not sleep for the
requested time. APS5_NO_SLEEP_WAKE=1 keeps every sleep in full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:50:57 -03:00

58 lines
1.4 KiB
C++

#include "prx/libkernel/Time/include/SleepWake.hpp"
#include "prx/libkernel/Time/include/TimedWait.hpp"
#include <atomic>
#include <cstdlib>
namespace SleepWake {
namespace {
struct ThreadState {
unsigned earlyWakes = 0;
std::uint64_t lastSleepEndNanos = 0;
bool sleeping = false;
};
thread_local ThreadState state;
std::atomic<std::uint64_t> completions{0};
bool Enabled() {
static const bool enabled = std::getenv("APS5_NO_SLEEP_WAKE") == nullptr;
return enabled;
}
}
void Sleep(std::uint64_t nanos) {
bool woken = false;
if (nanos != 0 && nanos <= MAX_WAKEABLE_NANOS && !state.sleeping && Enabled()) {
if (TimedWait::NowNanos() - state.lastSleepEndNanos >= nanos) state.earlyWakes = 0;
if (state.earlyWakes < EARLY_WAKES_PER_RUN) {
state.sleeping = true;
const bool early = TimedWait::SleepNanosUnlessChanged(nanos, completions, completions.load(std::memory_order_seq_cst));
state.sleeping = false;
if (early) ++state.earlyWakes;
woken = true;
}
}
if (!woken) TimedWait::SleepNanos(nanos);
state.lastSleepEndNanos = TimedWait::NowNanos();
}
}
extern "C" {
void KernelWakeSleepers_nid_no_patch() {
SleepWake::completions.fetch_add(1, std::memory_order_seq_cst);
TimedWait::WakeChangeSleepers();
}
void KernelNoteGpuSubmit_nid_no_patch() {
SleepWake::state.earlyWakes = 0;
}
}