File indexing completed on 2024-05-12 17:00:15
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 * SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "LinuxAmdGpu.h" 0009 0010 #include <libudev.h> 0011 #include <linux/pci.h> 0012 #include <sensors/sensors.h> 0013 0014 #include <systemstats/SysFsSensor.h> 0015 #include <systemstats/SensorsFeatureSensor.h> 0016 0017 int ppTableGetMax(const QByteArray &table) 0018 { 0019 const auto lines = table.split('\n'); 0020 auto line = lines.last(); 0021 return std::atoi(line.mid(line.indexOf(':') + 1).data()); 0022 } 0023 0024 int ppTableGetCurrent(const QByteArray &table) 0025 { 0026 const auto lines = table.split('\n'); 0027 0028 int current = 0; 0029 for (const auto &line : lines) { 0030 if (!line.contains('*')) { 0031 continue; 0032 } 0033 0034 current = std::atoi(line.mid(line.indexOf(':') + 1)); 0035 } 0036 0037 return current; 0038 } 0039 0040 LinuxAmdGpu::LinuxAmdGpu(const QString& id, const QString& name, udev_device *device) 0041 : GpuDevice(id, name) 0042 , m_device(device) 0043 { 0044 udev_device_ref(m_device); 0045 } 0046 0047 LinuxAmdGpu::~LinuxAmdGpu() 0048 { 0049 udev_device_unref(m_device); 0050 } 0051 0052 void LinuxAmdGpu::initialize() 0053 { 0054 GpuDevice::initialize(); 0055 0056 m_nameProperty->setValue(QString::fromLocal8Bit(udev_device_get_property_value(m_device, "ID_MODEL_FROM_DATABASE"))); 0057 0058 auto result = udev_device_get_sysattr_value(m_device, "mem_info_vram_total"); 0059 if (result) { 0060 m_totalVramProperty->setValue(std::atoll(result)); 0061 } 0062 0063 m_coreFrequencyProperty->setMax(ppTableGetMax(udev_device_get_sysattr_value(m_device, "pp_dpm_sclk"))); 0064 m_memoryFrequencyProperty->setMax(ppTableGetMax(udev_device_get_sysattr_value(m_device, "pp_dpm_mclk"))); 0065 0066 std::for_each(m_sensorsSensors.begin(), m_sensorsSensors.end(), [this] (KSysGuard::SensorProperty *sensor) { 0067 sensor->setPrefix(name()); 0068 }); 0069 } 0070 0071 void LinuxAmdGpu::update() 0072 { 0073 for (auto sensor : qAsConst(m_sysFsSensors)) { 0074 sensor->update(); 0075 } 0076 for (auto sensor : qAsConst(m_sensorsSensors)) { 0077 sensor->update(); 0078 } 0079 m_temperatureProperty->update(); 0080 } 0081 0082 void LinuxAmdGpu::makeSensors() 0083 { 0084 auto devicePath = QString::fromLocal8Bit(udev_device_get_syspath(m_device)); 0085 0086 m_nameProperty = new KSysGuard::SensorProperty(QStringLiteral("name"), this); 0087 m_totalVramProperty = new KSysGuard::SensorProperty(QStringLiteral("totalVram"), this); 0088 0089 auto sensor = new KSysGuard::SysFsSensor(QStringLiteral("usage"), devicePath % QStringLiteral("/gpu_busy_percent"), 0, this); 0090 m_usageProperty = sensor; 0091 m_sysFsSensors << sensor; 0092 0093 sensor = new KSysGuard::SysFsSensor(QStringLiteral("usedVram"), devicePath % QStringLiteral("/mem_info_vram_used"), this); 0094 m_usedVramProperty = sensor; 0095 m_sysFsSensors << sensor; 0096 0097 sensor = new KSysGuard::SysFsSensor(QStringLiteral("coreFrequency"), devicePath % QStringLiteral("/pp_dpm_sclk"), 0, this); 0098 sensor->setConvertFunction([](const QByteArray &input) { 0099 return ppTableGetCurrent(input); 0100 }); 0101 m_coreFrequencyProperty = sensor; 0102 m_sysFsSensors << sensor; 0103 0104 sensor = new KSysGuard::SysFsSensor(QStringLiteral("memoryFrequency"), devicePath % QStringLiteral("/pp_dpm_mclk"), 0, this); 0105 sensor->setConvertFunction([](const QByteArray &input) { 0106 return ppTableGetCurrent(input); 0107 }); 0108 m_memoryFrequencyProperty = sensor; 0109 m_sysFsSensors << sensor; 0110 0111 discoverSensors(); 0112 0113 // Potentially found by discoverSensors, if not create it so it's not missing 0114 if (!m_temperatureProperty) { 0115 m_temperatureProperty = new KSysGuard::SensorProperty(QStringLiteral("temperature"), this); 0116 } 0117 0118 // It would normally find this in lmsensors plugin or in another function, but just set it in case anything tries to explode 0119 if (!m_powerProperty) { 0120 m_powerProperty = new KSysGuard::SensorProperty(QStringLiteral("power"), this); 0121 } 0122 } 0123 0124 void LinuxAmdGpu::discoverSensors() 0125 { 0126 sensors_chip_name match; 0127 sensors_parse_chip_name("amdgpu-*", &match); 0128 int number = 0; 0129 const sensors_chip_name *chip; 0130 while ((chip = sensors_get_detected_chips(&match, &number))) { 0131 int domain, bus, device, function; 0132 if (std::sscanf(udev_device_get_sysname(m_device), "%x:%x:%x.%x", &domain, &bus, &device, &function) == 4 && 0133 ((domain << 16) + (bus << 8) + PCI_DEVFN(device, function)) == chip->addr) { 0134 break; 0135 } 0136 } 0137 if (!chip) { 0138 return; 0139 } 0140 number = 0; 0141 while (const sensors_feature * const feature = sensors_get_features(chip, &number)) { 0142 // We want a special id for the device temperature 0143 KSysGuard::SensorProperty *sensor; 0144 if (feature->type == SENSORS_FEATURE_TEMP && qstrcmp(feature->name, "temp1") == 0) { 0145 sensor = KSysGuard::makeSensorsFeatureSensor(QStringLiteral("temperature"), chip, feature, this); 0146 m_temperatureProperty = sensor; 0147 } else { 0148 sensor = makeSensorsFeatureSensor(feature->name, chip, feature, this); 0149 } 0150 if (sensor) { 0151 m_sensorsSensors << sensor; 0152 } 0153 } 0154 }