[PATCH 6/6] ntdll/tests: Add RtlQueryPerformanceCounter tests.

Rémi Bernon rbernon at codeweavers.com
Wed Mar 10 05:22:36 CST 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/ntdll/tests/time.c | 110 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/dlls/ntdll/tests/time.c b/dlls/ntdll/tests/time.c
index 51d9115b87c..d028f12e97c 100644
--- a/dlls/ntdll/tests/time.c
+++ b/dlls/ntdll/tests/time.c
@@ -19,8 +19,10 @@
  */
 
 #define NONAMELESSUNION
+#define NONAMELESSSTRUCT
 #include "ntdll_test.h"
 #include "ddk/wdm.h"
+#include "intrin.h"
 
 #define TICKSPERSEC        10000000
 #define TICKSPERMSEC       10000
@@ -35,6 +37,9 @@ static NTSTATUS (WINAPI *pRtlQueryTimeZoneInformation)( RTL_TIME_ZONE_INFORMATIO
 static NTSTATUS (WINAPI *pRtlQueryDynamicTimeZoneInformation)( RTL_DYNAMIC_TIME_ZONE_INFORMATION *);
 static BOOL     (WINAPI *pRtlQueryUnbiasedInterruptTime)( ULONGLONG *time );
 
+static BOOL     (WINAPI *pRtlQueryPerformanceCounter)(LARGE_INTEGER*);
+static BOOL     (WINAPI *pRtlQueryPerformanceFrequency)(LARGE_INTEGER*);
+
 static const int MonthLengths[2][12] =
 {
 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
@@ -122,6 +127,108 @@ static void test_NtQueryPerformanceCounter(void)
     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
 }
 
+struct hypervisor_shared_data
+{
+    UINT64 unknown;
+    UINT64 QpcMultiplier;
+    UINT64 QpcBias;
+};
+
+static void test_RtlQueryPerformanceCounter(void)
+{
+    SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION si;
+    struct hypervisor_shared_data *hsd;
+    KSHARED_USER_DATA *usd = (void *)0x7ffe0000;
+    LARGE_INTEGER frequency, counter;
+    unsigned int aux;
+    NTSTATUS status;
+    UINT64 tsc0, tsc1, mul_lo, mul_hi, tsc_lo, tsc_hi;
+    ULONG len;
+    BOOL ret;
+
+    if (!pRtlQueryPerformanceCounter || !pRtlQueryPerformanceFrequency)
+    {
+        win_skip( "RtlQueryPerformanceCounter/Frequency not available, skipping tests\n" );
+        return;
+    }
+
+    if (!(usd->u3.s.QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED))
+    {
+        todo_wine win_skip("QpcBypassEnabled is not set, skipping tests\n");
+        return;
+    }
+
+    if ((usd->u3.s.QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE))
+    {
+        ok( usd->u3.s.QpcBypassEnabled == (SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED|SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE|SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_RDTSCP),
+            "unexpected QpcBypassEnabled %x, expected 0x83\n", usd->u3.s.QpcBypassEnabled );
+        ok( usd->QpcFrequency == 10000000, "unexpected QpcFrequency %I64d, expected 10000000\n", usd->QpcFrequency );
+        ok( !usd->u3.s.QpcShift, "unexpected QpcShift %d, expected 0\n", usd->u3.s.QpcShift );
+        ok( usd->QpcInterruptTimeIncrement == ((ULONGLONG)1 << 63),
+            "unexpected QpcInterruptTimeIncrement %I64x, expected 1<<63\n", usd->QpcInterruptTimeIncrement );
+        ok( usd->QpcInterruptTimeIncrementShift == 1,
+            "unexpected QpcInterruptTimeIncrementShift %d, expected 1\n", usd->QpcInterruptTimeIncrementShift );
+        ok( usd->QpcSystemTimeIncrement == ((ULONGLONG)1 << 63),
+            "unexpected QpcSystemTimeIncrement %I64x, expected 1<<63\n", usd->QpcSystemTimeIncrement );
+        ok( usd->QpcSystemTimeIncrementShift == 1,
+            "unexpected QpcSystemTimeIncrementShift %d, expected 1\n", usd->QpcSystemTimeIncrementShift );
+
+        memset( &si, 0xcc, sizeof(si) );
+        status = pNtQuerySystemInformation( SystemHypervisorSharedPageInformation, &si, sizeof(si), &len );
+        ok( !status, "NtQuerySystemInformation returned %x\n", status );
+        ok( len == sizeof(si), "unexpected SystemHypervisorSharedPageInformation length %u\n", len );
+        trace( "SystemHypervisorSharedPageInformation: %p\n", si.HypervisorSharedUserVa );
+        hsd = (struct hypervisor_shared_data *)si.HypervisorSharedUserVa;
+        mul_hi = (hsd->QpcMultiplier >> 32);
+        mul_lo = (UINT32)hsd->QpcMultiplier;
+
+        tsc0 = __rdtscp(&aux);
+        ret = pRtlQueryPerformanceCounter( &counter );
+        tsc1 = __rdtscp(&aux);
+        ok( ret, "RtlQueryPerformanceCounter failed\n" );
+
+        tsc_hi = (tsc0 >> 32);
+        tsc_lo = (UINT32)tsc0;
+        tsc0 = (tsc_hi * mul_hi) + (tsc_hi * mul_lo >> 32) + (mul_hi * tsc_lo >> 32);
+        tsc0 += usd->QpcBias + hsd->QpcBias;
+
+        tsc_hi = (tsc1 >> 32);
+        tsc_lo = (UINT32)tsc1;
+        tsc1 = (tsc_hi * mul_hi) + (tsc_hi * mul_lo >> 32) + (mul_hi * tsc_lo >> 32);
+        tsc1 += usd->QpcBias + hsd->QpcBias;
+
+        ok( tsc0 <= counter.QuadPart, "rdtscp %I64d and RtlQueryPerformanceCounter %I64d are out of order\n", tsc0, counter.QuadPart );
+        ok( counter.QuadPart <= tsc1, "RtlQueryPerformanceCounter %I64d and rdtscp %I64d are out of order\n", counter.QuadPart, tsc1 );
+    }
+    else
+    {
+        ok( usd->u3.s.QpcShift == 10, "unexpected QpcShift %d, expected 10\n", usd->u3.s.QpcShift );
+        ok( usd->QpcInterruptTimeIncrementShift == 2,
+            "unexpected QpcInterruptTimeIncrementShift %d, expected 2\n", usd->QpcInterruptTimeIncrementShift );
+        ok( usd->QpcSystemTimeIncrementShift == 2,
+            "unexpected QpcSystemTimeIncrementShift %d, expected 2\n", usd->QpcSystemTimeIncrementShift );
+
+        tsc0 = __rdtsc();
+        ret = pRtlQueryPerformanceCounter( &counter );
+        tsc1 = __rdtsc();
+        ok( ret, "RtlQueryPerformanceCounter failed\n" );
+
+        tsc0 += usd->QpcBias;
+        tsc0 >>= usd->u3.s.QpcShift;
+        tsc1 += usd->QpcBias;
+        tsc1 >>= usd->u3.s.QpcShift;
+
+        ok( tsc0 <= counter.QuadPart, "rdtscp %I64d and RtlQueryPerformanceCounter %I64d are out of order\n", tsc0, counter.QuadPart );
+        ok( counter.QuadPart <= tsc1, "RtlQueryPerformanceCounter %I64d and rdtscp %I64d are out of order\n", counter.QuadPart, tsc1 );
+    }
+
+    ret = pRtlQueryPerformanceFrequency( &frequency );
+    ok( ret, "RtlQueryPerformanceFrequency failed\n" );
+    ok( frequency.QuadPart == usd->QpcFrequency,
+        "RtlQueryPerformanceFrequency returned %I64d, expected USD QpcFrequency %I64d\n",
+        frequency.QuadPart, usd->QpcFrequency );
+}
+
 static void test_RtlQueryTimeZoneInformation(void)
 {
     RTL_DYNAMIC_TIME_ZONE_INFORMATION tzinfo, tzinfo2;
@@ -266,6 +373,8 @@ START_TEST(time)
     pRtlQueryDynamicTimeZoneInformation =
         (void *)GetProcAddress(mod, "RtlQueryDynamicTimeZoneInformation");
     pRtlQueryUnbiasedInterruptTime = (void *)GetProcAddress(mod, "RtlQueryUnbiasedInterruptTime");
+    pRtlQueryPerformanceCounter = (void *)GetProcAddress(mod, "RtlQueryPerformanceCounter");
+    pRtlQueryPerformanceFrequency = (void *)GetProcAddress(mod, "RtlQueryPerformanceFrequency");
 
     if (pRtlTimeToTimeFields && pRtlTimeFieldsToTime)
         test_pRtlTimeToTimeFields();
@@ -274,4 +383,5 @@ START_TEST(time)
     test_NtQueryPerformanceCounter();
     test_RtlQueryTimeZoneInformation();
     test_user_shared_data_time();
+    test_RtlQueryPerformanceCounter();
 }
-- 
2.30.0




More information about the wine-devel mailing list