From f9d020bd84cdcd76a1b28ea8ab704abc3a65eb9b Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Mon, 3 Aug 2026 12:34:13 -0500 Subject: [PATCH 1/2] Preserve sub-millisecond event timestamp precision Use precise wall-clock time where available and retain nanosecond-derived 100 ns ticks on POSIX so record.time no longer truncates every event to milliseconds. Add regression coverage for POSIX timestamp precision.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 05d1030e-75b0-447f-9856-65091d59a97f --- lib/pal/PAL.cpp | 25 ++++++++++++++++++++----- tests/unittests/PalTests.cpp | 16 ++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/pal/PAL.cpp b/lib/pal/PAL.cpp index 3e667653f..a5291b0e3 100644 --- a/lib/pal/PAL.cpp +++ b/lib/pal/PAL.cpp @@ -430,7 +430,23 @@ namespace PAL_NS_BEGIN { { #ifdef _WIN32 FILETIME tocks; - ::GetSystemTimeAsFileTime(&tocks); + // Resolve the precise API dynamically so the SDK retains its Windows 7 + // runtime compatibility and falls back when the API is unavailable. + using GetSystemTimePreciseAsFileTimeProc = VOID (WINAPI*)(LPFILETIME); + HMODULE kernel32 = ::GetModuleHandleW(L"kernel32.dll"); + auto getSystemTimePreciseAsFileTime = + kernel32 + ? reinterpret_cast( + ::GetProcAddress(kernel32, "GetSystemTimePreciseAsFileTime")) + : nullptr; + if (getSystemTimePreciseAsFileTime) + { + getSystemTimePreciseAsFileTime(&tocks); + } + else + { + ::GetSystemTimeAsFileTime(&tocks); + } ULONGLONG ticks = (ULONGLONG(tocks.dwHighDateTime) << 32) | tocks.dwLowDateTime; // number of days from beginning to 1601 multiplied by ticks per day return ticks + 0x701ce1722770000ULL; @@ -440,10 +456,9 @@ namespace PAL_NS_BEGIN { // This UTC epoch contract has been signed in blood since C++20 std::chrono::time_point now = std::chrono::system_clock::now(); auto duration = now.time_since_epoch(); - auto millis = std::chrono::duration_cast(duration).count(); - uint64_t ticks = millis; - ticks *= 10000; // convert millis to ticks (1 tick = 100ns) - ticks += 0x89F7FF5F7B58000ULL; // UTC time 0 in .NET ticks + auto nanos = std::chrono::duration_cast(duration).count(); + int64_t ticks = nanos / 100; // convert nanoseconds to .NET ticks (1 tick = 100ns) + ticks += static_cast(0x89F7FF5F7B58000ULL); // UTC time 0 in .NET ticks return ticks; #endif } diff --git a/tests/unittests/PalTests.cpp b/tests/unittests/PalTests.cpp index ddf1f6dd2..c931ff376 100644 --- a/tests/unittests/PalTests.cpp +++ b/tests/unittests/PalTests.cpp @@ -122,6 +122,22 @@ TEST_F(PalTests, SystemTime) EXPECT_THAT(t1, Lt(t0 + 1000)); } +#if !defined(_WIN32) && !defined(_WIN64) +TEST_F(PalTests, SystemTimeInTicksPreservesSubMillisecondPrecision) +{ + constexpr int64_t TicksPerMillisecond = 10000; + bool observedSubMillisecondTick = false; + + for (int i = 0; i < 1000 && !observedSubMillisecondTick; ++i) + { + observedSubMillisecondTick = + PAL::getUtcSystemTimeinTicks() % TicksPerMillisecond != 0; + } + + EXPECT_TRUE(observedSubMillisecondTick); +} +#endif + TEST_F(PalTests, FormatUtcTimestampMsAsISO8601) { EXPECT_THAT(PAL::formatUtcTimestampMsAsISO8601(0ll), Eq("1970-01-01T00:00:00.000Z")); From babeb981262cb88bdf74b036c0da95489c477450 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Mon, 3 Aug 2026 15:31:27 -0500 Subject: [PATCH 2/2] Cache precise Windows clock lookup Resolve GetSystemTimePreciseAsFileTime once instead of repeating module and symbol lookups for every event timestamp.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 05d1030e-75b0-447f-9856-65091d59a97f --- lib/pal/PAL.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/pal/PAL.cpp b/lib/pal/PAL.cpp index a5291b0e3..0fc28abfb 100644 --- a/lib/pal/PAL.cpp +++ b/lib/pal/PAL.cpp @@ -433,12 +433,15 @@ namespace PAL_NS_BEGIN { // Resolve the precise API dynamically so the SDK retains its Windows 7 // runtime compatibility and falls back when the API is unavailable. using GetSystemTimePreciseAsFileTimeProc = VOID (WINAPI*)(LPFILETIME); - HMODULE kernel32 = ::GetModuleHandleW(L"kernel32.dll"); - auto getSystemTimePreciseAsFileTime = - kernel32 - ? reinterpret_cast( - ::GetProcAddress(kernel32, "GetSystemTimePreciseAsFileTime")) - : nullptr; + static const GetSystemTimePreciseAsFileTimeProc getSystemTimePreciseAsFileTime = + []() -> GetSystemTimePreciseAsFileTimeProc + { + HMODULE kernel32 = ::GetModuleHandleW(L"kernel32.dll"); + return kernel32 + ? reinterpret_cast( + ::GetProcAddress(kernel32, "GetSystemTimePreciseAsFileTime")) + : nullptr; + }(); if (getSystemTimePreciseAsFileTime) { getSystemTimePreciseAsFileTime(&tocks);