mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
kernel: block short sleep requests instead of busy waiting
This commit is contained in:
+2
-40
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <chrono> // IWYU pragma: keep
|
#include <chrono> // IWYU pragma: keep
|
||||||
@@ -26,8 +25,7 @@
|
|||||||
#ifdef KYTY_WIN_CS
|
#ifdef KYTY_WIN_CS
|
||||||
#include <windows.h> // IWYU pragma: keep
|
#include <windows.h> // IWYU pragma: keep
|
||||||
// IWYU pragma: no_include <winbase.h>
|
// IWYU pragma: no_include <winbase.h>
|
||||||
constexpr DWORD KYTY_CS_SPIN_COUNT = 4000;
|
constexpr DWORD KYTY_CS_SPIN_COUNT = 4000;
|
||||||
constexpr uint64_t KYTY_SLEEP_SPIN_LIMIT_100NS = 500; // 50 us
|
|
||||||
|
|
||||||
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
|
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
|
||||||
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
|
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
|
||||||
@@ -38,30 +36,6 @@ static void SleepHighResolution100ns(uint64_t units_100ns) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep spinning only where a kernel transition is
|
|
||||||
// likely to cost more than the requested delay; ordinary millisecond sleeps use the
|
|
||||||
// per-thread high-resolution waitable timer below.
|
|
||||||
if (units_100ns <= KYTY_SLEEP_SPIN_LIMIT_100NS) {
|
|
||||||
LARGE_INTEGER frequency {};
|
|
||||||
LARGE_INTEGER start {};
|
|
||||||
if (QueryPerformanceFrequency(&frequency) != 0 && QueryPerformanceCounter(&start) != 0 &&
|
|
||||||
frequency.QuadPart > 0) {
|
|
||||||
const auto wait_ticks =
|
|
||||||
static_cast<LONGLONG>((static_cast<long double>(units_100ns) *
|
|
||||||
static_cast<long double>(frequency.QuadPart)) /
|
|
||||||
10000000.0L);
|
|
||||||
const auto deadline = start.QuadPart + std::max<LONGLONG>(wait_ticks, 1);
|
|
||||||
LARGE_INTEGER now {};
|
|
||||||
do {
|
|
||||||
if (QueryPerformanceCounter(&now) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
YieldProcessor();
|
|
||||||
} while (now.QuadPart < deadline);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thread_local HANDLE timer = CreateWaitableTimerExW(
|
thread_local HANDLE timer = CreateWaitableTimerExW(
|
||||||
nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
||||||
if (timer == nullptr) {
|
if (timer == nullptr) {
|
||||||
@@ -131,14 +105,13 @@ static SleepConditionVariableCS_func_t ResolveSleepConditionVariableCS() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef KYTY_POSIX_HIGH_RES_SLEEP
|
#ifdef KYTY_POSIX_HIGH_RES_SLEEP
|
||||||
// Spin for very short waits; use an absolute deadline for longer waits.
|
// An absolute deadline preserves the requested sleep across signal interruptions.
|
||||||
static void SleepHighResolutionNanos(uint64_t nanos) {
|
static void SleepHighResolutionNanos(uint64_t nanos) {
|
||||||
if (nanos == 0) {
|
if (nanos == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint64_t NANOS_PER_SEC = 1000000000;
|
constexpr uint64_t NANOS_PER_SEC = 1000000000;
|
||||||
constexpr uint64_t SPIN_LIMIT_NS = 50000; // below this a context switch dominates
|
|
||||||
|
|
||||||
timespec deadline {};
|
timespec deadline {};
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0) {
|
if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0) {
|
||||||
@@ -150,17 +123,6 @@ static void SleepHighResolutionNanos(uint64_t nanos) {
|
|||||||
deadline.tv_sec += static_cast<time_t>(target_nsec / NANOS_PER_SEC);
|
deadline.tv_sec += static_cast<time_t>(target_nsec / NANOS_PER_SEC);
|
||||||
deadline.tv_nsec = static_cast<long>(target_nsec % NANOS_PER_SEC);
|
deadline.tv_nsec = static_cast<long>(target_nsec % NANOS_PER_SEC);
|
||||||
|
|
||||||
if (nanos <= SPIN_LIMIT_NS) {
|
|
||||||
timespec now {};
|
|
||||||
do {
|
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} while (now.tv_sec < deadline.tv_sec ||
|
|
||||||
(now.tv_sec == deadline.tv_sec && now.tv_nsec < deadline.tv_nsec));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, nullptr) == EINTR) {
|
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, nullptr) == EINTR) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-30
@@ -512,15 +512,6 @@ static void SchedulerBackoffOnce() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool SleepMicroSchedulerBackoff(uint64_t microseconds) {
|
|
||||||
if (microseconds > 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SchedulerBackoffOnce();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SleepMicroWithSignalPoll(uint64_t microseconds) {
|
static void SleepMicroWithSignalPoll(uint64_t microseconds) {
|
||||||
if (microseconds == 0) {
|
if (microseconds == 0) {
|
||||||
KernelDispatchPendingSignalForCurrentThread();
|
KernelDispatchPendingSignalForCurrentThread();
|
||||||
@@ -529,9 +520,7 @@ static void SleepMicroWithSignalPoll(uint64_t microseconds) {
|
|||||||
|
|
||||||
while (microseconds > 0) {
|
while (microseconds > 0) {
|
||||||
const auto step = std::min<uint64_t>(microseconds, SIGNAL_APC_POLL_MICROS);
|
const auto step = std::min<uint64_t>(microseconds, SIGNAL_APC_POLL_MICROS);
|
||||||
if (!SleepMicroSchedulerBackoff(step)) {
|
Common::Thread::SleepMicro(step);
|
||||||
Common::Thread::SleepMicro(step);
|
|
||||||
}
|
|
||||||
microseconds -= step;
|
microseconds -= step;
|
||||||
KernelDispatchPendingSignalForCurrentThread();
|
KernelDispatchPendingSignalForCurrentThread();
|
||||||
}
|
}
|
||||||
@@ -3842,28 +3831,16 @@ void KYTY_SYSV_ABI KernelSetThreadDtors(thread_dtors_func_t dtors) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI KernelUsleep(KernelUseconds microseconds) {
|
int KYTY_SYSV_ABI KernelUsleep(KernelUseconds microseconds) {
|
||||||
Common::Timer t;
|
|
||||||
t.Start();
|
|
||||||
SleepMicroWithSignalPoll(microseconds);
|
SleepMicroWithSignalPoll(microseconds);
|
||||||
// double ts = t.GetTimeS();
|
|
||||||
// LOGF("\tactual: %g microseconds\n", ts * 1000000.0);
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int KYTY_SYSV_ABI KernelSleep(unsigned int seconds) {
|
unsigned int KYTY_SYSV_ABI KernelSleep(unsigned int seconds) {
|
||||||
PRINT_NAME();
|
|
||||||
LOGF("\tsleep: %u\n", seconds);
|
|
||||||
Common::Timer t;
|
|
||||||
t.Start();
|
|
||||||
SleepMicroWithSignalPoll(static_cast<uint64_t>(seconds) * 1000000ull);
|
SleepMicroWithSignalPoll(static_cast<uint64_t>(seconds) * 1000000ull);
|
||||||
double ts = t.GetTimeS();
|
|
||||||
LOGF("\tactual: %g seconds\n", ts);
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI KernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rmtp) {
|
int KYTY_SYSV_ABI KernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rmtp) {
|
||||||
PRINT_NAME();
|
|
||||||
|
|
||||||
if (rqtp == nullptr) {
|
if (rqtp == nullptr) {
|
||||||
return KERNEL_ERROR_EFAULT;
|
return KERNEL_ERROR_EFAULT;
|
||||||
}
|
}
|
||||||
@@ -3880,13 +3857,7 @@ int KYTY_SYSV_ABI KernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rm
|
|||||||
uint64_t nanos =
|
uint64_t nanos =
|
||||||
static_cast<uint64_t>(rqtp->tv_sec) * 1000000000ull + static_cast<uint64_t>(rqtp->tv_nsec);
|
static_cast<uint64_t>(rqtp->tv_sec) * 1000000000ull + static_cast<uint64_t>(rqtp->tv_nsec);
|
||||||
|
|
||||||
LOGF("\tnanosleep: %" PRIu64 "\n", nanos);
|
|
||||||
|
|
||||||
Common::Timer t;
|
|
||||||
t.Start();
|
|
||||||
SleepNanoWithSignalPoll(nanos);
|
SleepNanoWithSignalPoll(nanos);
|
||||||
double ts = t.GetTimeS();
|
|
||||||
LOGF("\tactual: %g nanoseconds\n", ts * 1000000000.0);
|
|
||||||
|
|
||||||
if (rmtp != nullptr) {
|
if (rmtp != nullptr) {
|
||||||
rmtp->tv_sec = 0;
|
rmtp->tv_sec = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user