如何访问CPU的热传感器?

发布于 2024-10-22 06:34:48 字数 152 浏览 1 评论 0原文

我正在开发需要访问 CPU 中的温度传感器并控制它们的软件。

我不太了解硬件接口;我只知道如何与鼠标交互。我用谷歌搜索了很多相关信息,但未能找到任何相关信息或代码。

我真的需要将其添加到我的软件中。请指导我如何使用 C 或 C++ 或 ASM 来控制传感器。

I am working on software in which I need to access the temperature sensors in the CPU and get control over them.

I don't know much hardware interfacing; I just know how to interface with the mouse. I have googled a lot about it but failed to find any relevant information or piece of code.

I really need to add this in my software. Please guide me how to have the control over the sensors using C or C++ or ASM.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟雨扶苏 2024-10-29 06:34:48

如果没有特定的内核驱动程序,除了通过 WMI 之外,很难查询温度。下面是一段基于 WMI 的 MSAcpi_ThermalZoneTemperature 类的 C 代码:

HRESULT GetCpuTemperature(LPLONG pTemperature)
{
    if (pTemperature == NULL)
        return E_INVALIDARG;

    *pTemperature = -1;
    HRESULT ci = CoInitialize(NULL); // needs comdef.h
    HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    if (SUCCEEDED(hr))
    {
        IWbemLocator *pLocator; // needs Wbemidl.h & Wbemuuid.lib
        hr = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLocator);
        if (SUCCEEDED(hr))
        {
            IWbemServices *pServices;
            BSTR ns = SysAllocString(L"root\\WMI");
            hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices);
            pLocator->Release();
            SysFreeString(ns);
            if (SUCCEEDED(hr))
            {
                BSTR query = SysAllocString(L"SELECT * FROM MSAcpi_ThermalZoneTemperature");
                BSTR wql = SysAllocString(L"WQL");
                IEnumWbemClassObject *pEnum;
                hr = pServices->ExecQuery(wql, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
                SysFreeString(wql);
                SysFreeString(query);
                pServices->Release();
                if (SUCCEEDED(hr))
                {
                    IWbemClassObject *pObject;
                    ULONG returned;
                    hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned);
                    pEnum->Release();
                    if (SUCCEEDED(hr))
                    {
                        BSTR temp = SysAllocString(L"CurrentTemperature");
                        VARIANT v;
                        VariantInit(&v);
                        hr = pObject->Get(temp, 0, &v, NULL, NULL);
                        pObject->Release();
                        SysFreeString(temp);
                        if (SUCCEEDED(hr))
                        {
                            *pTemperature = V_I4(&v);
                        }
                        VariantClear(&v);
                    }
                }
            }
            if (ci == S_OK)
            {
                CoUninitialize();
            }
        }
    }
    return hr;
}

以及一些测试代码:

HRESULT GetCpuTemperature(LPLONG pTemperature);

int _tmain(int argc, _TCHAR* argv[])
{
    LONG temp;
    HRESULT hr = GetCpuTemperature(&temp);
    printf("hr=0x%08x temp=%i\n", hr, temp);
}

Without a specific kernel driver, it's difficult to query the temperature, other than through WMI. Here is a piece of C code that does it, based on WMI's MSAcpi_ThermalZoneTemperature class:

