Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Plasma
KSysGuard
Commits
1bf87804
Commit
1bf87804
authored
Oct 05, 2020
by
David Redondo
🏎
Browse files
Something I am more happy with
parent
d391e4fc
Changes
13
Hide whitespace changes
Inline
Side-by-side
plugins/global/cpu/CMakeLists.txt
View file @
1bf87804
add_library
(
ksysguard_plugin_cpu MODULE cpu.cpp cpuplugin.cpp
)
add_library
(
ksysguard_plugin_cpu MODULE cpu.cpp cpuplugin.cpp
usagecomputer.cpp
)
if
(
CMAKE_SYSTEM_NAME STREQUAL
"Linux"
)
target_sources
(
ksysguard_plugin_cpu PRIVATE linuxcpu.cpp
)
target_sources
(
ksysguard_plugin_cpu PRIVATE linuxcpu.cpp
linuxcpuplugin.cpp
)
elseif
(
CMAKE_SYSTEM_NAME STREQUAL
"FreeBSD"
)
target_sources
(
ksysguard_plugin_cpu PRIVATE freebsdcpu.cpp
)
target_sources
(
ksysguard_plugin_cpu PRIVATE freebsdcpu
plugin
.cpp
)
endif
()
target_link_libraries
(
ksysguard_plugin_cpu Qt5::Core KSysGuard::StatsBackend KF5::CoreAddons KF5::I18n
)
...
...
plugins/global/cpu/cpu.cpp
View file @
1bf87804
...
...
@@ -21,14 +21,9 @@
#include
<KLocalizedString>
CpuObject
::
CpuObject
(
const
QString
&
id
,
const
QString
&
name
,
SensorContainer
*
parent
)
Base
CpuObject
::
Base
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
);
m_usage
=
new
SensorProperty
(
QStringLiteral
(
"usage"
),
i18nc
(
"@title"
,
"Total Usage"
),
this
);
m_usage
->
setPrefix
(
name
);
m_usage
->
setShortName
(
i18nc
(
"@title, Short for 'Total Usage'"
,
"Usage"
));
...
...
@@ -56,19 +51,36 @@ CpuObject::CpuObject(const QString &id, const QString &name, SensorContainer *pa
m_wait
->
setVariantType
(
QVariant
::
Double
);
m_wait
->
setMax
(
100
);
if
(
id
!=
QStringLiteral
(
"all"
))
{
m_frequency
=
new
SensorProperty
(
QStringLiteral
(
"frequency"
),
i18nc
(
"@title"
,
"Current Frequency"
),
this
);
m_frequency
->
setPrefix
(
name
);
m_frequency
->
setShortName
(
i18nc
(
"@title, Short for 'Current Frequency'"
,
"Frequency"
));
m_frequency
->
setDescription
(
i18nc
(
"@info"
,
"Current frequency of the CPU"
));
m_frequency
->
setVariantType
(
QVariant
::
Double
);
m_frequency
->
setUnit
(
KSysGuard
::
Unit
::
UnitMegaHertz
);
auto
n
=
new
SensorProperty
(
QStringLiteral
(
"name"
),
i18nc
(
"@title"
,
"Name"
),
name
,
this
);
n
->
setVariantType
(
QVariant
::
String
);
}
CpuObject
::
CpuObject
(
const
QString
&
id
,
const
QString
&
name
,
SensorContainer
*
parent
)
:
BaseCpuObject
(
id
,
name
,
parent
)
{
m_frequency
=
new
SensorProperty
(
QStringLiteral
(
"frequency"
),
i18nc
(
"@title"
,
"Current Frequency"
),
this
);
m_frequency
->
setPrefix
(
name
);
m_frequency
->
setShortName
(
i18nc
(
"@title, Short for 'Current Frequency'"
,
"Frequency"
));
m_frequency
->
setDescription
(
i18nc
(
"@info"
,
"Current frequency of the CPU"
));
m_frequency
->
setVariantType
(
QVariant
::
Double
);
m_frequency
->
setUnit
(
KSysGuard
::
Unit
::
UnitMegaHertz
);
m_temperature
=
new
SensorProperty
(
QStringLiteral
(
"temperature"
),
i18nc
(
"@title"
,
"Current Temperature"
),
this
);
m_temperature
->
setPrefix
(
name
);
m_temperature
->
setShortName
(
i18nc
(
"@title, Short for Current Temperatur"
,
"Temperature"
));
m_temperature
->
setVariantType
(
QVariant
::
Double
);
m_temperature
->
setUnit
(
KSysGuard
::
Unit
::
UnitCelsius
);
}
AllCpusObject
::
AllCpusObject
(
unsigned
int
cpuCount
,
unsigned
int
coreCount
,
SensorContainer
*
parent
)
:
BaseCpuObject
(
QStringLiteral
(
"all"
),
i18nc
(
"@title"
,
"All"
),
parent
)
{
auto
cpus
=
new
SensorProperty
(
QStringLiteral
(
"cpuCount"
),
i18nc
(
"@title"
,
"Number of CPUs"
),
cpuCount
,
this
);
cpus
->
setShortName
(
i18nc
(
"@title, Short fort 'Number of CPUs'"
,
"CPUs"
));
cpus
->
setDescription
(
i18nc
(
"@info"
,
"Number of physical CPUs installed in the system"
));
m_temperature
=
new
SensorProperty
(
QStringLiteral
(
"temperature"
),
i18nc
(
"@title"
,
"Current Temperature"
),
this
);
m_temperature
->
setPrefix
(
name
);
m_temperature
->
setShortName
(
i18nc
(
"@title, Short for Current Temperatur"
,
"Temperature"
));
m_temperature
->
setVariantType
(
QVariant
::
Double
);
m_temperature
->
setUnit
(
KSysGuard
::
Unit
::
UnitCelsius
);
}
auto
cores
=
new
SensorProperty
(
QStringLiteral
(
"coreCount"
),
i18nc
(
"@title"
,
"Number of Cores"
),
coreCount
,
this
);
cores
->
setShortName
(
i18nc
(
"@title, Short fort 'Number of Cores'"
,
"Cores"
));
cores
->
setDescription
(
i18nc
(
"@info"
,
"Number of CPU cores across all physical CPUS"
));
}
plugins/global/cpu/cpu.h
View file @
1bf87804
...
...
@@ -22,19 +22,31 @@
#include
<SensorObject.h>
class
CpuObject
:
public
SensorObject
{
public:
CpuObject
(
const
QString
&
id
,
const
QString
&
name
,
SensorContainer
*
parent
);
// const int physicalId; // NOTE The combination of these two ids is not necessarily unique with hyperthreading
// const int coreId;
protected:
class
BaseCpuObject
:
public
SensorObject
{
protected:
BaseCpuObject
(
const
QString
&
id
,
const
QString
&
name
,
SensorContainer
*
parent
);
SensorProperty
*
m_usage
;
SensorProperty
*
m_system
;
SensorProperty
*
m_user
;
SensorProperty
*
m_wait
;
};
class
CpuObject
:
public
BaseCpuObject
{
public:
CpuObject
(
const
QString
&
id
,
const
QString
&
name
,
SensorContainer
*
parent
);
protected:
SensorProperty
*
m_frequency
;
SensorProperty
*
m_temperature
;
};
class
AllCpusObject
:
public
BaseCpuObject
{
public:
AllCpusObject
(
unsigned
int
cpuCount
,
unsigned
int
coreCount
,
SensorContainer
*
parent
);
protected:
SensorProperty
*
m_cpuCount
;
SensorProperty
*
m_coreCount
;
};
#endif
plugins/global/cpu/cpuplugin.cpp
View file @
1bf87804
...
...
@@ -25,8 +25,8 @@
#include
<SensorContainer.h>
#include
"freebsdcpu.h"
#include
"linuxcpu.h"
#include
"freebsdcpu
plugin
.h"
#include
"linuxcpu
plugin
.h"
CpuPluginPrivate
::
CpuPluginPrivate
(
CpuPlugin
*
q
)
:
m_container
(
new
SensorContainer
(
QStringLiteral
(
"cpu"
),
i18n
(
"CPUs"
),
q
))
...
...
plugins/global/cpu/cpuplugin_p.h
View file @
1bf87804
...
...
@@ -21,6 +21,7 @@
#define CPUPLUGIN_P_H
class
CpuPlugin
;
class
SensorContainer
;
class
CpuPluginPrivate
{
public:
...
...
plugins/global/cpu/freebsdcpu.cpp
→
plugins/global/cpu/freebsdcpu
plugin
.cpp
View file @
1bf87804
#include
"freebsdcpu.h"
#include
"freebsdcpu
plugin
.h"
#include
<algorithm>
#include
<vector>
...
...
@@ -19,59 +19,44 @@ bool readSysctl(const char *name, T *buffer, size_t size = sizeof(T)) {
FreeBsdCpuObject
::
FreeBsdCpuObject
(
const
QString
&
id
,
const
QString
&
name
,
SensorContainer
*
parent
)
:
CpuObject
(
id
,
name
,
parent
)
{
if
(
id
!=
QStringLiteral
(
"all"
))
{
// 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
);
// 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
);
}
const
QByteArray
tjmax
=
QByteArrayLiteral
(
"dev.cpu."
)
+
id
.
right
(
1
).
toLocal8Bit
()
+
QByteArrayLiteral
(
".coretemp.tjmax"
);
int
maxTemperature
;
size_t
maxTemperatureSize
=
sizeof
(
maxTemperature
)
;
// This is only availabel on Intel (using the coretemp driver)
if
(
readSysctl
(
tjmax
.
constData
(),
&
maxTemperature
))
{
m_temperature
->
setMax
(
maxTemperature
)
;
}
}
const
QByteArray
tjmax
=
QByteArrayLiteral
(
"dev.cpu."
)
+
id
.
right
(
1
).
toLocal8Bit
()
+
QByteArrayLiteral
(
".coretemp.tjmax"
)
;
int
maxTemperature
;
size_t
maxTemperatureSize
=
sizeof
(
maxTemperature
);
// This is only availabel on Intel (using the coretemp driver)
if
(
readSysctl
(
tjmax
.
constData
(),
&
maxTemperature
)
)
{
m_temperature
->
setMax
(
maxTemperature
);
}
}
// 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
;
};
// No wait usage on FreeBSD
m_usageComputer
.
setTicks
(
system
,
user
,
0
,
idle
);
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
;
if
(
id
()
==
QStringLiteral
(
"all"
))
{
return
;
}
m_system
->
setValue
(
m_usageComputer
.
systemUsage
);
m_user
->
setValue
(
m_usageComputer
.
userUsage
);
m_usage
->
setValue
(
m_usageComputer
.
totalUsage
);
int
frequency
;
const
QByteArray
prefix
=
QByteArrayLiteral
(
"dev.cpu."
)
+
id
().
right
(
1
).
toLocal8Bit
();
...
...
@@ -87,6 +72,16 @@ void FreeBsdCpuObject::update(long system, long user, long idle)
}
}
void
FreeBsdAllCpusObject
::
update
(
long
system
,
long
user
,
long
idle
)
{
// No wait usage on FreeBSD
m_usageComputer
.
setTicks
(
system
,
user
,
0
,
idle
);
m_system
->
setValue
(
m_usageComputer
.
systemUsage
);
m_user
->
setValue
(
m_usageComputer
.
userUsage
);
m_usage
->
setValue
(
m_usageComputer
.
totalUsage
);
}
FreeBsdCpuPluginPrivate
::
FreeBsdCpuPluginPrivate
(
CpuPlugin
*
q
)
:
CpuPluginPrivate
(
q
)
...
...
@@ -97,21 +92,12 @@ FreeBsdCpuPluginPrivate::FreeBsdCpuPluginPrivate(CpuPlugin* q)
for
(
int
i
=
0
;
i
<
numCpu
;
++
i
)
{
new
FreeBsdCpuObject
(
QStringLiteral
(
"cpu%1"
).
arg
(
i
),
i18nc
(
"@title"
,
"CPU %1"
,
i
+
1
),
m_container
);
}
// 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"
));
new
FreeBsdAllCpusObject
(
numCpu
,
numCpu
,
m_container
);
}
void
FreeBsdCpuPluginPrivate
::
update
()
{
auto
updateCpu
=
[]
(
FreeBsdCpuObject
*
cpu
,
long
*
cp_time
){
auto
updateCpu
=
[]
(
auto
*
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
;
...
...
plugins/global/cpu/freebsdcpu.h
→
plugins/global/cpu/freebsdcpu
plugin
.h
View file @
1bf87804
...
...
@@ -3,15 +3,22 @@
#include
"cpu.h"
#include
"cpuplugin_p.h"
#include
"usagecomputer.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
;
UsageComputer
m_usageComputer
;
};
class
FreeBsdAllCpusObject
:
public
AllCpusObject
{
public:
using
AllCpusObject
::
AllCpusObject
;
void
update
(
long
system
,
long
user
,
long
idle
);
private:
UsageComputer
m_usageComputer
;
};
class
FreeBsdCpuPluginPrivate
:
public
CpuPluginPrivate
{
...
...
plugins/global/cpu/linuxcpu.cpp
View file @
1bf87804
...
...
@@ -2,14 +2,10 @@
#include
<QFile>
#include
<KLocalizedString>
#ifdef HAVE_SENSORS
#include
<sensors/sensors.h>
#endif
#include
<SensorContainer.h>
static
double
readCpuFreq
(
const
QString
&
cpuId
,
const
QString
&
attribute
,
bool
&
ok
)
{
QFile
file
(
QStringLiteral
(
"/sys/devices/system/cpu/%1/cpufreq/"
).
arg
(
cpuId
)
+
attribute
);
...
...
@@ -26,17 +22,15 @@ LinuxCpuObject::LinuxCpuObject(const QString &id, const QString &name, SensorCon
,
m_sensorChipName
{
nullptr
}
,
m_temperatureSubfeature
{
-
1
}
{
if
(
m_frequency
)
{
m_frequency
->
setValue
(
frequency
);
bool
ok
;
const
double
max
=
readCpuFreq
(
id
,
"cpuinfo_max_freq"
,
ok
);
if
(
ok
)
{
m_frequency
->
setMax
(
max
);
}
const
double
min
=
readCpuFreq
(
id
,
"cpuinfo_min_freq"
,
ok
);
if
(
ok
)
{
m_frequency
->
setMin
(
min
);
}
m_frequency
->
setValue
(
frequency
);
bool
ok
;
const
double
max
=
readCpuFreq
(
id
,
"cpuinfo_max_freq"
,
ok
);
if
(
ok
)
{
m_frequency
->
setMax
(
max
);
}
const
double
min
=
readCpuFreq
(
id
,
"cpuinfo_min_freq"
,
ok
);
if
(
ok
)
{
m_frequency
->
setMin
(
min
);
}
}
...
...
@@ -63,28 +57,15 @@ void LinuxCpuObject::setTemperatureSensor(const sensors_chip_name * const chipNa
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
)
{
// 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_wait
->
setValue
(
percentage
(
wait
-
m_waitTicks
));
m_usage
->
setValue
(
percentage
((
system
+
user
+
wait
)
-
(
m_systemTicks
+
m_userTicks
+
m_waitTicks
)));
// First update usages
m_usageComputer
.
setTicks
(
system
,
user
,
wait
,
idle
);
m_
totalTicks
=
totalTicks
;
m_
systemTicks
=
system
;
m_
userTicks
=
user
;
m_
waitTicks
=
wait
;
m_
system
->
setValue
(
m_usageComputer
.
systemUsage
)
;
m_
user
->
setValue
(
m_usageComputer
.
userUsage
)
;
m_
wait
->
setValue
(
m_usageComputer
.
waitUsage
)
;
m_
usage
->
setValue
(
m_usageComputer
.
totalUsage
)
;
// Second update frequencies
if
(
!
m_frequency
)
{
return
;
}
// Second try to get current frequency
bool
ok
=
false
;
// First try cpuinfo_cur_freq, it is the frequency the hardware runs at (https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html)
int
frequency
=
readCpuFreq
(
id
(),
"cpuinfo_cur_freq"
,
ok
);
...
...
@@ -108,179 +89,13 @@ void LinuxCpuObject::update(unsigned long long system, unsigned long long user,
#endif
}
LinuxCpuPluginPrivate
::
LinuxCpuPluginPrivate
(
CpuPlugin
*
q
)
:
CpuPluginPrivate
(
q
)
{
// Parse /proc/cpuinfo
QFile
cpuinfo
(
"/proc/cpuinfo"
);
cpuinfo
.
open
(
QIODevice
::
ReadOnly
);
QHash
<
int
,
int
>
numCores
;
for
(
QByteArray
line
=
cpuinfo
.
readLine
();
!
line
.
isEmpty
();
line
=
cpuinfo
.
readLine
())
{
unsigned
int
processor
,
physicalId
,
coreId
;
double
frequency
=
0
;
// Processors are divided by empty lines
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. 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
();
if
(
field
==
"processor"
)
{
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"
,
physicalId
+
1
,
++
numCores
[
physicalId
]);
auto
cpu
=
new
LinuxCpuObject
(
QStringLiteral
(
"cpu%1"
).
arg
(
processor
),
name
,
m_container
,
frequency
);
m_cpusBySystemIds
.
insert
({
physicalId
,
coreId
},
cpu
);
}
const
int
cores
=
m_container
->
objects
().
size
();
// Add total usage sensors
auto
total
=
new
LinuxCpuObject
(
QStringLiteral
(
"all"
),
i18nc
(
"@title"
,
"All"
),
m_container
,
0
);
auto
cpuCount
=
new
SensorProperty
(
QStringLiteral
(
"cpuCount"
),
i18nc
(
"@title"
,
"Number of CPUs"
),
numCores
.
size
(),
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"
),
cores
,
total
);
coreCount
->
setShortName
(
i18nc
(
"@title, Short fort 'Number of Cores'"
,
"Cores"
));
coreCount
->
setDescription
(
i18nc
(
"@info"
,
"Number of CPU cores across all physical CPUS"
));
addSensors
();
}
void
LinuxAllCpusObject
::
update
(
unsigned
long
long
system
,
unsigned
long
long
user
,
unsigned
long
long
wait
,
unsigned
long
long
idle
)
{
m_usageComputer
.
setTicks
(
system
,
user
,
wait
,
idle
);
void
LinuxCpuPluginPrivate
::
update
()
{
// Parse /proc/stat to get usage values. The format is described at
// https://www.kernel.org/doc/html/latest/filesystems/proc.html#miscellaneous-kernel-statistics-in-proc-stat
QFile
stat
(
"/proc/stat"
);
stat
.
open
(
QIODevice
::
ReadOnly
);
QByteArray
line
;
for
(
QByteArray
line
=
stat
.
readLine
();
!
line
.
isNull
();
line
=
stat
.
readLine
())
{
LinuxCpuObject
*
cpu
;
// Total values
if
(
line
.
startsWith
(
"cpu "
))
{
cpu
=
static_cast
<
LinuxCpuObject
*>
(
m_container
->
object
(
QStringLiteral
(
"all"
)));
}
else
if
(
line
.
startsWith
(
"cpu"
))
{
cpu
=
static_cast
<
LinuxCpuObject
*>
(
m_container
->
object
(
line
.
left
(
line
.
indexOf
(
' '
))));
}
else
{
continue
;
}
auto
values
=
line
.
split
(
' '
);
unsigned
long
long
user
=
values
[
1
].
toULongLong
();
unsigned
long
long
nice
=
values
[
2
].
toULongLong
();
unsigned
long
long
system
=
values
[
3
].
toULongLong
();
unsigned
long
long
idle
=
values
[
4
].
toULongLong
();
unsigned
long
long
iowait
=
values
[
5
].
toULongLong
();
unsigned
long
long
irq
=
values
[
6
].
toULongLong
();
unsigned
long
long
softirq
=
values
[
7
].
toULongLong
();
unsigned
long
long
steal
=
values
[
8
].
toULongLong
();
cpu
->
update
(
system
+
irq
+
softirq
,
user
+
nice
,
iowait
+
steal
,
idle
);
}
m_system
->
setValue
(
m_usageComputer
.
systemUsage
);
m_user
->
setValue
(
m_usageComputer
.
userUsage
);
m_wait
->
setValue
(
m_usageComputer
.
waitUsage
);
m_usage
->
setValue
(
m_usageComputer
.
totalUsage
);
}
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
);
}
else
if
(
qstrcmp
(
chipName
->
prefix
,
"k10temp"
)
==
0
)
{
addSensorsAmd
(
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
))
{
if
(
feature
->
type
!=
SENSORS_FEATURE_TEMP
)
{
continue
;
}
char
*
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
);
}
free
(
sensorLabel
);
}
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
)
{
(
*
cpu_it
)
->
setTemperatureSensor
(
chipName
,
feature
.
value
());
}
}
}
#endif
}
void
LinuxCpuPluginPrivate
::
addSensorsAmd
(
const
sensors_chip_name
*
const
chipName
)
{
// All Processors should have the Tctl pseudo temperature as temp1. Newer ones have the real die
// temperature Tdie as temp2. Some of those have temperatures for each core complex die (CCD) as
// temp3-6 or temp3-10 depending on the number of CCDS.
// https://www.kernel.org/doc/html/latest/hwmon/k10temp.html
int
featureNumber
=
0
;
sensors_feature
const
*
tctl
=
nullptr
;
sensors_feature
const
*
tdie
=
nullptr
;
sensors_feature
const
*
tccd
[
8
]
=
{
nullptr
};
while
(
sensors_feature
const
*
feature
=
sensors_get_features
(
chipName
,
&
featureNumber
))
{
const
QByteArray
name
(
feature
->
name
);
if
(
feature
->
type
!=
SENSORS_FEATURE_TEMP
||
!
name
.
startsWith
(
"temp"
))
{
continue
;
}
// For temps 1 and 2 we can't just go by the number because in kernels older than 5.7 they
// are the wrong way around, so we have to compare labels.
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b02c6857389da66b09e447103bdb247ccd182456
char
*
label
=
sensors_get_label
(
chipName
,
feature
);
if
(
qstrcmp
(
label
,
"Tctl"
)
==
0
)
{
tctl
=
feature
;
}
else
if
(
qstrcmp
(
label
,
"Tdie"
)
==
0
)
{
tdie
=
feature
;
}
else
{
tccd
[
name
.
mid
(
4
).
toUInt
()]
=
feature
;
}
free
(
label
);
}
// TODO How to map CCD temperatures to cores?
auto
setSingleSensor
=
[
this
,
chipName
]
(
const
sensors_feature
*
const
feature
)
{
for
(
auto
&
cpu
:
m_cpusBySystemIds
)
{
cpu
->
setTemperatureSensor
(
chipName
,
feature
);
}
};
if
(
tdie
)
{
setSingleSensor
(
tdie
);
}
else
if
(
tctl
)
{
setSingleSensor
(
tctl
);
}
}
plugins/global/cpu/linuxcpu.h
View file @
1bf87804
/*
Copyright (c) 2020 David Redondo <kde@david-redondo.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef LINUXCPU_H
#define LINUXCPU_H
#include
<QHash>