Commit a63bede9 authored by David Redondo's avatar David Redondo 🏎

FreeBSD usage and frequencies

parent a04a9934
add_library(ksysguard_plugin_cpu MODULE cpu.cpp cpuplugin.cpp linuxcpu.cpp)
add_library(ksysguard_plugin_cpu MODULE cpu.cpp cpuplugin.cpp)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_sources(ksysguard_plugin_cpu PRIVATE linuxcpu.cpp)
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
target_sources(ksysguard_plugin_cpu PRIVATE freebsdcpu.cpp)
endif()
target_link_libraries(ksysguard_plugin_cpu Qt5::Core KSysGuard::StatsBackend KF5::CoreAddons KF5::I18n)
install(TARGETS ksysguard_plugin_cpu DESTINATION ${KDE_INSTALL_PLUGINDIR}/ksysguard)
......@@ -26,8 +26,6 @@ class CpuObject : public SensorObject {
public:
CpuObject(const QString &id, const QString &name, SensorContainer *parent);
virtual void update() = 0;
// const int physicalId; // NOTE The combination of these two ids is not necessarily unique with hyperthreading
// const int coreId;
protected:
......
......@@ -25,6 +25,7 @@
#include <SensorContainer.h>
#include "freebsdcpu.h"
#include "linuxcpu.h"
CpuPluginPrivate::CpuPluginPrivate(CpuPlugin *q)
......@@ -34,8 +35,10 @@ CpuPluginPrivate::CpuPluginPrivate(CpuPlugin *q)
CpuPlugin::CpuPlugin(QObject *parent, const QVariantList &args)
: SensorPlugin(parent, args)
#ifdef Q_OS_LINUX
#if defined Q_OS_LINUX
, d(new LinuxCpuPluginPrivate(this))
#elif defined Q_OS_FREEBSD
, d(new FreeBsdCpuPluginPrivate(this))
#else
, d(new CpuPluginPrivate(this))
#endif
......
#include "freebsdcpu.h"
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <KLocalizedString>
#include <SensorContainer.h>
FreeBsdCpuObject::FreeBsdCpuObject(const QString &id, const QString &name, SensorContainer *parent)
: CpuObject(id, name, parent)
{
// For min and max frequency we have to parse the values return by freq_levels because only
// minimum is exposed as a single value
size_t size;
const QByteArray levelsName = QByteArrayLiteral("dev.cpu.") + id.right(1).toLocal8Bit() + QByteArrayLiteral(".freq_levels");
if (sysctlbyname(levelsName, nullptr, &size, nullptr, 0) != -1) {
QByteArray freqLevels(size, Qt::Uninitialized);
if (sysctlbyname(levelsName, freqLevels.data(), &size, nullptr, 0) != -1) {
// The format is a list of pairs "frequency/power", see https://svnweb.freebsd.org/base/head/sys/kern/kern_cpu.c?revision=360464&view=markup#l1019
const QList<QByteArray> levels = freqLevels.split(' ');
int min = INT_MAX;
int max = 0;
for (const auto &level : levels) {
const int frequency = level.left(level.indexOf('/')).toInt();
min = std::min(frequency, min);
max = std::max(frequency, max);
}
// value are already in MHz see cpufreq(4)
m_frequency->setMin(min);
m_frequency->setMax(max);
}
}
}
// No wait usage on FreeBSD
void FreeBsdCpuObject::update(long system, long user, long idle)
{
long totalTicks = system + user + idle;
long totalDiff = totalTicks - m_totalTicks;
auto percentage = [totalDiff] (long tickDiff) {
// according to the documentation some counters can go backwards in some circumstances
return tickDiff > 0 ? 100.0 * tickDiff / totalDiff : 0;
};
m_system->setValue(percentage(system - m_systemTicks));
m_user->setValue(percentage(user - m_userTicks));
m_usage->setValue(percentage((system + user) - (m_systemTicks + m_userTicks)));
m_systemTicks = system;
m_userTicks = user;
m_totalTicks = totalTicks;
int frequency;
size_t frequencySize = sizeof(frequency);
const QByteArray name = QByteArrayLiteral("dev.cpu.") + id().right(1).toLocal8Bit() + QByteArrayLiteral(".freq");
if (sysctlbyname(name.constData(), &frequency, &frequencySize, nullptr, 0) != -1) {
// value is already in MHz
m_frequency->setValue(frequency);
}
}
FreeBsdCpuPluginPrivate::FreeBsdCpuPluginPrivate(CpuPlugin* q)
: CpuPluginPrivate(q)
{
// The values used here can be found in smp(4)
unsigned int numCpu;
size_t unsignedIntSize = sizeof(numCpu);
sysctl((int[]){CTL_HW, HW_NCPU}, 2, &numCpu, &unsignedIntSize, nullptr, 0);
for (unsigned int i = 0; i < numCpu; ++i) {
new FreeBsdCpuObject(QStringLiteral("cpu%1").arg(i), i18nc("@title", "CPU %1", i + 1), m_container);
}
// TODO parse smp sysctl kern.sched.topology_spec xml to be able show names like "CPU 1 Core 2"
// Add total usage sensors
auto total = new FreeBsdCpuObject(QStringLiteral("all"), i18nc("@title", "All"), m_container);
auto cpuCount = new SensorProperty(QStringLiteral("cpuCount"), i18nc("@title", "Number of CPUs"), numCpu, total);
cpuCount->setShortName(i18nc("@title, Short fort 'Number of CPUs'", "CPUs"));
cpuCount->setDescription(i18nc("@info", "Number of physical CPUs installed in the system"));
auto coreCount = new SensorProperty(QStringLiteral("coreCount"), i18nc("@title", "Number of Cores"), numCpu, total);
coreCount->setShortName(i18nc("@title, Short fort 'Number of Cores'", "Cores"));
coreCount->setDescription(i18nc("@info", "Number of CPU cores across all physical CPUS"));
}
void FreeBsdCpuPluginPrivate::update()
{
auto updateCpu = [] (FreeBsdCpuObject *cpu, long *cp_time){
cpu->update(cp_time[CP_SYS + CP_INTR], cp_time[CP_USER] + cp_time[CP_NICE], cp_time[CP_IDLE]);
};
unsigned int numCores = m_container->objects().count() - 1;
std::vector<long> cp_times(numCores * CPUSTATES);
size_t cpTimesSize = sizeof(long) * numCores * CPUSTATES;
if (sysctlbyname("kern.cp_times", &cp_times[0], &cpTimesSize, nullptr, 0) != -1) {
for (unsigned int i = 0; i < numCores; ++i) {
auto cpu = static_cast<FreeBsdCpuObject*>(m_container->object(QStringLiteral("cpu%1").arg(i)));
updateCpu(cpu, &cp_times[CPUSTATES * i]);
}
}
// update total values
long cp_time[CPUSTATES];
size_t cpTimeSize = sizeof(long) * CPUSTATES;
if (sysctlbyname("kern.cp_times", cp_time, &cpTimeSize, nullptr, 0) != -1) {
updateCpu(static_cast<FreeBsdCpuObject*>(m_container->object(QStringLiteral("all"))), cp_time);
}
}
#ifndef FREEBSDCPU_H
#define FREEBSDCPU_H
#include "cpu.h"
#include "cpuplugin_p.h"
class FreeBsdCpuObject : public CpuObject {
public:
FreeBsdCpuObject(const QString &id, const QString &name, SensorContainer *parent);
void update(long system, long user, long idle);
private:
long m_totalTicks;
long m_systemTicks;
long m_userTicks;
};
class FreeBsdCpuPluginPrivate : public CpuPluginPrivate {
public:
FreeBsdCpuPluginPrivate(CpuPlugin *q);
void update() override;
};
#endif
......@@ -4,8 +4,6 @@
#include <KLocalizedString>
#include <sensors/sensors.h>
#include <SensorContainer.h>
static double readCpuFreq(const QString &cpuId, const QString &attribute, bool &ok)
......@@ -37,8 +35,9 @@ LinuxCpuObject::LinuxCpuObject(const QString &id, const QString &name, SensorCon
}
}
void LinuxCpuObject::setTicks(unsigned long long system, unsigned long long user, unsigned long long wait, unsigned long long idle)
void LinuxCpuObject::update(unsigned long long system, unsigned long long user, unsigned long long wait, unsigned long long idle)
{
// First calculate usages
unsigned long long totalTicks = system + user + wait + idle;
unsigned long long totalDiff = totalTicks - m_totalTicks;
auto percentage = [totalDiff] (unsigned long long tickDiff) {
......@@ -55,10 +54,8 @@ void LinuxCpuObject::setTicks(unsigned long long system, unsigned long long user
m_systemTicks = system;
m_userTicks = user;
m_waitTicks = wait;
}
void LinuxCpuObject::update()
{
// Second update frequencies
if (!m_frequency) {
return;
}
......@@ -139,9 +136,6 @@ void LinuxCpuPluginPrivate::update()
unsigned long long user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
std::sscanf(line.data(), "%*s %llu %llu %llu %llu %llu %llu %llu %llu%llu %llu",
&user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, &guest_nice);
cpu->setTicks(system + irq + softirq, user + nice , iowait + steal, idle);
}
for (SensorObject *cpu : m_container->objects()) {
static_cast<LinuxCpuObject*>(cpu)->update();
cpu->update(system + irq + softirq, user + nice , iowait + steal, idle);
}
}
......@@ -16,7 +16,6 @@
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef LINUXCPU_H
#define LINUXCPU_H
......@@ -28,8 +27,7 @@ class LinuxCpuObject : public CpuObject
public:
LinuxCpuObject(const QString &id, const QString &name, SensorContainer *parent, double frequency);
void setTicks(unsigned long long system, unsigned long long user, unsigned long long wait, unsigned long long idle);
void update() override;
void update(unsigned long long system, unsigned long long user, unsigned long long wait, unsigned long long idle);
private:
unsigned long long m_totalTicks;
unsigned long long m_systemTicks;
......
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