The followings will help:
How to obtain information about CPU, RAM, GPU
I have been making a small tool recently
One of the functions requires obtaining the current CPU, RAM, GPU usage rate of the system
How can I currently obtain the usage rate of CPU, RAM, and GPU? Are there any APIs available?
My tool is compatible with Windows versions currently supported by Microsoft
Windows API - Win32
2 answers
Sort by: Most helpful
-
-
Castorix31 90,191 Reputation points
2025-06-09T14:12:53.8+00:00 PDH return 0 on my PC for GPU (Intel HD GPU)
But other APIs can be used, like D3DKMTQueryStatistics (+ GlobalMemoryStatusEx and GetSystemTimes)
I asked ChatGPT to generate a Win32 app to format results and call APIs in a thread on a Button click, which seem correct on my Windows 10 OS (if I compare with Task Manager) =>
#include <windows.h> #include <psapi.h> #include <dxgi1_4.h> #include <thread> #include <string> #include <chrono> #include <sstream> #include <iostream> #pragma comment(lib, "pdh.lib") #pragma comment(lib, "dxgi.lib") #pragma comment(lib, "user32.lib") #pragma comment(lib, "gdi32.lib") #include <d3dkmthk.h> HWND hWnd; bool m_bRunning = false; LUID m_AdapterLuid = { 0, 0 }; LUID GetAdapterLuid() { IDXGIFactory1* factory; CreateDXGIFactory1(IID_PPV_ARGS(&factory)); IDXGIAdapter1* adapter; factory->EnumAdapters1(0, &adapter); // 0 = first adapter DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); return desc.AdapterLuid; } ULONGLONG prevTime = 0; float GetGPUUsage() { double usage = 0; D3DKMT_QUERYSTATISTICS stats = {}; stats.Type = D3DKMT_QUERYSTATISTICS_NODE; stats.AdapterLuid = m_AdapterLuid; stats.QueryNode.NodeId = 0; // Node index, usually 0 for GPU NTSTATUS status = D3DKMTQueryStatistics(&stats); if (status == 0) { ULONGLONG newTime = stats.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart; if (prevTime != 0) { ULONGLONG delta = newTime - prevTime; usage = (double)delta / 10000000.0 * 100.0; } prevTime = newTime; return usage; } else { OutputDebugString(L"Failed to query D3DKMT statistics\n"); return -1; } } void Log(const std::wstring& label, float value) { std::wstringstream ss; ss << label << L": " << value << L"%\n"; OutputDebugString(ss.str().c_str()); } float GetCPUUsage() { static ULARGE_INTEGER lastIdleTime = {}, lastKernelTime = {}, lastUserTime = {}; FILETIME idleTime, kernelTime, userTime; if (!GetSystemTimes(&idleTime, &kernelTime, &userTime)) return 0.0f; ULARGE_INTEGER idle, kernel, user; idle.LowPart = idleTime.dwLowDateTime; idle.HighPart = idleTime.dwHighDateTime; kernel.LowPart = kernelTime.dwLowDateTime; kernel.HighPart = kernelTime.dwHighDateTime; user.LowPart = userTime.dwLowDateTime; user.HighPart = userTime.dwHighDateTime; ULONGLONG sysIdleDiff = idle.QuadPart - lastIdleTime.QuadPart; ULONGLONG sysKernelDiff = kernel.QuadPart - lastKernelTime.QuadPart; ULONGLONG sysUserDiff = user.QuadPart - lastUserTime.QuadPart; lastIdleTime = idle; lastKernelTime = kernel; lastUserTime = user; ULONGLONG sysTotal = sysKernelDiff + sysUserDiff; if (sysTotal == 0) return 0.0f; // Normalize to percent of total logical cores SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); int numProcs = sysInfo.dwNumberOfProcessors; double cpuUsage = 100.0 * (1.0 - (double)sysIdleDiff / sysTotal); cpuUsage /= numProcs; // Normalize // Clamp to 0-100% if (cpuUsage < 0.0) cpuUsage = 0.0; if (cpuUsage > 100.0) cpuUsage = 100.0; return static_cast<float>(cpuUsage); } float GetMemoryUsage() { MEMORYSTATUSEX memStatus = { sizeof(memStatus) }; if (GlobalMemoryStatusEx(&memStatus)) return (float)memStatus.dwMemoryLoad; return 0.0f; } void MonitorThread() { while (m_bRunning) { float cpu = GetCPUUsage(); float mem = GetMemoryUsage(); float gpu = GetGPUUsage(); Log(L"CPU", cpu); Log(L"Memory", mem); Log(L"GPU", gpu); OutputDebugString(L"\r\n"); std::this_thread::sleep_for(std::chrono::seconds(1)); } } void StartMonitoring() { if (!m_bRunning) { m_bRunning = true; std::thread(MonitorThread).detach(); } } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: m_bRunning = false; PostQuitMessage(0); break; case WM_COMMAND: if (LOWORD(wParam) == 1) { m_AdapterLuid = GetAdapterLuid(); if (m_AdapterLuid.LowPart != 0 || m_AdapterLuid.HighPart != 0) StartMonitoring(); } break; } return DefWindowProc(hwnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) { const wchar_t CLASS_NAME[] = L"PerfMonitorWindow"; WNDCLASS wc = {}; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); hWnd = CreateWindowEx(0, CLASS_NAME, L"Win32 Perf Monitor", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 150, nullptr, nullptr, hInstance, nullptr); CreateWindow(L"BUTTON", L"Start Monitor", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 50, 50, 180, 30, hWnd, (HMENU)1, hInstance, nullptr); ShowWindow(hWnd, nCmdShow); MSG msg = {}; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }