#cpp #windows #3d #gpu
Необходимо при запуске 3д приложения выполнять код. Думал ставить хуки на создание окон d3d и opengl, но потом увидел в диспетчере вот такое Подскажите функцию или пример, как можно вынуть данную информацию.
Ответы
Ответ 1
Функциональность просмотра информации о работе GPU в диспетчере - новинка Windows 10 (подробнее). Для того, чтобы она работала, необходим графический адаптер с поддержкой WDDM 2.0. Информация берется, по-видимому, из специального счетчика производительности "GPU Engine", который имеет для каждого процесса, использующего графику, несколько экземпляров с именем вида: pid_5036_luid_0x00000000_0x00009F54_phys_0_eng_3_engtype_3D Из этой строки можно извлечь информацию о том, к какому процессу и графическому движку он относится. У счетчика два значения, Utilization Percentage и Running time. Utilization Percentage у меня почему-то всегда нулевое, наверное, самый простой способ найти процессы, использующие 3D-графику - это отфильтровать те, у которых Running time больше нуля. Для работы со счетчиками производительности можно использовать WMI или PDH-функции. Пример вывода процессов, использующих 3D Engine, с помощью PDH-функций: #define WIN32_LEAN_AND_MEAN 1 #include#include #include #include #include //для работы со счетчиками производительности: #include #include #pragma comment(lib, "pdh.lib") //для получения информации о процессах: #include "psapi.h" #include "Shlwapi.h" #pragma comment(lib, "Shlwapi.lib") const PWSTR COUNTER_OBJECT = L"GPU Engine"; //Имя счетчика производительности /*Вывод имени процесса по его PID*/ void PrintProcessName(int pid){ HANDLE hProcess; DWORD charsCarried=0; TCHAR PrName[MAX_PATH]=L""; hProcess= OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,pid); if (hProcess) { charsCarried=MAX_PATH; if (QueryFullProcessImageName(hProcess,0,PrName,&charsCarried)==0){ StringCchCopy(PrName,MAX_PATH,L"Unknown process"); } CloseHandle(hProcess); } else StringCchCopy(PrName,MAX_PATH,L"Unknown process"); PathStripPath(PrName); wprintf(L"%s",PrName); } void main(void) { PDH_STATUS status = ERROR_SUCCESS; LPWSTR pwsCounterListBuffer = NULL; DWORD dwCounterListSize = 0; LPWSTR pwsInstanceListBuffer = NULL; DWORD dwInstanceListSize = 0; LPWSTR pTemp = NULL; HQUERY hQuery = NULL; HCOUNTER hCounter = NULL; DWORD dwFormat = PDH_FMT_LONG; PDH_FMT_COUNTERVALUE ItemBuffer; wchar_t buffer[1000]; wchar_t * p; // Determine the required buffer size for the data. status = PdhEnumObjectItems( NULL, // real-time source NULL, // local machine COUNTER_OBJECT, // object to enumerate pwsCounterListBuffer, // pass NULL and 0 &dwCounterListSize, // to get required buffer size pwsInstanceListBuffer, &dwInstanceListSize, PERF_DETAIL_WIZARD, // counter detail level 0); if (status == PDH_MORE_DATA) { // Allocate the buffers and try the call again. pwsCounterListBuffer = (LPWSTR)malloc(dwCounterListSize * sizeof(WCHAR)); pwsInstanceListBuffer = (LPWSTR)malloc(dwInstanceListSize * sizeof(WCHAR)); if (NULL != pwsCounterListBuffer && NULL != pwsInstanceListBuffer) { status = PdhEnumObjectItems( NULL, // real-time source NULL, // local machine COUNTER_OBJECT, // object to enumerate pwsCounterListBuffer, &dwCounterListSize, pwsInstanceListBuffer, &dwInstanceListSize, PERF_DETAIL_WIZARD, // counter detail level 0); if (status == ERROR_SUCCESS) { wprintf(L"\nProcesses using 3D engine:\n\n"); // Walk the instance list. The list can contain one // or more null-terminated strings. The list is terminated // using two null-terminator characters. for (pTemp = pwsInstanceListBuffer; *pTemp != 0; pTemp += wcslen(pTemp) + 1) { p = wcsstr(pTemp,L"engtype_3D"); if(p==NULL)continue;//отфильтровать записи, не относящиеся к 3D Engine //построим путь к запрашиваемому значению счетчика... StringCchCopy(buffer,1000,L"\\GPU Engine("); StringCchCat(buffer,1000,pTemp); StringCchCat(buffer,1000,L")\\Running time"); //создадим запрос... status = PdhOpenQuery(NULL, 0, &hQuery); if (ERROR_SUCCESS != status) { wprintf(L"PdhOpenQuery failed with 0x%x\n", status); continue; } //добавим счетчик в запрос... status = PdhAddCounter(hQuery, buffer, 0, &hCounter); if (ERROR_SUCCESS != status) { wprintf(L"PdhAddCounter failed with 0x%x\n", status); continue; } //получаем данные... status = PdhCollectQueryData(hQuery); if (ERROR_SUCCESS != status) { wprintf(L"PdhCollectQueryData failed with 0x%x\n", status); continue; } status = PdhCollectQueryData(hQuery); if (ERROR_SUCCESS != status) { wprintf(L"PdhCollectQueryData failed with 0x%x\n", status); continue; } // Format the performance data record. status = PdhGetFormattedCounterValue(hCounter, dwFormat,(LPDWORD)NULL,&ItemBuffer); if (ERROR_SUCCESS != status) { wprintf(L"PdhGetFormattedCounterValue failed with 0x%x\n", status); continue; } int pid=0; //выведем информацию о процессе, если Running time > 0 if(ItemBuffer.longValue > 0){ swscanf(pTemp,L"pid_%d",&pid); //парсим PID из имени счетчика PrintProcessName(pid); wprintf(L", PID: %d - ", pid); wprintf(L"Usage time: %d\n",(int)ItemBuffer.longValue); } PdhCloseQuery(hQuery); } } else { wprintf(L"Second PdhEnumObjectItems failed with %0x%x.\n", status); } } else { wprintf(L"Unable to allocate buffers.\n"); status = ERROR_OUTOFMEMORY; } } else { wprintf(L"\nPdhEnumObjectItems failed with 0x%x.\n", status); } if (pwsCounterListBuffer != NULL) free (pwsCounterListBuffer); if (pwsInstanceListBuffer != NULL) free (pwsInstanceListBuffer); system("PAUSE"); } На системах до Windows 10 (или если нет поддержки данной функциональности у адаптера, и, как следствие - нет этого счетчика), можно использовать функцию EnumProcessModules для получения загруженных DLL процесса. Если среди них есть библиотеки Direct 3D - d3d9.dll, d3d10.dll, d3d11.dll и т.п., можно считать, что процесс использует 3D-графику.
Комментариев нет:
Отправить комментарий