Rémi Bernon : ntdll/tests: Add RtlQueryPerformanceCounter tests.
Alexandre Julliard
julliard at winehq.org
Fri Mar 19 16:42:01 CDT 2021
Module: wine
Branch: master
Commit: d9d478e277bcf60e47803d00d1897e8aa649027c
URL: https://source.winehq.org/git/wine.git/?a=commit;h=d9d478e277bcf60e47803d00d1897e8aa649027c
Author: Rémi Bernon <rbernon at codeweavers.com>
Date: Thu Mar 18 17:22:06 2021 +0100
ntdll/tests: Add RtlQueryPerformanceCounter tests.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/tests/time.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++
include/winternl.h | 1 +
2 files changed, 112 insertions(+)
diff --git a/dlls/ntdll/tests/time.c b/dlls/ntdll/tests/time.c
index 51d9115b87c..431d8cec8ca 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,107 @@ static void test_NtQueryPerformanceCounter(void)
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
}
+#if defined(__i386__) || defined(__x86_64__)
+
+struct hypervisor_shared_data
+{
+ UINT64 unknown;
+ UINT64 QpcMultiplier;
+ UINT64 QpcBias;
+};
+
+/* 128-bit multiply a by b and return the high 64 bits, same as __umulh */
+static UINT64 multiply_tsc(UINT64 a, UINT64 b)
+{
+ UINT64 ah = a >> 32, al = (UINT32)a, bh = b >> 32, bl = (UINT32)b, m;
+ m = (ah * bl) + (bh * al) + ((al * bl) >> 32);
+ return (ah * bh) + (m >> 32);
+}
+
+static void test_RtlQueryPerformanceCounter(void)
+{
+ struct hypervisor_shared_data *hsd;
+ KSHARED_USER_DATA *usd = (void *)0x7ffe0000;
+ LARGE_INTEGER frequency, counter;
+ NTSTATUS status;
+ UINT64 tsc0, tsc1;
+ 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 );
+
+ hsd = NULL;
+ status = pNtQuerySystemInformation( SystemHypervisorSharedPageInformation, &hsd, sizeof(void *), &len );
+ ok( !status, "NtQuerySystemInformation returned %x\n", status );
+ ok( len == sizeof(void *), "unexpected SystemHypervisorSharedPageInformation length %u\n", len );
+ ok( !!hsd, "unexpected SystemHypervisorSharedPageInformation address %p\n", hsd );
+
+ tsc0 = __rdtsc();
+ ret = pRtlQueryPerformanceCounter( &counter );
+ tsc1 = __rdtsc();
+ ok( ret, "RtlQueryPerformanceCounter failed\n" );
+
+ tsc0 = multiply_tsc(tsc0, hsd->QpcMultiplier) + hsd->QpcBias + usd->QpcBias;
+ tsc1 = multiply_tsc(tsc1, hsd->QpcMultiplier) + hsd->QpcBias + usd->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 );
+}
+#endif
+
static void test_RtlQueryTimeZoneInformation(void)
{
RTL_DYNAMIC_TIME_ZONE_INFORMATION tzinfo, tzinfo2;
@@ -266,6 +372,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 +382,7 @@ START_TEST(time)
test_NtQueryPerformanceCounter();
test_RtlQueryTimeZoneInformation();
test_user_shared_data_time();
+#if defined(__i386__) || defined(__x86_64__)
+ test_RtlQueryPerformanceCounter();
+#endif
}
diff --git a/include/winternl.h b/include/winternl.h
index d35d509eb41..fcdedaec8aa 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1551,6 +1551,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS {
SystemFileCacheInformationEx = 81,
SystemDynamicTimeZoneInformation = 102,
SystemLogicalProcessorInformationEx = 107,
+ SystemHypervisorSharedPageInformation = 197,
SystemInformationClassMax
} SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS;
More information about the wine-cvs
mailing list