[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