From: Paul Gofman pgofman@codeweavers.com
--- dlls/advapi32/advapi.c | 20 ++++++++++++++++ dlls/advapi32/advapi32.spec | 2 +- dlls/advapi32/tests/perf.c | 46 +++++++++++++++++++++++++++++++++++++ include/perflib.h | 10 ++++++++ 4 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/dlls/advapi32/advapi.c b/dlls/advapi32/advapi.c index ecef33561b8..6b3ffe2ea25 100644 --- a/dlls/advapi32/advapi.c +++ b/dlls/advapi32/advapi.c @@ -341,3 +341,23 @@ ULONG WINAPI PerfAddCounters( HANDLE query, PERF_COUNTER_IDENTIFIER *id, DWORD s id->Status = ERROR_WMI_GUID_NOT_FOUND; return ERROR_SUCCESS; } + +ULONG WINAPI PerfQueryCounterData( HANDLE query, PERF_DATA_HEADER *data, DWORD data_size, DWORD *size_needed ) +{ + FIXME( "query %p, data %p, data_size %lu, size_needed %p stub.\n", query, data, data_size, size_needed ); + + if (!size_needed) return ERROR_INVALID_PARAMETER; + + *size_needed = sizeof(PERF_DATA_HEADER); + + if (!data || data_size < sizeof(PERF_DATA_HEADER)) return ERROR_NOT_ENOUGH_MEMORY; + + data->dwTotalSize = sizeof(PERF_DATA_HEADER); + data->dwNumCounters = 0; + QueryPerformanceCounter( (LARGE_INTEGER *)&data->PerfTimeStamp ); + QueryPerformanceFrequency( (LARGE_INTEGER *)&data->PerfFreq ); + GetSystemTimeAsFileTime( (FILETIME *)&data->PerfTime100NSec ); + FileTimeToSystemTime( (FILETIME *)&data->PerfTime100NSec, &data->SystemTime ); + + return ERROR_SUCCESS; +} diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index 4009d33b5f8..b69186d07a7 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -565,7 +565,7 @@ # @ stub PerfIncrementULongCounterValue # @ stub PerfIncrementULongLongCounterValue @ stdcall PerfOpenQueryHandle(wstr ptr) -# @ stub PerfQueryCounterData +@ stdcall PerfQueryCounterData(long ptr long ptr) # @ stub PerfQueryCounterInfo # @ stub PerfQueryCounterSetRegistrationInfo # @ stub PerfQueryInstance diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index bc8d0a71702..34b6e952842 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -25,6 +25,7 @@ #include "winerror.h" #include "perflib.h" #include "winperf.h" +#include "winternl.h"
#include "wine/test.h"
@@ -34,6 +35,7 @@ DEFINE_FUNCTION(PerfCloseQueryHandle); DEFINE_FUNCTION(PerfOpenQueryHandle); DEFINE_FUNCTION(PerfAddCounters); +DEFINE_FUNCTION(PerfQueryCounterData); #undef DEFINE_FUNCTION
static void init_functions(void) @@ -44,6 +46,7 @@ static void init_functions(void) GET_FUNCTION(PerfCloseQueryHandle); GET_FUNCTION(PerfOpenQueryHandle); GET_FUNCTION(PerfAddCounters); + GET_FUNCTION(PerfQueryCounterData); #undef GET_FUNCTION }
@@ -209,11 +212,19 @@ void test_provider_init(void)
DEFINE_GUID(TestCounterGUID, 0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33);
+static ULONG64 trunc_nttime_ms(ULONG64 t) +{ + return (t / 10000) * 10000; +} + static void test_perf_counters(void) { + LARGE_INTEGER freq, qpc1, qpc2, nttime1, nttime2, systime; char buffer[sizeof(PERF_COUNTER_IDENTIFIER) + 8]; PERF_COUNTER_IDENTIFIER *counter_id; + PERF_DATA_HEADER dh; HANDLE query; + DWORD size; ULONG ret;
if (!pPerfOpenQueryHandle) @@ -244,6 +255,41 @@ static void test_perf_counters(void) ok(!ret, "got ret %lu.\n", ret); ok(counter_id->Status == ERROR_WMI_GUID_NOT_FOUND, "got Status %#lx.\n", counter_id->Status);
+ ret = pPerfQueryCounterData(query, NULL, 0, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got ret %lu.\n", ret); + + size = 0xdeadbeef; + ret = pPerfQueryCounterData(query, NULL, 0, &size); + ok(ret == ERROR_NOT_ENOUGH_MEMORY, "got ret %lu.\n", ret); + ok(size == sizeof(dh), "got size %lu.\n", size); + + ret = pPerfQueryCounterData(query, &dh, sizeof(dh), NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got ret %lu.\n", ret); + + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&qpc1); + NtQuerySystemTime(&nttime1); + + size = 0xdeadbeef; + ret = pPerfQueryCounterData(query, &dh, sizeof(dh), &size); + QueryPerformanceCounter(&qpc2); + NtQuerySystemTime(&nttime2); + SystemTimeToFileTime(&dh.SystemTime, (FILETIME *)&systime); + ok(!ret, "got ret %lu.\n", ret); + ok(size == sizeof(dh), "got size %lu.\n", size); + ok(dh.dwTotalSize == sizeof(dh), "got dwTotalSize %lu.\n", dh.dwTotalSize); + ok(!dh.dwNumCounters, "got dwNumCounters %lu.\n", dh.dwNumCounters); + ok(dh.PerfFreq == freq.QuadPart, "got PerfFreq %I64u.\n", dh.PerfFreq); + ok(dh.PerfTimeStamp >= qpc1.QuadPart && dh.PerfTimeStamp <= qpc2.QuadPart, + "got PerfTimeStamp %I64u, qpc1 %I64u, qpc2 %I64u.\n", + dh.PerfTimeStamp, qpc1.QuadPart, qpc2.QuadPart); + ok(dh.PerfTime100NSec >= nttime1.QuadPart && dh.PerfTime100NSec <= nttime2.QuadPart, + "got PerfTime100NSec %I64u, nttime1 %I64u, nttime2 %I64u.\n", + dh.PerfTime100NSec, nttime1.QuadPart, nttime2.QuadPart); + ok(systime.QuadPart >= trunc_nttime_ms(nttime1.QuadPart) && systime.QuadPart <= trunc_nttime_ms(nttime2.QuadPart), + "got systime %I64u, nttime1 %I64u, nttime2 %I64u, %d.\n", + systime.QuadPart, nttime1.QuadPart, nttime2.QuadPart, dh.SystemTime.wMilliseconds); + ret = pPerfCloseQueryHandle(query); ok(!ret, "got ret %lu.\n", ret); } diff --git a/include/perflib.h b/include/perflib.h index ef2b6c6d832..232ac308fce 100644 --- a/include/perflib.h +++ b/include/perflib.h @@ -94,6 +94,15 @@ typedef struct _PERF_COUNTER_IDENTIFIER { #define PERF_WILDCARD_COUNTER 0xFFFFFFFF #define PERF_WILDCARD_INSTANCE L"*"
+typedef struct _PERF_DATA_HEADER { + ULONG dwTotalSize; + ULONG dwNumCounters; + LONGLONG PerfTimeStamp; + LONGLONG PerfTime100NSec; + LONGLONG PerfFreq; + SYSTEMTIME SystemTime; +} PERF_DATA_HEADER, *PPERF_DATA_HEADER; + PERF_COUNTERSET_INSTANCE WINAPI *PerfCreateInstance(HANDLE, const GUID *, const WCHAR *, ULONG); ULONG WINAPI PerfDeleteInstance(HANDLE, PERF_COUNTERSET_INSTANCE *); ULONG WINAPI PerfSetCounterRefValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, void *); @@ -105,6 +114,7 @@ ULONG WINAPI PerfStopProvider(HANDLE); ULONG WINAPI PerfAddCounters(HANDLE, PERF_COUNTER_IDENTIFIER *, DWORD); ULONG WINAPI PerfCloseQueryHandle(HANDLE); ULONG WINAPI PerfOpenQueryHandle(const WCHAR *, HANDLE *); +ULONG WINAPI PerfQueryCounterData(HANDLE, PERF_DATA_HEADER *, DWORD, DWORD *);
#ifdef __cplusplus } /* extern "C" */