Получение значений счетчиков производительности

В данной статье хочу показать, как можно получить значение счетчиков производительности вашего компьютера, при небольшой модификации кода можно так же получать значения счетчиков других машин.
Для получения значений использовалась библиотека PDH(Performance Data Helper) – основу которой составляет pdh.dll, которая предоставляет не очень удобный способ получения информации о производительности компонентов компьютера. В данной статье я рассматриваю пример, в котором получаю значение загруженности жестких дисков.
По началу мною были предприняты попытки получить загруженность жесткого диска при помощи API функции DeviceIoControl с применением параметра IOCTL_DISK_PERFORMANCE, к сожалению, в силу своей неопытности или ленивости мне это не удалось.
Примером реализации использования библиотеки PDH может служит программа раннее сделанная мною PDHMon, которую вы можете скачать по ссылке http://code.hut1.ru/downloads/PDHMon.zip, также в комплекте с операционной системой Windows имеется программа для просмотра и отображения значений счетчиков производительности, perfmon.msc.
Получение значений счетчиков производительности.

Далее представлен алгоритм получения значения счетчиков производительности, а именно загруженности жестких дисков, для создания программы использовалась среда разработки MVC++ 6, тип проекта Win32 Console Application.

1. Первое что необходимо сделать, это добавить в проект необходимые для работы библиотеки заголовочные файлы:
#include #include

2. Подключить lib файл к проекту: #pragma comment(lib, «pdh.lib»)

3. Вызвать функцию PdhOpenQuery, тем самым создать запрос на использование счетчиков производительности.

4. Для формирования пути к счетчику производительности использовать функцию PdhLookupPerfNameByIndex, которая при вызове с определенным индексом возвращает имя или объект счетчика. Сначала нужно получить имя объекта и сохранить его, после уже вторым вызовом получаем имя счетчика. Для того чтобы узнать какой индекс нам нужен я использовал утилиту PCViewer(автор программы Сергей Холодилов), которую можно найти на сайте http://www.rsdn.ru/ . Результат работы которой, представлен на рисунках, на которых можете увидеть, откуда брать значения индексов.
Получение индекса имени объекта при помощи PCViewer.
Получение индекса имени объекта при помощи PCViewer.

Получение индекса имени счетчика при помощи PCViewer.
Получение индекса имени счетчика при помощи PCViewer.

5. Далее заполняется структура PDH_COUNTER_PATH_ELEMENTS, где элементами структуры являются имя объекта(szObjectName), имя счетчика(szCounterName), имя машины(szMachineName) которое получаем при помощи вызова API функции GetComputerName.

