Commit bdeba27b authored by David Redondo's avatar David Redondo 🏎
Browse files

Linux intel

parent 10be6f78
......@@ -23,6 +23,8 @@
CpuObject::CpuObject(const QString &id, const QString &name, SensorContainer *parent)
: SensorObject(id, name, parent)
, m_frequency{nullptr}
, m_temperature{nullptr}
{
auto n = new SensorProperty(QStringLiteral("name"), i18nc("@title", "Name"), name, this);
n->setVariantType(QVariant::String);
......
......@@ -4,7 +4,9 @@
#include <KLocalizedString>
#ifdef HAVE_SENSORS
#include <sensors/sensors.h>
#endif
#include <SensorContainer.h>
......@@ -21,9 +23,11 @@ static double readCpuFreq(const QString &cpuId, const QString &attribute, bool &
LinuxCpuObject::LinuxCpuObject(const QString &id, const QString &name, SensorContainer *parent, double frequency)
: CpuObject(id, name, parent)
, m_sensorChipName{nullptr}
, m_temperatureSubfeature{-1}
{
if (m_frequency) {
m_frequency->setValue(frequency);
m_frequency->setValue(frequency);
bool ok;
const double max = readCpuFreq(id, "cpuinfo_max_freq", ok);
if (ok) {
......@@ -36,6 +40,27 @@ LinuxCpuObject::LinuxCpuObject(const QString &id, const QString &name, SensorCon
}
}
void LinuxCpuObject::setTemperatureSensor(const sensors_chip_name * const chipName, const sensors_feature * const feature)
{
#ifdef HAVE_SENSORS
m_sensorChipName = chipName;
const sensors_subfeature * const temperature = sensors_get_subfeature(chipName, feature, SENSORS_SUBFEATURE_TEMP_INPUT);
if (temperature) {
m_temperatureSubfeature = temperature->number;
}
// Typically temp_emergency > temp_crit > temp_max, but not every processor has them
// see https://www.kernel.org/doc/html/latest/hwmon/sysfs-interface.html
double value;
for (auto subfeatureType : {SENSORS_SUBFEATURE_TEMP_EMERGENCY, SENSORS_SUBFEATURE_TEMP_CRIT, SENSORS_SUBFEATURE_TEMP_MAX}) {
const sensors_subfeature * const subfeature = sensors_get_subfeature(chipName, feature, subfeatureType);
if (subfeature && sensors_get_value(chipName, subfeature->number, &value) == 0) {
m_temperature->setMax(value);
break;
}
}
#endif
}
void LinuxCpuObject::update(unsigned long long system, unsigned long long user, unsigned long long wait, unsigned long long idle)
{
// First calculate usages
......@@ -68,9 +93,19 @@ void LinuxCpuObject::update(unsigned long long system, unsigned long long user,
}
if (ok) {
m_frequency->setValue(frequency);
}
}
// FIXME Should we fall back to reading /proc/cpuinfo again when the above fails? Could have the
// frequency value changed even if the cpu apparently doesn't use CPUFreq?
// Third update temperature
#ifdef HAVE_SENSORS
if (m_sensorChipName && m_temperatureSubfeature != -1) {
double value;
if (sensors_get_value(m_sensorChipName, m_temperatureSubfeature, &value) == 0) {
m_temperature->setValue(value);
}
}
#endif
}
LinuxCpuPluginPrivate::LinuxCpuPluginPrivate(CpuPlugin *q)
......@@ -82,15 +117,14 @@ LinuxCpuPluginPrivate::LinuxCpuPluginPrivate(CpuPlugin *q)
QHash<int, int> numCores;
for (QByteArray line = cpuinfo.readLine(); !line.isEmpty(); line = cpuinfo.readLine()) {
int physicalId = -1;
int processor = -1;
double frequency = -1;
unsigned int processor, physicalId, coreId;
double frequency = 0;
// Processors are divided by empty lines
for (; (physicalId == -1 && processor == -1 && frequency == -1) || line != "\n"; line = cpuinfo.readLine()) {
for (; line != "\n"; line = cpuinfo.readLine()) {
// we are interested in processor number as identifier for /proc/stat, physical id (the
// cpu the core belongs to) and the number of the core. However with hyperthreading
// multiple entries will have the same combination of physical id and core id. So we just
// count up the core number.
// count up the core number. For mapping temperature both ids are still needed nonetheless.
const int delim = line.indexOf(":");
const QByteArray field = line.left(delim).trimmed();
const QByteArray value = line.mid(delim + 1).trimmed();
......@@ -98,12 +132,16 @@ LinuxCpuPluginPrivate::LinuxCpuPluginPrivate(CpuPlugin *q)
processor = value.toInt();
} else if (field == "physical id") {
physicalId = value.toInt();
} else if (field == "core id") {
coreId = value.toInt();
} else if (field == "cpu MHz") {
frequency = value.toDouble();
}
}
const QString name = i18nc("@title", "CPU %1 Core %2").arg(physicalId + 1).arg(++numCores[physicalId]);
new LinuxCpuObject(QStringLiteral("cpu%1").arg(processor), name, m_container, frequency);
auto cpu = new LinuxCpuObject(QStringLiteral("cpu%1").arg(processor), name, m_container, frequency);
qDebug() << physicalId << coreId << cpu->id();
m_cpusBySystemIds.insert({physicalId, coreId}, cpu);
}
const int cores = m_container->objects().size();
// Add total usage sensors
......@@ -119,28 +157,6 @@ LinuxCpuPluginPrivate::LinuxCpuPluginPrivate(CpuPlugin *q)
addSensors();
}
void LinuxCpuPluginPrivate::addSensors()
{
#ifdef HAVE_SENSORS
sensors_init(nullptr);
int number = 0;
while (sensors_chip_name const *chipName = sensors_get_detected_chips(nullptr, &number)) {
char name[100];
sensors_snprintf_chip_name(name, 100, chipName);
qDebug() << name << chipName->prefix << "Bus(" << chipName->bus.nr << chipName->bus.type << ")" << chipName->addr << chipName->path;
int featureNumber = 0;
while (sensors_feature const * feature = sensors_get_features(chipName, &featureNumber)) {
qDebug() << '\t' << feature->number << sensors_get_label(chipName, feature) << feature->name << feature->type;
int subfeatureNumber = 0;
while (sensors_subfeature const * subfeature = sensors_get_all_subfeatures(chipName, feature, &subfeatureNumber)) {
qDebug() << "\t\t" << subfeature->number << subfeature->name << subfeature->type << subfeature->flags << subfeature->mapping;
}
}
}
#endif
}
void LinuxCpuPluginPrivate::update()
{
// Parse /proc/stat to get usage values. The format is described at
......@@ -164,3 +180,58 @@ void LinuxCpuPluginPrivate::update()
cpu->update(system + irq + softirq, user + nice , iowait + steal, idle);
}
}
void LinuxCpuPluginPrivate::addSensors()
{
#ifdef HAVE_SENSORS
sensors_init(nullptr);
int number = 0;
while (const sensors_chip_name * const chipName = sensors_get_detected_chips(nullptr, &number)) {
char name[100];
sensors_snprintf_chip_name(name, 100, chipName);
if (qstrcmp(chipName->prefix, "coretemp") == 0) {
addSensorsIntel(chipName);
}
}
#endif
}
// Documentation: https://www.kernel.org/doc/html/latest/hwmon/coretemp.html
void LinuxCpuPluginPrivate::addSensorsIntel(const sensors_chip_name * const chipName)
{
#ifdef HAVE_SENSORS
int featureNumber = 0;
QHash<unsigned int, sensors_feature const *> coreFeatures;
int physicalId = -1;
while (sensors_feature const * feature = sensors_get_features(chipName, &featureNumber)) {
const char * const sensorLabel = sensors_get_label(chipName, feature);
unsigned int coreId;
// First try to see if it's a core temperature because we should have more of those
if (std::sscanf(sensorLabel, "Core %d", &coreId) != 0) {
coreFeatures.insert(coreId, feature);
} else {
std::sscanf(sensorLabel, "Package id %d", &physicalId);
}
}
if (physicalId == -1) {
return;
}
for (auto feature = coreFeatures.cbegin(); feature != coreFeatures.cend(); ++feature) {
if (m_cpusBySystemIds.contains({physicalId, feature.key()})) {
// When the cpu has hyperthreading we display multiple cores for each physical core.
// Naturally they share the same temperature sensor and have the same coreId.
auto cpu_range = m_cpusBySystemIds.equal_range({physicalId, feature.key()});
for (auto cpu_it = cpu_range.first; cpu_it != cpu_range.second; ++cpu_it) {
qDebug() << physicalId << feature.key() << feature.value()->name;
(*cpu_it)->setTemperatureSensor(chipName, feature.value());
}
}
}
// int subfeatureNumber = 0;
// while (sensors_subfeature const * subfeature = sensors_get_all_subfeatures(chipName, feature, &subfeatureNumber)) {
// qDebug() << "\t\t" << subfeature->number << subfeature->name << subfeature->type << subfeature->flags << subfeature->mapping;
// }
// }
#endif
}
......@@ -19,20 +19,29 @@
#ifndef LINUXCPU_H
#define LINUXCPU_H
#include <QHash>
#include "cpu.h"
#include "cpuplugin_p.h"
struct sensors_chip_name;
struct sensors_feature;
class LinuxCpuObject : public CpuObject
{
public:
LinuxCpuObject(const QString &id, const QString &name, SensorContainer *parent, double frequency);
void update(unsigned long long system, unsigned long long user, unsigned long long wait, unsigned long long idle);
void setTemperatureSensor(const sensors_chip_name * const chipName, const sensors_feature * const feature);
private:
unsigned long long m_totalTicks;
unsigned long long m_systemTicks;
unsigned long long m_userTicks;
unsigned long long m_waitTicks;
const sensors_chip_name * m_sensorChipName;
int m_temperatureSubfeature;
};
class LinuxCpuPluginPrivate : public CpuPluginPrivate {
......@@ -41,6 +50,8 @@ public:
void update() override;
private:
void addSensors();
void addSensorsIntel(const sensors_chip_name * const chipName);
QMultiHash<QPair<unsigned int, unsigned int>, LinuxCpuObject * const> m_cpusBySystemIds;
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment