diff --git a/core/libs/prx/libSceJobManager/Export.cpp b/core/libs/prx/libSceJobManager/Export.cpp index 7c6a8d77dcad..dafdc9f89c36 100644 --- a/core/libs/prx/libSceJobManager/Export.cpp +++ b/core/libs/prx/libSceJobManager/Export.cpp @@ -1018,7 +1018,7 @@ int Initialize(void* self, void* memory, std::uint64_t size, std::uint32_t worke std::unique_ptr owner(manager, DestroyManager); manager->running = true; manager->workerCount = workers; - manager->spinTicks = sceKernelGetTscFrequency() / 1000000 * settings.spinMicroseconds; + manager->spinTicks = HostTscFrequency_nid_no_patch() / 1000000 * settings.spinMicroseconds; for (std::uint32_t index = 0; index < layout.nodes; ++index) std::construct_at(&manager->nodes[index]); for (std::uint32_t index = layout.nodes; index > 1; --index) ReturnNode(*manager, &manager->nodes[index - 1]); manager->freeSequences = sequences == MaxSequences ? ~std::uint32_t{0} : (std::uint32_t{1} << sequences) - 1; diff --git a/core/libs/prx/libkernel/CMakeLists.txt b/core/libs/prx/libkernel/CMakeLists.txt index 2a70b082f255..046719c5e42e 100644 --- a/core/libs/prx/libkernel/CMakeLists.txt +++ b/core/libs/prx/libkernel/CMakeLists.txt @@ -239,9 +239,11 @@ if(BUILD_TESTING) endif() add_test(NAME guest_process_time_tsc COMMAND guest_process_time_tests tsc) add_test(NAME guest_process_time_tsc_scaled COMMAND guest_process_time_tests tsc) - set_tests_properties(guest_process_time_tsc_scaled PROPERTIES ENVIRONMENT "APS5_TIME_SCALE=0.5") + add_test(NAME guest_process_time_rdtsc COMMAND guest_process_time_tests rdtsc) + add_test(NAME guest_process_time_rdtsc_scaled COMMAND guest_process_time_tests rdtsc) + set_tests_properties(guest_process_time_tsc_scaled guest_process_time_rdtsc_scaled PROPERTIES ENVIRONMENT "APS5_TIME_SCALE=0.5") if(WIN32) - set_tests_properties(guest_process_time_tsc guest_process_time_tsc_scaled PROPERTIES ENVIRONMENT_MODIFICATION + set_tests_properties(guest_process_time_tsc guest_process_time_tsc_scaled guest_process_time_rdtsc guest_process_time_rdtsc_scaled PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() add_test_executable(guest_process_arguments_tests ${LIBS_INCLUDE_DIR}/tests/GuestProcessArguments.cpp) diff --git a/core/libs/prx/libkernel/Time/Time.cpp b/core/libs/prx/libkernel/Time/Time.cpp index d97b8b752a70..fefda9aeb85c 100644 --- a/core/libs/prx/libkernel/Time/Time.cpp +++ b/core/libs/prx/libkernel/Time/Time.cpp @@ -849,12 +849,10 @@ int APS5_VABI sceKernelGettimezone(KernelTimezone* tz) { } uint64_t APS5_VABI sceKernelReadTsc(void) { - if (TimeScale() == 1.0) return __rdtsc(); - static const std::uint64_t origin = __rdtsc(); - return origin + static_cast(static_cast(__rdtsc() - origin) * TimeScale()); + return __rdtsc(); } -uint64_t APS5_VABI sceKernelGetTscFrequency(void) { +std::uint64_t APS5_VABI HostTscFrequency_nid_no_patch() { static const std::uint64_t frequency = [] { const CurrentCpuPin pin; const std::uint64_t startNanos = RawMonotonicNanos(); @@ -867,6 +865,11 @@ uint64_t APS5_VABI sceKernelGetTscFrequency(void) { return frequency; } +uint64_t APS5_VABI sceKernelGetTscFrequency(void) { + static const std::uint64_t frequency = static_cast(static_cast(HostTscFrequency_nid_no_patch()) / TimeScale()); + return frequency; +} + std::int64_t APS5_VABI sceKernelGetCpuFrequency(void) { return static_cast(sceKernelGetTscFrequency()); } diff --git a/core/libs/prx/libkernel/Time/include/Time.hpp b/core/libs/prx/libkernel/Time/include/Time.hpp index 3d292a09a6c6..983695748d9c 100644 --- a/core/libs/prx/libkernel/Time/include/Time.hpp +++ b/core/libs/prx/libkernel/Time/include/Time.hpp @@ -11,6 +11,7 @@ extern "C" { std::uint64_t APS5_VABI sceKernelGetProcessTimeCounter(); std::uint64_t APS5_VABI sceKernelGetProcessTimeCounterFrequency(); std::uint64_t APS5_VABI sceKernelGetTscFrequency(); + std::uint64_t APS5_VABI HostTscFrequency_nid_no_patch(); int APS5_VABI sceKernelUsleep_nid_postfix(KernelUseconds microseconds); int APS5_VABI sceKernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rmtp); int APS5_VABI nanosleep_nid_postfix(const KernelTimespec* rqtp, KernelTimespec* rmtp); diff --git a/core/libs/tests/GuestProcessTime.cpp b/core/libs/tests/GuestProcessTime.cpp index 0d75b8f43f6c..c4c89f86ca4a 100644 --- a/core/libs/tests/GuestProcessTime.cpp +++ b/core/libs/tests/GuestProcessTime.cpp @@ -6,6 +6,7 @@ #include #include #include +#include static void Require(bool condition, const char* message) { if (!condition) { @@ -21,6 +22,18 @@ int main(int argc, char** argv) { const double scale = scaleText ? std::strtod(scaleText, nullptr) : 1.0; const auto elapsedMicros = static_cast(static_cast(sleptMicros) * (scale > 0.0 ? scale : 1.0)); const auto minimumElapsedMicros = elapsedMicros * 19 / 20; + if (argc > 1 && std::strcmp(argv[1], "rdtsc") == 0) { + const std::uint64_t frequency = sceKernelGetTscFrequency(); + const std::uint64_t nativeStart = __rdtsc(); + const std::uint64_t readStart = sceKernelReadTsc(); + const auto until = std::chrono::steady_clock::now() + std::chrono::microseconds(sleptMicros); + while (std::chrono::steady_clock::now() < until) std::this_thread::sleep_until(until); + const std::uint64_t nativeMicros = (__rdtsc() - nativeStart) * 1000000 / frequency; + const std::uint64_t readMicros = (sceKernelReadTsc() - readStart) * 1000000 / frequency; + Require(nativeMicros >= minimumElapsedMicros && nativeMicros < elapsedMicros * 3 / 2, "native rdtsc ticks over the reported TSC frequency do not follow the time scale"); + Require(readMicros >= minimumElapsedMicros && readMicros < elapsedMicros * 3 / 2, "sceKernelReadTsc ticks over the reported TSC frequency do not follow the time scale"); + return 0; + } const auto slept = std::chrono::steady_clock::now() + std::chrono::microseconds(sleptMicros); while (std::chrono::steady_clock::now() < slept) std::this_thread::sleep_until(slept); if (argc > 1 && std::strcmp(argv[1], "tsc") == 0) {