Publish tool cleanup and Framework monitoring refinements

This commit is contained in:
ajp_anton
2026-09-12 05:17:02 +00:00
parent db352083cf
commit 7f56368674
51 changed files with 1487 additions and 341 deletions
@@ -2,6 +2,7 @@
#include "hardware.h"
#include "fan.h"
#include "cpu.h"
#include "power.h"
#include <QTest>
#include <QTemporaryDir>
#include <QDir>
@@ -14,6 +15,76 @@ class HardwareTest : public QObject {
QFile file(path); QVERIFY(file.open(QIODevice::WriteOnly)); QCOMPARE(file.write(value), value.size());
}
private Q_SLOTS:
void energyCounters() {
EnergyCounter counter;
const quint64 range = 262143328850ULL;
QVERIFY(!counter.sample(1000000, range, 0, 3000));
QCOMPARE(counter.sample(6000000, range, 1000, 3000), std::optional<double>(5));
QCOMPARE(counter.sample(16000000, range, 3000, 3000), std::optional<double>(5));
QVERIFY(!counter.sample(100, range, 4000, 3000)); // Reset, not a wrap.
QCOMPARE(counter.sample(100, range, 5000, 3000), std::optional<double>(0));
QVERIFY(!counter.sample(200, range, 10000, 3000)); // Long gaps establish a new baseline.
QCOMPARE(counter.sample(1000200, range, 11000, 3000), std::optional<double>(1));
EnergyCounter wrapped;
QVERIFY(!wrapped.sample(range - 3000000, range, 0, 3000));
QCOMPARE(wrapped.sample(2000000, range, 1000, 3000), std::optional<double>(5));
QVERIFY(!wrapped.sample(100, 100000000, 2000, 3000)); // Changed range.
QVERIFY(!wrapped.sample(100, 0, 3000, 3000));
QVERIFY(!wrapped.sample(range + 1, range, 4000, 3000));
EnergyCounter large;
const quint64 base = 1ULL << 60;
QVERIFY(!large.sample(base, base * 2, 0, 3000));
QCOMPARE(large.sample(base + 1000, base * 2, 1000, 3000), std::optional<double>(.001));
}
void powerDiscoveryAndSampling() {
QTemporaryDir root;
const QString rapl = root.path() + "/class/powercap/intel-rapl:0/";
const QString mmio = root.path() + "/class/powercap/intel-rapl-mmio:0/";
for (const auto &path : {rapl, mmio}) {
put(path + "name", "package-0"); put(path + "energy_uj", "1000000");
put(path + "max_energy_range_uj", "262143328850");
}
const QString fan = root.path() + "/class/hwmon/hwmon9/";
put(fan + "name", "power_meter"); put(fan + "power1_input", "250000"); put(fan + "power1_average", "500000");
const QString acpiFan = root.path() + "/class/hwmon/hwmon10/";
put(acpiFan + "name", "acpi_fan"); put(acpiFan + "power1_input", "0");
PowerMonitor monitor(root.path()); QCOMPARE(monitor.sensors().size(), 2);
QCOMPARE(monitor.sensors()[0].name, QString("CPU package"));
QCOMPARE(monitor.sensors()[0].path, rapl + "energy_uj");
const QString cpu = monitor.sensors()[0].id, fanId = monitor.sensors()[1].id;
auto values = monitor.sample(1000, 0);
QVERIFY(!values.contains(cpu)); QCOMPARE(values.value(fanId), .25);
put(rapl + "energy_uj", "6000000");
values = monitor.sample(1000, 1000); QCOMPARE(values.value(cpu), 5.);
put(rapl + "energy_uj", "unavailable"); QVERIFY(!monitor.sample(1000, 2000).contains(cpu));
put(rapl + "energy_uj", "11000000"); QVERIFY(!monitor.sample(1000, 3000).contains(cpu));
put(rapl + "energy_uj", "16000000"); QCOMPARE(monitor.sample(1000, 4000).value(cpu), 5.);
monitor.reset(); QVERIFY(!monitor.sample(1000, 5000).contains(cpu));
put(fan + "power1_input", "0"); QCOMPARE(monitor.sample(1000, 6000).value(fanId), 0.);
QTemporaryDir fallback;
const QString fallbackZone = fallback.path() + "/class/powercap/intel-rapl-mmio:0/";
put(fallbackZone + "name", "package-0"); put(fallbackZone + "energy_uj", "0");
PowerMonitor mmioOnly(fallback.path()); QCOMPARE(mmioOnly.sensors().size(), 1);
QCOMPARE(mmioOnly.sensors()[0].id, cpu);
QVERIFY(mmioOnly.sample(1000, 0).isEmpty()); // Missing range is not a zero reading.
}
void platformPowerIsExcluded() {
for (const auto &prefix : {"intel-rapl:", "intel-rapl-mmio:"}) {
QTemporaryDir root;
const QStringList names{"package-0", "core", "uncore", "dram", "psys", "psys-0"};
for (int i = 0; i < names.size(); ++i) {
const QString path = root.path() + "/class/powercap/" + prefix + QString::number(i) + "/";
put(path + "name", names[i].toUtf8()); put(path + "energy_uj", "0");
put(path + "max_energy_range_uj", "1000000");
}
PowerMonitor monitor(root.path());
QStringList discovered;
for (const auto &sensor : monitor.sensors()) discovered.append(sensor.name);
QCOMPARE(discovered, QStringList({"CPU package", "CPU cores", "Uncore", "Memory (RAPL)"}));
QVERIFY(monitor.sample(1000, 0).isEmpty());
QCOMPARE(monitor.sample(1000, 1000).size(), 4);
}
}
void modelGate() {
QTemporaryDir root;
QVERIFY(!compatibilityError(root.path()).isEmpty());