diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index 34fedd2b645..d76d6ddd44a 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winerror.h" #include "perflib.h" +#include "winperf.h" #include "wine/test.h" @@ -35,7 +36,20 @@ static ULONG WINAPI test_provider_callback(ULONG code, void *buffer, ULONG size) void test_provider_init(void) { + static GUID test_set_guid = {0xdeadbeef, 0x0002, 0x0003, {0x0f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; + static GUID test_set_guid2 = {0xdeadbeef, 0x0003, 0x0003, {0x0f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; static GUID test_guid = {0xdeadbeef, 0x0001, 0x0002, {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; + static struct + { + PERF_COUNTERSET_INFO counterset; + PERF_COUNTER_INFO counter; + } + pc_template = + { + {{0}}, + {1, PERF_COUNTER_COUNTER, PERF_ATTRIB_BY_REFERENCE, sizeof(PERF_COUNTER_INFO), PERF_DETAIL_NOVICE, 0, 0}, + }; + PERF_PROVIDER_CONTEXT prov_context; HANDLE prov, prov2; ULONG ret; @@ -76,6 +90,31 @@ void test_provider_init(void) bret = IsBadWritePtr(prov, 8); ok(!bret, "Handle does not point to the data.\n"); + pc_template.counterset.CounterSetGuid = test_set_guid; + pc_template.counterset.ProviderGuid = test_guid; + pc_template.counterset.NumCounters = 0; + pc_template.counterset.InstanceType = PERF_COUNTERSET_SINGLE_INSTANCE; + ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template.counterset)); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + pc_template.counterset.CounterSetGuid = test_set_guid; + pc_template.counterset.ProviderGuid = test_guid; + pc_template.counterset.NumCounters = 1; + pc_template.counterset.InstanceType = PERF_COUNTERSET_SINGLE_INSTANCE; + ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template)); + ok(!ret, "Got unexpected ret %u.\n", ret); + + pc_template.counterset.CounterSetGuid = test_set_guid2; + /* Looks like ProviderGuid doesn't need to match provider. */ + pc_template.counterset.ProviderGuid = test_set_guid; + pc_template.counterset.NumCounters = 1; + pc_template.counterset.InstanceType = PERF_COUNTERSET_SINGLE_INSTANCE; + ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template)); + ok(!ret, "Got unexpected ret %u.\n", ret); + + ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template)); + ok(ret == ERROR_ALREADY_EXISTS, "Got unexpected ret %u.\n", ret); + ret = PerfStopProvider(prov); ok(!ret, "Got unexpected ret %u.\n", ret); diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index d468c84f619..403c0cf6cd2 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -154,10 +154,18 @@ LONG WINAPI AppPolicyGetWindowingModel(HANDLE token, AppPolicyWindowingModel *po return ERROR_SUCCESS; } +struct counterset_template +{ + PERF_COUNTERSET_INFO counterset; + PERF_COUNTER_INFO counter[1]; +}; + struct perf_provider { GUID guid; PERFLIBREQUEST callback; + struct counterset_template **countersets; + unsigned int counterset_count; }; static struct perf_provider *perf_provider_from_handle(HANDLE prov) @@ -187,10 +195,44 @@ ULONG WINAPI PerfDeleteInstance(HANDLE provider, PPERF_COUNTERSET_INSTANCE block /*********************************************************************** * PerfSetCounterSetInfo (KERNELBASE.@) */ -ULONG WINAPI PerfSetCounterSetInfo(HANDLE handle, PPERF_COUNTERSET_INFO template, ULONG size) +ULONG WINAPI PerfSetCounterSetInfo( HANDLE handle, PERF_COUNTERSET_INFO *template, ULONG size ) { - FIXME("%p %p %u: stub\n", handle, template, size); - return ERROR_CALL_NOT_IMPLEMENTED; + struct perf_provider *prov = perf_provider_from_handle( handle ); + struct counterset_template **new_array; + struct counterset_template *new; + unsigned int i; + + FIXME( "handle %p, template %p, size %u semi-stub.\n", handle, template, size ); + + if (!prov || !template) return ERROR_INVALID_PARAMETER; + if (!template->NumCounters) return ERROR_INVALID_PARAMETER; + if (size < sizeof(*template) || (size - (sizeof(*template))) / sizeof(PERF_COUNTER_INFO) < template->NumCounters) + return ERROR_INVALID_PARAMETER; + + for (i = 0; i < prov->counterset_count; ++i) + { + if (IsEqualGUID( &template->CounterSetGuid, &prov->countersets[i]->counterset.CounterSetGuid )) + return ERROR_ALREADY_EXISTS; + } + + size = offsetof( struct counterset_template, counter[template->NumCounters] ); + if (!(new = heap_alloc( size ))) return ERROR_OUTOFMEMORY; + + if (prov->counterset_count) + new_array = heap_realloc( prov->countersets, sizeof(*prov->countersets) * (prov->counterset_count + 1) ); + else + new_array = heap_alloc( sizeof(*prov->countersets) ); + + if (!new_array) + { + heap_free( new ); + return ERROR_OUTOFMEMORY; + } + memcpy( new, template, size ); + new_array[prov->counterset_count++] = new; + prov->countersets = new_array; + + return STATUS_SUCCESS; } /*********************************************************************** @@ -245,9 +287,13 @@ ULONG WINAPI PerfStartProviderEx( GUID *guid, PERF_PROVIDER_CONTEXT *context, HA ULONG WINAPI PerfStopProvider(HANDLE handle) { struct perf_provider *prov = perf_provider_from_handle( handle ); + unsigned int i; TRACE( "handle %p.\n", handle ); + for (i = 0; i < prov->counterset_count; ++i) + heap_free( prov->countersets[i] ); + heap_free( prov->countersets ); heap_free( prov ); return STATUS_SUCCESS; } diff --git a/include/perflib.h b/include/perflib.h index 47bc0716541..5a2a1162ae7 100644 --- a/include/perflib.h +++ b/include/perflib.h @@ -34,6 +34,19 @@ typedef struct _PERF_COUNTERSET_INFO { ULONG InstanceType; } PERF_COUNTERSET_INFO, * PPERF_COUNTERSET_INFO; +/* PERF_COUNTERSET_INFO InstanceType values. */ +#define PERF_COUNTERSET_FLAG_MULTIPLE 0x00000002 +#define PERF_COUNTERSET_FLAG_AGGREGATE 0x00000004 +#define PERF_COUNTERSET_FLAG_HISTORY 0x00000008 +#define PERF_COUNTERSET_FLAG_INSTANCE 0x00000010 + +#define PERF_COUNTERSET_SINGLE_INSTANCE 0 +#define PERF_COUNTERSET_MULTI_INSTANCES PERF_COUNTERSET_FLAG_MULTIPLE +#define PERF_COUNTERSET_SINGLE_AGGREGATE PERF_COUNTERSET_FLAG_AGGREGATE +#define PERF_COUNTERSET_MULTI_AGGREGATE (PERF_COUNTERSET_FLAG_AGGREGATE | PERF_COUNTERSET_FLAG_MULTIPLE) +#define PERF_COUNTERSET_SINGLE_AGGREGATE_HISTORY (PERF_COUNTERSET_FLAG_HISTORY | PERF_COUNTERSET_SINGLE_AGGREGATE) +#define PERF_COUNTERSET_INSTANCE_AGGREGATE (PERF_COUNTERSET_MULTI_AGGREGATE | PERF_COUNTERSET_FLAG_INSTANCE) + typedef struct _PERF_COUNTERSET_INSTANCE { GUID CounterSetGuid; ULONG dwSize; @@ -42,6 +55,23 @@ typedef struct _PERF_COUNTERSET_INSTANCE { ULONG InstanceNameSize; } PERF_COUNTERSET_INSTANCE, * PPERF_COUNTERSET_INSTANCE; +typedef struct _PERF_COUNTER_INFO { + ULONG CounterId; + ULONG Type; + ULONGLONG Attrib; + ULONG Size; + ULONG DetailLevel; + LONG Scale; + ULONG Offset; +} PERF_COUNTER_INFO, *PPERF_COUNTER_INFO; + +/* PERF_COUNTER_INFO Attrib flags. */ +#define PERF_ATTRIB_BY_REFERENCE 0x00000001 +#define PERF_ATTRIB_NO_DISPLAYABLE 0x00000002 +#define PERF_ATTRIB_NO_GROUP_SEPARATOR 0x00000004 +#define PERF_ATTRIB_DISPLAY_AS_REAL 0x00000008 +#define PERF_ATTRIB_DISPLAY_AS_HEX 0x00000010 + typedef struct _PROVIDER_CONTEXT { DWORD ContextSize; DWORD Reserved; @@ -51,6 +81,7 @@ typedef struct _PROVIDER_CONTEXT { LPVOID pMemContext; } PERF_PROVIDER_CONTEXT, * PPERF_PROVIDER_CONTEXT; +ULONG WINAPI PerfSetCounterSetInfo(HANDLE, PERF_COUNTERSET_INFO *, ULONG); ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *); ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *); ULONG WINAPI PerfStopProvider(HANDLE); diff --git a/include/winperf.h b/include/winperf.h index 113bfbae40f..926da8f8c4a 100644 --- a/include/winperf.h +++ b/include/winperf.h @@ -161,6 +161,35 @@ typedef struct _PERF_COUNTER_BLOCK DWORD ByteLength; } PERF_COUNTER_BLOCK, *PPERF_COUNTER_BLOCK; +#define PERF_COUNTER_VALUE 0x00000000 +#define PERF_COUNTER_RATE 0x00010000 +#define PERF_COUNTER_FRACTION 0x00020000 +#define PERF_COUNTER_BASE 0x00030000 +#define PERF_COUNTER_ELAPSED 0x00040000 +#define PERF_COUNTER_QUEUELEN 0x00050000 +#define PERF_COUNTER_HISTOGRAM 0x00060000 +#define PERF_COUNTER_PRECISION 0x00070000 + +#define PERF_TEXT_UNICODE 0x00000000 +#define PERF_TEXT_ASCII 0x00010000 + +#define PERF_TIMER_TICK 0x00000000 +#define PERF_TIMER_100NS 0x00100000 +#define PERF_OBJECT_TIMER 0x00200000 + +#define PERF_DELTA_COUNTER 0x00400000 +#define PERF_DELTA_BASE 0x00800000 +#define PERF_INVERSE_COUNTER 0x01000000 +#define PERF_MULTI_COUNTER 0x02000000 + +#define PERF_DISPLAY_NO_SUFFIX 0x00000000 +#define PERF_DISPLAY_PER_SEC 0x10000000 +#define PERF_DISPLAY_PERCENT 0x20000000 +#define PERF_DISPLAY_SECONDS 0x30000000 +#define PERF_DISPLAY_NOSHOW 0x40000000 + +#define PERF_COUNTER_COUNTER (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | \ + PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC) #include