CallNtPowerInformation获取ProcessorInformation返回错误CPU频率原因咨询
CallNtPowerInformation获取CPU频率在12代酷睿上返回错误值的原因及解决办法
问题描述
此前在Windows 10系统中,可通过以下调用获取当前CPU核心频率:
const NTSTATUS gotinfo = CallNtPowerInformation ( ProcessorInformation, NULL, 0, pinf, sizeof(pinf) ); assert(gotinfo != ERROR_INSUFFICIENT_BUFFER); assert(gotinfo != ERROR_ACCESS_DENIED); assert(gotinfo == ERROR_SUCCESS);但在Core i5 12600K上调用该函数时,所有核心的Max和Cur频率均返回3700MHz,结果明显错误,而函数返回状态为SUCCESS。同时微软未在WINNT.H中加入
PROCESSOR_POWER_INFORMATION结构体定义,需自行定义,且未按承诺在新版本中修复此问题。
问题原因
- 12代酷睿混合架构不兼容:Core i5 12600K属于Alder Lake系列,采用P核(性能核)+E核(能效核)的异构架构。
CallNtPowerInformation的ProcessorInformation查询逻辑是为同构核心设计的,未适配这种新架构,返回的是一个统一的基准频率值(3700MHz为该CPU的基础频率),而非各核心的真实运行频率。 - API底层实现未更新:微软并未针对异构核心CPU更新该API的底层数据采集逻辑,导致即使函数返回SUCCESS,也无法输出准确的分核心频率数据。
替代解决方案
1. 基于TSC和性能计数器计算实时频率
通过读取CPU时间戳计数器(TSC)结合QueryPerformanceCounter的时间差,可计算出当前CPU的真实运行频率:
#include <windows.h> #include <stdint.h> #include <stdio.h> // 获取CPU基准频率(单位:Hz) uint64_t GetCPUBaseFrequency() { HKEY hKey; uint64_t baseFreqMHz = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { DWORD dataSize = sizeof(baseFreqMHz); RegQueryValueEx(hKey, L"~MHz", NULL, NULL, (LPBYTE)&baseFreqMHz, &dataSize); RegCloseKey(hKey); } return baseFreqMHz * 1000000; } // 获取当前CPU实时频率(单位:Hz) double GetCurrentCPUFrequency() { LARGE_INTEGER perfFreq, startPerf, endPerf; QueryPerformanceFrequency(&perfFreq); QueryPerformanceCounter(&startPerf); uint64_t startTSC = __rdtsc(); Sleep(10); // 等待足够时间确保计数变化 uint64_t endTSC = __rdtsc(); QueryPerformanceCounter(&endPerf); double elapsedTime = (double)(endPerf.QuadPart - startPerf.QuadPart) / perfFreq.QuadPart; return (double)(endTSC - startTSC) / elapsedTime; } int main() { double currentFreq = GetCurrentCPUFrequency(); printf("Current CPU Frequency: %.2f GHz\n", currentFreq / 1000000000); return 0; }
2. 使用WMI查询Win32_Processor类
WMI的Win32_Processor类已适配异构核心CPU,可准确获取各核心的当前和最大频率:
#include <windows.h> #include <wbemidl.h> #include <comdef.h> #include <stdio.h> #pragma comment(lib, "wbemuuid.lib") void GetCPUFrequencyViaWMI() { HRESULT hres; // 初始化COM环境 hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) return; // 设置COM安全策略 hres = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL ); if (FAILED(hres)) { CoUninitialize(); return; } // 获取WMI定位器 IWbemLocator* pLoc = NULL; hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc); if (FAILED(hres)) { CoUninitialize(); return; } // 连接WMI服务 IWbemServices* pSvc = NULL; hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc ); if (FAILED(hres)) { pLoc->Release(); CoUninitialize(); return; } // 设置代理安全级别 hres = CoSetProxyBlanket( pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); if (FAILED(hres)) { pSvc->Release(); pLoc->Release(); CoUninitialize(); return; } // 执行WQL查询 IEnumWbemClassObject* pEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT CurrentClockSpeed, MaxClockSpeed FROM Win32_Processor"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator ); if (FAILED(hres)) { pSvc->Release(); pLoc->Release(); CoUninitialize(); return; } // 遍历查询结果 IWbemClassObject* pclsObj = NULL; ULONG uReturn = 0; while (pEnumerator) { HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if (0 == uReturn) break; VARIANT vtCur, vtMax; // 获取当前频率 hr = pclsObj->Get(L"CurrentClockSpeed", 0, &vtCur, 0, 0); printf("Current Clock Speed: %lu MHz\n", vtCur.ulVal); VariantClear(&vtCur); // 获取最大频率 hr = pclsObj->Get(L"MaxClockSpeed", 0, &vtMax, 0, 0); printf("Max Clock Speed: %lu MHz\n", vtMax.ulVal); VariantClear(&vtMax); pclsObj->Release(); } // 清理资源 pEnumerator->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); } int main() { GetCPUFrequencyViaWMI(); return 0; }
关于PROCESSOR_POWER_INFORMATION结构体的说明
由于微软未在官方头文件中定义该结构体,需自行手动定义,标准格式如下:
typedef struct _PROCESSOR_POWER_INFORMATION { ULONG Number; // 核心编号 ULONG MaxMhz; // 最大频率(MHz) ULONG CurrentMhz; // 当前频率(MHz) ULONG MhzLimit; // 频率限制(MHz) ULONG MaxIdleState; // 最大空闲状态 ULONG CurrentIdleState;// 当前空闲状态 } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
即便定义正确,该结构体在异构核心CPU上仍无法返回准确数据,这是API底层实现的固有问题,并非结构体定义错误导致。
内容的提问来源于stack exchange,提问作者Bram
相关产品推荐
相关产品推荐

