You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 23:07:40