HRESULT GetCpuTemperature(LPLONG pTemperature)
{
    if (pTemperature == NULL)
        return E_INVALIDARG;

    *pTemperature = -1;
    HRESULT ci = CoInitialize(NULL); // needs comdef.h
    HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    if (SUCCEEDED(hr))
    {
        IWbemLocator *pLocator; // needs Wbemidl.h & Wbemuuid.lib
        hr = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLocator);
        if (SUCCEEDED(hr))
        {
            IWbemServices *pServices;
            BSTR ns = SysAllocString(L"root\\WMI");
            hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices);
            pLocator->Release();
            SysFreeString(ns);
            if (SUCCEEDED(hr))
            {
                BSTR query = SysAllocString(L"SELECT * FROM MSAcpi_ThermalZoneTemperature");
                BSTR wql = SysAllocString(L"WQL");
                IEnumWbemClassObject *pEnum;
                hr = pServices->ExecQuery(wql, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
                SysFreeString(wql);
                SysFreeString(query);
                pServices->Release();
                if (SUCCEEDED(hr))
                {
                    IWbemClassObject *pObject;
                    ULONG returned;
                    hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned);
                    pEnum->Release();
                    if (SUCCEEDED(hr))
                    {
                        BSTR temp = SysAllocString(L"CurrentTemperature");
                        VARIANT v;
                        VariantInit(&v);
                        hr = pObject->Get(temp, 0, &v, NULL, NULL);
                        pObject->Release();
                        SysFreeString(temp);
                        if (SUCCEEDED(hr))
                        {
                            *pTemperature = V_I4(&v);
                        }
                        VariantClear(&v);
                    }
                }
            }
            if (ci == S_OK)
            {
                CoUninitialize();
            }
        }
    }
    return hr;
}

and some test code:

HRESULT GetCpuTemperature(LPLONG pTemperature);

int _tmain(int argc, _TCHAR* argv[])
{
    LONG temp;
    HRESULT hr = GetCpuTemperature(&temp);
    printf("hr=0x%08x temp=%i\n", hr, temp);
}
木格 2024-10-29 06:34:48

我假设您对 IA-32(英特尔架构,32 位)CPU 和 Microsoft Windows 感兴趣。

