hardware_monitor_cpp: достойная альтернатива, для мониторинга вашей системы

от автора

Всем привет!

Предыстория (можете пропустить)

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

Но недавно обнаружил, что «очередное решение несуществующей проблемы» видео моего личного Android порта Blender 5.3.0 Alpha, ушла в массы, и начала жить своей жизнью, а люди на реддит, выкладывают видосы, с тем как они работают на своих Android планшетах. Причем оригинальный пост, собрал еле-еле 3 стрелочки вверх на реддит, а пост с видосами да и форк моего репозитория, получили дикие отклики по меркам их сабреддитов.

Потому решил, таки рассказать, про самописные вещи которые лежат в опенсорсе, и которыми я активно пользуюсь.

Вступление

Гуглил я как-то опенсорс с++ библиотеку для мониторинга, температуры и нагрузки компонентов ПК. И не нагуглил. Вот такие вот дела. Есть HWiNFO, платно и закрыто. Есть OpenHardwareMonitor — написан C# и билиотека мертва. Есть форк предыдущей билиотеки — LibreHardwareMonitor — живее всех живых, но C#, да ещё и по дефолту требует 10 .NET.

Зачем нужен C++ , когда можно подцепить DLL из C# напрямую? Ну вот не хочу я таскать .NET определенной версии, с собой из бандла в бандл. AOT компиляция, вообще не поможет, тут как раз то самое использование специфических вещей, которые AOT не компилит. Finita la comedia! А ещё есть один косяк, у последней билиотеки: мака нет в списке поддержки, от слова совсем.

«Одно кольцо, чтоб править всеми» Windows, Linux, MacOS — x64, arm64. Вот тут я и решил, сесть и написать её. В очередной раз. Тем более, что меня уволили, и времени теперь вагон, можно потрогать все свои пэт прожекты. Тем более что есть референс в виде LibreHardwareMonitor.

Правда то что он есть, немного и плохо одновременно. Нельзя сделать как у них, потому что «лицензия детка»! Мне их лицензия не нравится. Надо избавлятся, делать надо не так.

Встречайте HardwareMonitorCpp (hardware_monitor_cpp)!

Пытался, я получить температуру процессора, без повышение привилегий. Гайки, никак. One Ring0 to rule them all! Ну на винде и макоси по крайней мере Ring0 обязателен, Linux может и без этого.

Остальное работает и без sudo. Что такое остальное? Общая информация о железе: как железка называется, сколько у неё частота, память занятая/свободная, текущая температура и текущая. Полноценный мониторинг одним словом. Понятно что у процессора нет занятой свободной памяти, а у SSD нет текущей частоты, но есть количество активного времени, и IO Bound.

Чем классная билиотека?

Ну во перхвы к неё сразу идёт Python сервер, которые все эти данные выдает в сеть! Так же есть консольная приложуха, которая выдаёт эти данные визуально в консоль (со своими собственными настройками, котрые сохраняются между запусками). Писать 100500 утилит, не стал. Я пользуюсь только консольной приложухой на винде и маке. Очень нравится, легким движением руки, переключаюсь между нагрузкой и температурой (кнопка «t»), а таймскейл меняю с 1 секунды на колонку до 1 минуты на колонку(кнопки «-» и «=»). Очень удобно, особенно что бы прикинуть визуально, сколько ещё проекту собираться, и сколько он собирался в прошлый раз. И сколько он выжрал оперативы, например.

А ещё на Windows и MacOS наконец-то есть внятный график и размера файла подкачки. Я сколько не смотрел в TaskManager и ActivityMonitor так надо найти 2 числа и дальше математикой заниматься. Не круто! Тут сразу виндно что к чему.

Все написано на C++. Потому что я плюсовик и я могу! Консольное приложение в ходе разработки раздулось с 7 мб оперативы до 30 мб на винде. Да и только потому что я решил, больше снапшотов системы хранить в истории отображения.

Из плюшек библиотеки: можно запросить по всему оборудованию только нагрузку или только температуру.

Из минусов: для Windows нужно отдельно ставить PawnIO для цифер процессора, но это нормально. LibreHardwareMontior тоже драйвер таскает и запускатет от имени администратора, для того же самого. Судьба такая. HWiNFO тоже, вот, не просто так просит поднять привелегии.

Что я делать не стал: мониторить температуру материнки и обороты вентилятора. Мне самой температуры железок хватает, что бы понять, что к чему. А а писать код вслепую для 100500 вендоров не хочется, хоть и есть куда подглядеть.

Консольное приложение и Python сервер

Вместе с самой библиотекой в комплекте идёт консольное приложение и отдельно сервер на Python, который выдаёт эту информацию в сеть.

Скрины из консольного приложения на MacOS