6. Следующим шагом формируем полный путь к счетчику, при помощи функции PdhMakeCounterPath, одним из возвращаемых параметров которой будет полный путь к счетчику в формате: \\Computer\PerfObject(ParentInstance/ObjectInstance#InstanceIndex)\Counter

7. При помощи функции PdhAddCounter добавляем счетчик к нашему запросу сделанному в пункте 3.

8. После функцией PdhCollectQueryData соединяем все в одно целое.

9. И последний шаг, получаем форматированное значение счетчика функцией PdhGetFormattedCounterValue.

Исходный код программы:

#include <iostream.h>
#include <windows.h>
#include <pdh.h>
#include <PDHMsg.h>
 
#pragma comment(lib, "pdh.lib")
 
int main()
{
        PDH_HQUERY hQuery;
        CHAR szObjectName[256],szCounterName[256],szPath[256];
        PDH_STATUS pdhStatus;
        PDH_HCOUNTER * phCounter = (HCOUNTER*)GlobalAlloc(GPTR,sizeof(HCOUNTER));
 
 
 
        if(PdhOpenQuery(0,0,&hQuery) == ERROR_SUCCESS)
        {
                DWORD dwSize = sizeof(szObjectName);
                pdhStatus = PdhLookupPerfNameByIndex(NULL,234,szObjectName,&dwSize);//-1
                if(pdhStatus == ERROR_SUCCESS)
                {
 
                        /*CharToOem(szObjectName,szObjectName);*/ cout<<"PdhLookupPerfNameByIndex(1) -ok- "<<szObjectName<<endl;
                        dwSize = sizeof(szCounterName);
                        pdhStatus = PdhLookupPerfNameByIndex(NULL,200,szCounterName,&dwSize);//-2
 
                        if(pdhStatus == ERROR_SUCCESS)
                        {
                                /*CharToOem(szCounterName,szCounterName);*/cout<<"PdhLookupPerfNameByIndex(2) -ok- "<<szCounterName<<endl;
                                PDH_COUNTER_PATH_ELEMENTS pdh_elm;memset(&pdh_elm,0,sizeof(pdh_elm));
 
                                TCHAR szCompName[256];DWORD dwSize = sizeof(szCompName);
                                GetComputerName(szCompName,&dwSize); cout<<szCompName<<endl;
                                
                                pdh_elm.szMachineName    = szCompName;
                                pdh_elm.szObjectName     = szObjectName;
                                pdh_elm.szInstanceName   = "_Total";
                                pdh_elm.szParentInstance = NULL;
                                pdh_elm.dwInstanceIndex  = 0;
                                pdh_elm.szCounterName    = szCounterName;
 
                                dwSize = sizeof(szPath);
                                pdhStatus = PdhMakeCounterPath(&pdh_elm,szPath,&dwSize,0);
 
                                if(pdhStatus == ERROR_SUCCESS)
                                {
                                        /*CharToOem(szPath,szPath);*/ cout<<"PdhMakeCounterPath -ok- "<<szPath<<endl;
                                        
                                        pdhStatus = PdhAddCounter(hQuery,szPath,0,phCounter);
 
                                        if(pdhStatus == ERROR_SUCCESS)
                                        {
 
                                                cout<<"PdhAddCounter -ok-"<<endl;
                                                for(int i=0;i<10;i++)
                                                {
                                                        if(PdhCollectQueryData(hQuery) == ERROR_SUCCESS)
                                                        {
                                                                cout<<"PdhCollectQueryData -ok-"<<endl;
                                                                
                                                                PDH_FMT_COUNTERVALUE pdhValue;
                                                                DWORD dwType;
                                                                
                                                                pdhStatus = PdhGetFormattedCounterValue(*phCounter,PDH_FMT_DOUBLE,&dwType,&pdhValue);
                                                                if(pdhStatus == ERROR_SUCCESS)
                                                                {
                                                                        cout<<"PdhGetFormattedCounterValue -ok-"<<endl;
                                                                        cout<<pdhValue.doubleValue<<endl;
 
                                                                }else{cout<<"Error PdhGetFormattedCounterValue"<<endl;}
                                                
                                                        }
                                                        else{cout<<"Error PdhCollectQueryData"<<endl;}
                                                        
                                                        Sleep(500);
                                                }
                                        }else
                                        {
                                                cout<<"Error PdhAddCounter"<<endl;
                                                if(pdhStatus == PDH_INVALID_ARGUMENT){cout<<"PDH_INVALID_ARGUMENT"<<endl;}
                                                if(pdhStatus == PDH_CSTATUS_BAD_COUNTERNAME){cout<<"PDH_CSTATUS_BAD_COUNTERNAME"<<endl;}
                                                if(pdhStatus == PDH_CSTATUS_NO_COUNTER){cout<<"PDH_CSTATUS_NO_COUNTER"<<endl;}
                                                if(pdhStatus == PDH_CSTATUS_NO_COUNTERNAME){cout<<"PDH_CSTATUS_NO_COUNTERNAME"<<endl;}
                                                if(pdhStatus == PDH_CSTATUS_NO_MACHINE){cout<<"PDH_CSTATUS_NO_MACHINE"<<endl;}
                                                if(pdhStatus == PDH_CSTATUS_NO_OBJECT){cout<<"PDH_CSTATUS_NO_OBJECT"<<endl;}
                                                if(pdhStatus == PDH_FUNCTION_NOT_FOUND){cout<<"PDH_FUNCTION_NOT_FOUND"<<endl;}
                                                if(pdhStatus == PDH_INVALID_HANDLE){cout<<"PDH_INVALID_HANDLE"<<endl;}
                                                if(pdhStatus == PDH_MEMORY_ALLOCATION_FAILURE){cout<<"PDH_MEMORY_ALLOCATION_FAILURE"<<endl;}
                                        }
 
                                }else
                                {
                                        cout<<"Error PdhMakeCounterPath: "<<endl;
 
                                        if(pdhStatus == PDH_MORE_DATA){cout<<"PDH_MORE_DATA"<<endl;}
                                        if(pdhStatus == PDH_INVALID_ARGUMENT){cout<<"PDH_INVALID_ARGUMENT"<<endl;}
                                        
                                }
 
                        }else{cout<<"Error PdhLookupPerfNameByIndex - 2"<<endl;}
                }else
                {
                        cout<<"Error PdhLookupPerfNameByIndex - 1"<<endl;
                        if(pdhStatus == PDH_MORE_DATA){cout<<"PDH_MORE_DATA"<<endl;}
                        if(pdhStatus == PDH_INVALID_ARGUMENT){cout<<"PDH_INVALID_ARGUMENT"<<endl;}
                }
        }else{cout<<"Error PdhOpenQuery"<<endl;}
/*************************************************************************/
        
        GlobalFree(phCounter);
        PdhRemoveCounter(phCounter);
        PdhCloseQuery(hQuery);
 
        return 0;
}