型号特定寄存器 (MSR) IA32_THERM_STATUS 有 7 位编码“数字读数(位 22:16,RO)——相对于 TCC 激活温度的数字温度读数,单位为 1 摄氏度”。 (请参阅“英特尔® 64 和 IA-32 架构 - 软件开发人员手册 - 第 3 卷(3A 和 3B):系统编程指南”中的“14.5.5.2 读取数字传感器”http://www.intel.com/Assets/PDF/manual/325384.pdf)。

因此,IA32_THERM_STATUS 不会为您提供“CPU 温度”,而是提供一些代理。

为了读取 IA32_THERM_STATUS 寄存器,您使用 asm 指令 rdmsr,现在 rdmsr 无法从用户空间代码调用,因此您需要一些内核空间代码(也许是设备驱动程序?)。

您还可以使用内部 __readmsr (请参阅 http://msdn.microsoft.com/en-us/library/y55zyfdx(v=VS.100).aspx) 无论如何都有相同的限制:“此功能仅在内核中可用模式”。

每个 CPU 核心都有自己的数字热传感器 (DTS),因此需要更多代码来获取所有温度(也许使用亲和性掩码?请参阅 Win32 API SetThreadAffinityMask)。

我做了一些测试,实际上发现了 IA32_THERM_STATUS DTS 读数与 Prime95“就地大型 FFT(最大热量、功耗、测试了一些 RAM)”测试之间的相关性。 Prime95 是 ftp://mersenne.org/gimps/p95v266.zip

我没有找到公式从 DTS 读数中获取“CPU 温度”(无论这意味着什么)。

编辑:

引用一篇有趣的文章TJunction 最大? #热旅行? #PROCHOT? 作者:"fgw"(2007 年 12 月) :

无法在任何寄存器中找到某个处理器的 tjmax。
因此没有软件可以读取该值。各种软件开发商都有哪些
正在做的事情,是他们只是简单地假设某个特定的连接点
处理器并将这些信息保存在程序内的表中。
除此之外,tjmax 甚至不是他们所追求的正确值。在
事实上,他们正在寻找 TCC 激活温度阈值。这
温度阈值用于计算当前绝对值
核心温度从。理论上你可以说:绝对
核心温度 = TCC 激活温度阈值 - DTS 我必须
从理论上讲,因为如上所述,这种 TCC 激活
温度阈值无法通过软件读取,必须进行假设
由程序员。在大多数情况下(coretemp、珠穆朗玛峰...)
假设值为 85C 或 100C,具体取决于处理器系列和
修订。因为此 TCC 激活温度阈值已校准
在每个处理器单独制造期间,它可能是 83C
一个处理器,但另一个可能是 87C。考虑到
这些程序计算核心温度的方式,你可以算出
在你自己的情况下,绝对核心温度是多么准确!两者都不
tjmax 或“最想要的”TCC 激活温度阈值都可以
可在任何公开英特尔文件中找到。经过一些讨论
在英特尔开发者论坛上,英特尔没有显示出这样做的迹象
可用信息。

I assume you are interested in a IA-32 (Intel Architecture, 32-bit) CPU and Microsoft Windows.

The Model Specific Register (MSR) IA32_THERM_STATUS has 7 bits encoding the "Digital Readout (bits 22:16, RO) — Digital temperature reading in 1 degree Celsius relative to the TCC activation temperature." (see "14.5.5.2 Reading the Digital Sensor" in "Intel® 64 and IA-32 Architectures - Software Developer’s Manual - Volume 3 (3A & 3B): System Programming Guide" http://www.intel.com/Assets/PDF/manual/325384.pdf).

So IA32_THERM_STATUS will not give you the "CPU temperature" but some proxy for it.

In order to read the IA32_THERM_STATUS register you use the asm instruction rdmsr, now rdmsr cannot be called from user space code and so you need some kernel space code (maybe a device driver?).

You can also use the intrinsic __readmsr (see http://msdn.microsoft.com/en-us/library/y55zyfdx(v=VS.100).aspx) which has anyway the same limitation: "This function is only available in kernel mode".

Every CPU cores has its own Digital Thermal Sensors (DTS) and so some more code is needed to get all the temperatures (maybe with the affinity mask? see Win32 API SetThreadAffinityMask).

I did some tests and actually found a correlation between the IA32_THERM_STATUS DTS readouts and the Prime95 "In-place large FFTs (maximum heat, power consumption, some RAM tested)" test. Prime95 is ftp://mersenne.org/gimps/p95v266.zip

I did not find a formula to get the "CPU temperature" (whatever that may mean) from the DTS readout.

Edit:

Quoting from an interesting post TJunction Max? #THERMTRIP? #PROCHOT? by "fgw" (December 2007):

there is no way to find tjmax of a certain processor in any register.
thus no software can read this value. what various software developers
are doing, is they simply assume a certain tjunction for a certain
processor and hold this information in a table within the program.
besides that, tjmax is not even the correct value they are after. in
fact they are looking for TCC activacion temperature threshold. this
temperature threshold is used to calculate current absolute
coretemperatures from. theoretical you can say: absolute
coretemperature = TCC activacion temperature threshold - DTS i had to
say theoretically because, as stated above, this TCC activacion
temperature threshold cant be read by software and has to be assumed
by the programmer. in most situations (coretemp, everest, ...) they
assume a value of 85C or 100C depending on processor family and
revision. as this TCC activacion temperature threshold is calibrated
during manufacturing individually per processor, it could be 83C for
one processor but may be 87C for the other. taking into account the
way those programms are calculating coretemperatures, you can figure
out at your own, how accurate absolute coretemperatures are! neither
tjmax nor the "most wanted" TCC activacion temperature threshold can
be found in any public intel documents. following some discussions
over on the intel developer forum, intel shows no sign to make this
information available.

野の 2024-10-29 06:34:48

您可以从 WMI 中的 MSAcpi_ThermalZoneTemperature 中读取它。

使用 C++ 中的 WMI 有点复杂,请参阅 MSDN 解释和示例

注意:更改了原来无用的答案

You can read it from the MSAcpi_ThermalZoneTemperature in WMI

Using WMI from C++ is a bit involved, see MSDN explanantion and examples

note: changed original unhelpful answer

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文