Скрины из консольного приложения на MacOS
Внешний вид UI питоновского сервера

Внешний вид UI питоновского сервера

Несмотря на то, что прямо то, как оно написано, может не покрыть ваши нужды, приложение и сервер хорошая точка старта для того, что бы с помощью молотка и напильника получить, ровно то, что бы вам хотелось. Ну и да, сборка питоновского сервера сразу оборачивает биндинги библиотеки в питоновское расширение, так что можно будет использовать бинарь и в других местах.

Билдится всё очень просто. Всё что нужны установленные ninja и cmake и чтобы они были доступны в Path. Дальше достаточно запустить один из python файлов сборки. Их три:

  • python build_lib.py

  • python build_console.py

  • python build_server.py

Сборки самодостаточные. После подтягивания саб модулей ничего дополнительно кроме запуска скрипта сборки делать не нужно. В README.md всё подробно описано.

Если впадлу билдить, уже есть готовые сборки релизов (но там не всё).

Примеры использования кода

Вывод температуры ядер:

#include <iostream>#include <HardwareMonitorCpp/HardwareMonitor.hpp>int main() {    // Инициализация мониторинга    HardwareMonitor::HardwareManager monitor;    monitor.Update();    // Получаем список всех доступных процессоров    auto cpus = monitor.GetCpuHardware();    for (const auto& cpu : cpus) {        std::cout << "Процессор: " << cpu->GetName() << "\n";        // Выводим только температуру ядер        for (const auto& sensor : cpu->GetSensors()) {            if (sensor->GetSensorType() == HardwareMonitor::SensorType::Temperature) {                std::cout << "  " << sensor->GetName()                           << ": " << sensor->GetValue().value_or(0) << " °C\n";            }        }    }    return 0;}

Монитор загрузки системных ресурсов:

#include <iostream>#include <thread>#include <chrono>#include <HardwareMonitorCpp/HardwareMonitor.hpp>void PrintSystemStatus(HardwareMonitor::HardwareManager& monitor) {    monitor.Update();    // 1. Загрузка CPU    for (const auto& cpu : monitor.GetCpuHardware()) {        for (const auto& sensor : cpu->GetSensors()) {            if (sensor->GetSensorType() == HardwareMonitor::SensorType::Load &&                sensor->GetName() == "CPU Total") {                std::cout << "[CPU] Загрузка: " << sensor->GetValue().value_or(0) << "%\n";            }        }    }    // 2. Использование GPU и температуры    for (const auto& gpu : monitor.GetGpuHardware()) {        std::cout << "[GPU] " << gpu->GetName() << ":\n";        for (const auto& sensor : gpu->GetSensors()) {            if (sensor->GetSensorType() == HardwareMonitor::SensorType::Temperature) {                std::cout << "  - Температура: " << sensor->GetValue().value_or(0) << " °C\n";            }            if (sensor->GetSensorType() == HardwareMonitor::SensorType::Load) {                std::cout << "  - Загрузка ядра: " << sensor->GetValue().value_or(0) << "%\n";            }        }    }}int main() {    HardwareMonitor::HardwareManager monitor;    // Цикл мониторинга раз в секунду    for (int i = 0; i < 5; ++i) {        std::cout << "=== Обновление данных (" << i + 1 << ") ===\n";        PrintSystemStatus(monitor);        std::this_thread::sleep_for(std::chrono::seconds(1));    }    return 0;}

Безопасный опрос датчиков

Иногда датчики у той или иной железки могут быть недоступны. Например у одного SSD: есть мониторинг температуры, у дргого нет.

#include <iostream>#include <HardwareMonitorCpp/HardwareMonitor.hpp>// Вспомогательная функция для безопасного получения значенияvoid PrintSensorValue(const std::shared_ptr<HardwareMonitor::ISensor>& sensor) {    std::cout << "Датчик: " << sensor->GetName() << " | ";    if (auto value = sensor->GetValue(); value.has_value()) {        std::cout << "Значение: " << *value;    } else {        std::cout << "Данные недоступны";    }    std::cout << "\n";}int main() {    HardwareMonitor::HardwareManager monitor;    monitor.Update();    // Получаем оперативную память    for (const auto& ram : monitor.GetRamHardware()) {        std::cout << "Модуль RAM: " << ram->GetName() << "\n";                for (const auto& sensor : ram->GetSensors()) {            PrintSensorValue(sensor);        }    }    return 0;}

Спасибо за внимание!

Как и в прошлой статье про другую мою библиотеку, готов к конструктивной критике, и делать апдейты. Она кстати, немного подросла, но серьезно улушилась. Если кому интересно есть статья на медиум, но пока что на английском так как большая половина критики прилетела с Reddit.

ссылка на оригинал статьи https://habr.com/ru/articles/1077310/