Как получить доступ к датчикам температуры CPU?

Вопрос или проблема

Я работаю над программным обеспечением, в котором мне нужно получить доступ к датчикам температуры в ЦП и получить контроль над ними.

Я не знаю много о взаимодействии с оборудованием; я только знаю, как взаимодействовать с мышью. Я много искал информацию об этом в интернете, но не смог найти никакой релевантной информации или кода.

Мне действительно нужно добавить это в мое программное обеспечение. Пожалуйста, помогите мне узнать, как получить контроль над датчиками, используя C, C++ или ASM.

Без конкретного драйвера ядра сложно запросить температуру, кроме как через WMI. Вот фрагмент кода на C, который это делает, основанный на классе MSAcpi_ThermalZoneTemperature WMI:

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

    *pTemperature = -1;
    HRESULT ci = CoInitialize(NULL); // требует 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; // требует 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);
}

Я предполагаю, что вас интересует ЦП IA-32 (архитектура Intel, 32 бита) и Microsoft Windows.

Модельный регистра (MSR) IA32_THERM_STATUS имеет 7 бит для кодирования “Цифрового вывода (биты 22:16, RO) — Цифровое считывание температуры в 1 градус Цельсия относительно температуры активации TCC.” (см. “14.5.5.2 Считывание цифрового датчика” в “Intel® 64 и IA-32 Архитектуры – Руководство разработчика ПО – Том 3 (3A и 3B): Руководство по системному программированию” http://www.intel.com/Assets/PDF/manual/325384.pdf).

Таким образом, IA32_THERM_STATUS не даст вам “температуру ЦП”, а только некоторый прокси для этого.

Чтобы прочитать регистр IA32_THERM_STATUS, вы используете инструкцию asm rdmsr, но rdmsr не может быть вызван из кода пользовательского пространства, поэтому вам нужен некоторый код в пространстве ядра (возможно, драйвер устройства?).

Вы также можете использовать встроенную функцию __readmsr (см. http://msdn.microsoft.com/en-us/library/y55zyfdx(v=VS.100).aspx), которая все равно имеет то же ограничение: “Эта функция доступна только в режиме ядра”.

Каждое ядро ЦП имеет свои собственные цифровые термодатчики (DTS), поэтому потребуется больше кода, чтобы получить все температуры (возможно, с маской аффинности? см. Win32 API SetThreadAffinityMask).

Я провел некоторые тесты и действительно обнаружил корреляцию между показаниями DTS IA32_THERM_STATUS и тестом Prime95 “In-place large FFTs (максимальное тепло, потребление энергии, некоторые тестируемые ОЗУ)”. Prime95 это ftp://mersenne.org/gimps/p95v266.zip

Я не нашел формулы, чтобы получить “температуру ЦП” (что бы это ни означало) из показаний DTS.

Правка:

Цитируя интересный пост TJunction Max? #THERMTRIP? #PROCHOT? от “fgw” (декабрь 2007):

нет способа найти tjmax определенного процессора в каком-либо регистре.
таким образом, никакое программное обеспечение не может прочитать это значение. что различные разработчики программного обеспечения
делают, это они просто предполагают определенный tjunction для определенного
процессора и хранят эту информацию в таблице внутри программы.
помимо этого, tjmax даже не является правильным значением, которое они ищут. фактически они ищут порог активации TCC. этот
порог температуры используется для расчета текущих абсолютных
температур ядра. теоретически вы можете сказать: абсолютная
температура ядра = порог активации температуры TCC – DTS, я должен был сказать теоретически, потому что, как указано выше, этот порог активации температуры TCC нельзя считать программным обеспечением и должен быть предположен
программистом. в большинстве ситуаций (coretemp, everest и т.д.) они
предполагают значение 85C или 100C в зависимости от семейства процессоров и
ревизии. поскольку этот порог активации температуры TCC калибруется
индивидуально при производстве для каждого процессора, он может быть 83C для
одного процессора, но может быть 87C для другого. учитывая, как программы рассчитывают температуры ядра, вы можете самостоятельно выяснить, насколько
точны абсолютные температуры ядра! ни tjmax, ни “наиболее желаемый” порог активации температуры TCC нельзя найти в любых публичных documento intel. следуя некоторым обсуждениям
на форуме разработчиков intel, intel не проявляет признаков, что эта информация будет доступна.

Вы можете прочитать это из MSAcpi_ThermalZoneTemperature в WMI

Использование WMI из C++ немного затруднительно, см. объяснение и примеры MSDN

замечание: изменен оригинальный бесполезный ответ

Ответ или решение

Как получить доступ к датчикам температуры процессора

Доступ к датчикам температуры процессора может быть сложной задачей, особенно если вы не знакомы с аппаратным интерфейсом. В этой статье мы подробно рассмотрим, как получить доступ к температурным датчикам ЦП с использованием языка C или C++ на операционной системе Windows, а также некоторые ограничения, которые могут возникнуть.

1. Использование WMI (Windows Management Instrumentation)

Для получения данных о температуре ЦП в среде Windows одним из самых простых способов является использование Windows Management Instrumentation (WMI). В WMI есть класс MSAcpi_ThermalZoneTemperature, который предоставляет информацию о температуре. В следующем коде показано, как это можно сделать на C++.

#include <wbemidl.h>
#include <comdef.h>
#include <iostream>

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

    *pTemperature = -1;
    HRESULT ci = CoInitialize(NULL);
    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;
        hr = CoCreateInstance(CLSID_WbemLocator, 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;
}

int main()
{
    LONG temp;
    HRESULT hr = GetCpuTemperature(&temp);
    std::cout << "hr=0x" << std::hex << hr << " temp=" << temp << std::endl;

    return 0;
}

2. Чтение Модульных Специфических Регистров (MSR)

Если вам нужно более низкоуровневое управление, вы можете рассмотреть возможность чтения регистра, связанного с термальными датчиками процессора, такого как IA32_THERM_STATUS. Для этого можно использовать инструкцию rdmsr, которая позволяет читать значение из MSR. Однако следует отметить, что эта инструкция может быть выполнена только в режиме ядра, а значит, вам понадобится писать драйвер устройства.

В качестве альтернативы вы можете использовать встроенную функцию __readmsr, но, как и в случае с rdmsr, она также доступна только в режиме ядра.

; пример использования rdmsr в ассемблере
rdmsr
; результат будет в EDX:EAX

3. Ограничения и предостережения

  • Уровень доступа: Доступ к регистрам процессора из пользовательского пространства обычно запрещен для обеспечения безопасности и стабильности системы. Вам может понадобиться написать драйвер устройства для чтения определенных регистров или работы с низкоуровневыми API.

  • Точность данных: Чтения температуры ЦП могут не предоставлять точных абсолютных значений. Например, информация из регистра IA32_THERM_STATUS может давать только относительные значения, которые «порядочно» могут нуждаться в дополнительной коррекции, основываясь на характеристиках конкретного процессора.

  • Зависимость от железа: Разные процессоры могут иметь разные схемы регистрации данных температур, и поэтому важно учитывать специфические характеристики вашего оборудования.

Заключение

Получение доступа к датчикам температуры процессора требует знания о программировании на низком уровне. Использование WMI может предоставить наиболее простой способ, особенно для приложений Windows. Если вы хотите больше контроля, возможно, придется рассмотреть написание драйвера ядра. В любом случае, учитывайте ограничения, связанные с безопасностью и точностью данных.

Оцените материал
Добавить комментарий

Капча загружается...