285 lines
7.4 KiB
C++
285 lines
7.4 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
grovperf.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
SIS Groveler performance DLL main file
|
||
|
|
||
|
Authors:
|
||
|
|
||
|
John Douceur, 1998
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
User Mode
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "all.hxx"
|
||
|
|
||
|
static _TCHAR *service_name = _T("Groveler");
|
||
|
|
||
|
static DWORD first_counter;
|
||
|
static DWORD first_help;
|
||
|
static int open_count = 0;
|
||
|
|
||
|
static SharedData *shared_data;
|
||
|
|
||
|
static const int ms_per_100ns_inv = 10000;
|
||
|
|
||
|
static __int64 total_counter[num_perf_counters];
|
||
|
|
||
|
extern "C" DWORD CALLBACK OpenGrovelerPerformanceData(LPWSTR lpDeviceNames)
|
||
|
{
|
||
|
if (open_count == 0)
|
||
|
{
|
||
|
shared_data = new SharedData;
|
||
|
ASSERT(shared_data != 0);
|
||
|
HKEY path_key;
|
||
|
_TCHAR perf_path[1024];
|
||
|
_stprintf(perf_path,
|
||
|
_T("SYSTEM\\CurrentControlSet\\Services\\%s\\Performance"),
|
||
|
service_name);
|
||
|
long result =
|
||
|
RegOpenKeyEx(HKEY_LOCAL_MACHINE, perf_path, 0, KEY_READ, &path_key);
|
||
|
ASSERT_PRINTF(result == ERROR_SUCCESS, (_T("error = %d\n"), result));
|
||
|
if (result != ERROR_SUCCESS)
|
||
|
{
|
||
|
return result;
|
||
|
}
|
||
|
ASSERT(path_key != 0);
|
||
|
first_counter = 0;
|
||
|
DWORD ctr_size = sizeof(DWORD);
|
||
|
result = RegQueryValueEx(path_key, _T("First Counter"), 0, 0,
|
||
|
(BYTE *)&first_counter, &ctr_size);
|
||
|
ASSERT_PRINTF(result == ERROR_SUCCESS, (_T("error = %d\n"), result));
|
||
|
if (result != ERROR_SUCCESS)
|
||
|
{
|
||
|
return result;
|
||
|
}
|
||
|
first_help = 0;
|
||
|
ctr_size = sizeof(DWORD);
|
||
|
result = RegQueryValueEx(path_key, _T("First Help"), 0, 0,
|
||
|
(BYTE *)&first_help, &ctr_size);
|
||
|
ASSERT_PRINTF(result == ERROR_SUCCESS, (_T("error = %d\n"), result));
|
||
|
if (result != ERROR_SUCCESS)
|
||
|
{
|
||
|
return result;
|
||
|
}
|
||
|
ASSERT(path_key != 0);
|
||
|
RegCloseKey(path_key);
|
||
|
path_key = 0;
|
||
|
}
|
||
|
open_count++;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
extern "C" DWORD WINAPI CloseGrovelerPerformanceData()
|
||
|
{
|
||
|
open_count--;
|
||
|
if (open_count == 0)
|
||
|
{
|
||
|
ASSERT(shared_data != 0);
|
||
|
delete shared_data;
|
||
|
shared_data = 0;
|
||
|
}
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
extern "C" DWORD WINAPI CollectGrovelerPerformanceData(
|
||
|
LPWSTR lpwszValue,
|
||
|
LPVOID *lppData,
|
||
|
LPDWORD lpcbBytes,
|
||
|
LPDWORD lpcObjectTypes)
|
||
|
{
|
||
|
if (open_count == 0)
|
||
|
{
|
||
|
*lpcbBytes = 0;
|
||
|
*lpcObjectTypes = 0;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
int num_partitions;
|
||
|
SharedDataRecord records[max_shared_data_records];
|
||
|
bool ok = shared_data->extract_values(&num_partitions, records);
|
||
|
if (!ok)
|
||
|
{
|
||
|
*lpcbBytes = 0;
|
||
|
*lpcObjectTypes = 0;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
int data_size = space_needed_for_data(num_partitions);
|
||
|
if (data_size > int(*lpcbBytes))
|
||
|
{
|
||
|
*lpcbBytes = 0;
|
||
|
*lpcObjectTypes = 0;
|
||
|
return ERROR_MORE_DATA;
|
||
|
}
|
||
|
build_part_object_info_block(lppData, num_partitions, data_size);
|
||
|
for (int index = 0; index < num_partitions; index++)
|
||
|
{
|
||
|
build_part_instance_info_block(lppData, index, records);
|
||
|
}
|
||
|
if (num_partitions > 0)
|
||
|
{
|
||
|
build_total_instance_info_block(lppData, num_partitions, records);
|
||
|
}
|
||
|
*lpcbBytes = data_size;
|
||
|
*lpcObjectTypes = 1;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int space_needed_for_data(
|
||
|
int num_partitions)
|
||
|
{
|
||
|
if (num_partitions > 0)
|
||
|
{
|
||
|
return sizeof(PartitionObjectInformationBlock) +
|
||
|
num_partitions * sizeof(PartitionInstanceInformationBlock) +
|
||
|
sizeof(TotalInstanceInformationBlock);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return sizeof(PartitionObjectInformationBlock);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void build_part_object_info_block(
|
||
|
LPVOID *lppData,
|
||
|
int num_partitions,
|
||
|
int data_size)
|
||
|
{
|
||
|
int num_instances = 0;
|
||
|
if (num_partitions > 0)
|
||
|
{
|
||
|
num_instances = num_partitions + 1;
|
||
|
}
|
||
|
PartitionObjectInformationBlock *block =
|
||
|
(PartitionObjectInformationBlock *)*lppData;
|
||
|
block->object_type.TotalByteLength = data_size;
|
||
|
block->object_type.DefinitionLength =
|
||
|
sizeof(PartitionObjectInformationBlock);
|
||
|
block->object_type.HeaderLength = sizeof(PERF_OBJECT_TYPE);
|
||
|
block->object_type.ObjectNameTitleIndex = first_counter;
|
||
|
block->object_type.ObjectNameTitle = 0;
|
||
|
block->object_type.ObjectHelpTitleIndex = first_help;
|
||
|
block->object_type.ObjectHelpTitle = 0;
|
||
|
block->object_type.DetailLevel = object_info.detail_level;
|
||
|
block->object_type.NumCounters = num_perf_counters;
|
||
|
block->object_type.DefaultCounter = 0;
|
||
|
block->object_type.NumInstances = num_instances;
|
||
|
block->object_type.CodePage = 0;
|
||
|
for (int index = 0; index < num_perf_counters; index++)
|
||
|
{
|
||
|
block->definition[index].ByteLength = sizeof(PERF_COUNTER_DEFINITION);
|
||
|
block->definition[index].CounterNameTitleIndex =
|
||
|
first_counter + 2 * (index + 1);
|
||
|
block->definition[index].CounterNameTitle = 0;
|
||
|
block->definition[index].CounterHelpTitleIndex =
|
||
|
first_help + 2 * (index + 1);
|
||
|
block->definition[index].CounterHelpTitle = 0;
|
||
|
block->definition[index].DefaultScale = 0;
|
||
|
block->definition[index].DetailLevel = counter_info[index].detail_level;
|
||
|
block->definition[index].CounterType = counter_info[index].counter_type;
|
||
|
block->definition[index].CounterSize = sizeof(LARGE_INTEGER);
|
||
|
block->definition[index].CounterOffset =
|
||
|
FIELD_OFFSET( PartitionData, counter[index] );
|
||
|
}
|
||
|
*lppData = (void *)(block + 1);
|
||
|
}
|
||
|
|
||
|
void build_part_instance_info_block(
|
||
|
LPVOID *lppData,
|
||
|
int partition_index,
|
||
|
SharedDataRecord *records)
|
||
|
{
|
||
|
PartitionInstanceInformationBlock *block =
|
||
|
(PartitionInstanceInformationBlock *)*lppData;
|
||
|
block->instance_def.ByteLength =
|
||
|
FIELD_OFFSET(PartitionInstanceInformationBlock, partition_data);
|
||
|
block->instance_def.ParentObjectTitleIndex = 0;
|
||
|
block->instance_def.ParentObjectInstance = 0;
|
||
|
block->instance_def.UniqueID = PERF_NO_UNIQUE_ID;
|
||
|
block->instance_def.NameOffset =
|
||
|
FIELD_OFFSET(PartitionInstanceInformationBlock, instance_name);
|
||
|
block->instance_def.NameLength =
|
||
|
sizeof(_TCHAR) * (partition_name_length);
|
||
|
|
||
|
_stprintf(block->instance_name, _T("%-.*s"),
|
||
|
partition_name_length,
|
||
|
records[partition_index].driveName);
|
||
|
|
||
|
|
||
|
block->partition_data.counter_block.ByteLength = sizeof(PartitionData);
|
||
|
for (int index = 0; index < num_perf_counters; index++)
|
||
|
{
|
||
|
switch (counter_info[index].counter_type)
|
||
|
{
|
||
|
case PERF_100NSEC_TIMER:
|
||
|
block->partition_data.counter[index].QuadPart = ms_per_100ns_inv *
|
||
|
records[partition_index].fields[counter_info[index].source];
|
||
|
break;
|
||
|
default:
|
||
|
block->partition_data.counter[index].QuadPart =
|
||
|
records[partition_index].fields[counter_info[index].source];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
*lppData = (void *)(block + 1);
|
||
|
}
|
||
|
|
||
|
void build_total_instance_info_block(
|
||
|
LPVOID *lppData,
|
||
|
int num_partitions,
|
||
|
SharedDataRecord *records)
|
||
|
{
|
||
|
TotalInstanceInformationBlock *block =
|
||
|
(TotalInstanceInformationBlock *)*lppData;
|
||
|
block->instance_def.ByteLength =
|
||
|
FIELD_OFFSET(TotalInstanceInformationBlock, partition_data);
|
||
|
block->instance_def.ParentObjectTitleIndex = 0;
|
||
|
block->instance_def.ParentObjectInstance = 0;
|
||
|
block->instance_def.UniqueID = PERF_NO_UNIQUE_ID;
|
||
|
block->instance_def.NameOffset =
|
||
|
FIELD_OFFSET(TotalInstanceInformationBlock, instance_name);
|
||
|
block->instance_def.NameLength =
|
||
|
sizeof(_TCHAR) * (total_name_length);
|
||
|
_tcscpy(block->instance_name, _T("_Total"));
|
||
|
block->partition_data.counter_block.ByteLength = sizeof(PartitionData);
|
||
|
for (int index = 0; index < num_perf_counters; index++)
|
||
|
{
|
||
|
total_counter[index] = 0;
|
||
|
}
|
||
|
for (int part = 0; part < num_partitions; part++)
|
||
|
{
|
||
|
for (index = 0; index < num_perf_counters; index++)
|
||
|
{
|
||
|
total_counter[index] +=
|
||
|
records[part].fields[counter_info[index].source];
|
||
|
}
|
||
|
}
|
||
|
for (index = 0; index < num_perf_counters; index++)
|
||
|
{
|
||
|
switch (counter_info[index].counter_type)
|
||
|
{
|
||
|
case PERF_100NSEC_TIMER:
|
||
|
block->partition_data.counter[index].QuadPart =
|
||
|
ms_per_100ns_inv * total_counter[index];
|
||
|
break;
|
||
|
default:
|
||
|
block->partition_data.counter[index].QuadPart =
|
||
|
total_counter[index];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
*lppData = (void *)(block + 1);
|
||
|
}
|