/*++ 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[] = L"Groveler"; static DWORD first_counter; static DWORD first_help; static int open_count = 0; static SharedData *shared_data = NULL; 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 != NULL); HKEY path_key; _TCHAR perf_path[1024]; (void)StringCbPrintf(perf_path, sizeof(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) { RegCloseKey(path_key); 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) { RegCloseKey(path_key); return result; } ASSERT(path_key != 0); RegCloseKey(path_key); path_key = 0; } open_count++; return ERROR_SUCCESS; } extern "C" DWORD WINAPI CloseGrovelerPerformanceData() { ASSERT(open_count > 0); open_count--; if (open_count == 0) { ASSERT(shared_data != NULL); delete shared_data; shared_data = NULL; } 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); (void)StringCbPrintf(block->instance_name, sizeof(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); }