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
237c8843
Commit
237c8843
authored
Oct 02, 2020
by
Arjen Hiemstra
Browse files
Add initial GPU plugin
Only AMD GPUs on Linux supported so far, but those report a nice set of details.
parent
3a30493b
Changes
16
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
237c8843
...
...
@@ -92,6 +92,13 @@ if (libpcap_FOUND)
)
endif
()
find_package
(
UDev
)
set_package_properties
(
UDev PROPERTIES
TYPE RECOMMENDED
PURPOSE
"UDev is used for finding graphics cards."
)
include_directories
(
${
CMAKE_CURRENT_BINARY_DIR
}
)
configure_file
(
config-workspace.h.cmake
${
CMAKE_CURRENT_BINARY_DIR
}
/config-workspace.h
)
...
...
plugins/global/CMakeLists.txt
View file @
237c8843
...
...
@@ -6,3 +6,7 @@ add_subdirectory(network)
add_subdirectory
(
power
)
add_subdirectory
(
disks
)
add_subdirectory
(
cpu
)
if
(
UDev_FOUND
)
add_subdirectory
(
gpu
)
endif
()
plugins/global/gpu/CMakeLists.txt
0 → 100644
View file @
237c8843
set
(
KSYSGUARD_GPU_PLUGIN_SOURCES
GpuPlugin.cpp
GpuBackend.cpp
GpuDevice.cpp
LinuxAmdGpu.cpp
LinuxBackend.cpp
SysFsSensor.cpp
)
add_library
(
ksysguard_plugin_gpu MODULE
${
KSYSGUARD_GPU_PLUGIN_SOURCES
}
)
target_link_libraries
(
ksysguard_plugin_gpu Qt5::Core Qt5::DBus KSysGuard::StatsBackend KF5::CoreAddons KF5::I18n UDev::UDev
)
install
(
TARGETS ksysguard_plugin_gpu DESTINATION
${
KDE_INSTALL_PLUGINDIR
}
/ksysguard
)
plugins/global/gpu/GpuBackend.cpp
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include
"GpuBackend.h"
plugins/global/gpu/GpuBackend.h
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include
<QObject>
class
GpuDevice
;
class
GpuBackend
:
public
QObject
{
Q_OBJECT
public:
GpuBackend
(
QObject
*
parent
=
nullptr
)
:
QObject
(
parent
)
{
}
~
GpuBackend
()
override
=
default
;
virtual
void
start
()
=
0
;
virtual
void
stop
()
=
0
;
virtual
void
update
()
=
0
;
Q_SIGNAL
void
deviceAdded
(
GpuDevice
*
device
);
Q_SIGNAL
void
deviceRemoved
(
GpuDevice
*
device
);
};
plugins/global/gpu/GpuDevice.cpp
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include
"GpuDevice.h"
#include
<KLocalizedString>
GpuDevice
::
GpuDevice
(
const
QString
&
id
,
const
QString
&
name
)
:
SensorObject
(
id
,
name
)
{
}
void
GpuDevice
::
initialize
()
{
makeSensors
();
m_nameProperty
->
setName
(
i18nc
(
"@title"
,
"Name"
));
m_nameProperty
->
setPrefix
(
name
());
m_nameProperty
->
setValue
(
name
());
m_usageProperty
->
setName
(
i18nc
(
"@title"
,
"Usage"
));
m_usageProperty
->
setPrefix
(
name
());
m_usageProperty
->
setMin
(
0
);
m_usageProperty
->
setMax
(
100
);
m_usageProperty
->
setUnit
(
KSysGuard
::
UnitPercent
);
m_totalVramProperty
->
setName
(
i18nc
(
"@title"
,
"Total Video Memory"
));
m_totalVramProperty
->
setPrefix
(
name
());
m_totalVramProperty
->
setShortName
(
i18nc
(
"@title Short for Total Video Memory"
,
"Total"
));
m_totalVramProperty
->
setUnit
(
KSysGuard
::
UnitByte
);
m_usedVramProperty
->
setName
(
i18nc
(
"@title"
,
"Video Memory Used"
));
m_usedVramProperty
->
setPrefix
(
name
());
m_usedVramProperty
->
setShortName
(
i18nc
(
"@title Short for Video Memory Used"
,
"Used"
));
m_usedVramProperty
->
setMax
(
m_totalVramProperty
);
m_usedVramProperty
->
setUnit
(
KSysGuard
::
UnitByte
);
m_coreFrequencyProperty
->
setName
(
i18nc
(
"@title"
,
"Frequency"
));
m_coreFrequencyProperty
->
setPrefix
(
name
());
m_coreFrequencyProperty
->
setUnit
(
KSysGuard
::
UnitMegaHertz
);
m_memoryFrequencyProperty
->
setName
(
i18nc
(
"@title"
,
"Memory Frequency"
));
m_memoryFrequencyProperty
->
setPrefix
(
name
());
m_memoryFrequencyProperty
->
setUnit
(
KSysGuard
::
UnitMegaHertz
);
m_coreTemperatureProperty
->
setName
(
i18nc
(
"@title"
,
"Temperature"
));
m_coreTemperatureProperty
->
setPrefix
(
name
());
m_coreTemperatureProperty
->
setUnit
(
KSysGuard
::
UnitCelsius
);
m_memoryTemperatureProperty
->
setName
(
i18nc
(
"@title"
,
"Memory Temperature"
));
m_memoryTemperatureProperty
->
setPrefix
(
name
());
m_memoryTemperatureProperty
->
setUnit
(
KSysGuard
::
UnitCelsius
);
}
void
GpuDevice
::
makeSensors
()
{
m_nameProperty
=
new
SensorProperty
(
QStringLiteral
(
"name"
),
this
);
m_usageProperty
=
new
SensorProperty
(
QStringLiteral
(
"usage"
),
this
);
m_totalVramProperty
=
new
SensorProperty
(
QStringLiteral
(
"totalVram"
),
this
);
m_usedVramProperty
=
new
SensorProperty
(
QStringLiteral
(
"usedVram"
),
this
);
m_coreFrequencyProperty
=
new
SensorProperty
(
QStringLiteral
(
"coreFrequency"
),
this
);
m_memoryFrequencyProperty
=
new
SensorProperty
(
QStringLiteral
(
"memoryFrequency"
),
this
);
m_coreTemperatureProperty
=
new
SensorProperty
(
QStringLiteral
(
"coreTemperature"
),
this
);
m_memoryTemperatureProperty
=
new
SensorProperty
(
QStringLiteral
(
"memoryTemperature"
),
this
);
}
plugins/global/gpu/GpuDevice.h
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include
<QObject>
#include
"SensorObject.h"
class
GpuDevice
:
public
SensorObject
{
Q_OBJECT
public:
GpuDevice
(
const
QString
&
id
,
const
QString
&
name
);
~
GpuDevice
()
override
=
default
;
virtual
void
initialize
();
virtual
void
update
()
=
0
;
protected:
virtual
void
makeSensors
();
SensorProperty
*
m_nameProperty
;
SensorProperty
*
m_usageProperty
;
SensorProperty
*
m_totalVramProperty
;
SensorProperty
*
m_usedVramProperty
;
SensorProperty
*
m_coreTemperatureProperty
;
SensorProperty
*
m_memoryTemperatureProperty
;
SensorProperty
*
m_coreFrequencyProperty
;
SensorProperty
*
m_memoryFrequencyProperty
;
};
plugins/global/gpu/GpuPlugin.cpp
0 → 100644
View file @
237c8843
/*
Copyright (c) 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
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.
*/
#include
"GpuPlugin.h"
#include
<KPluginFactory>
#include
<KLocalizedString>
#include
<SensorContainer.h>
#include
"GpuDevice.h"
#include
"LinuxBackend.h"
class
GpuPlugin
::
Private
{
public:
std
::
unique_ptr
<
SensorContainer
>
container
;
std
::
unique_ptr
<
GpuBackend
>
backend
;
};
GpuPlugin
::
GpuPlugin
(
QObject
*
parent
,
const
QVariantList
&
args
)
:
SensorPlugin
(
parent
,
args
)
,
d
(
std
::
make_unique
<
Private
>
())
{
d
->
container
=
std
::
make_unique
<
SensorContainer
>
(
QStringLiteral
(
"gpu"
),
i18nc
(
"@title"
,
"GPU"
),
this
);
#ifdef Q_OS_LINUX
d
->
backend
=
std
::
make_unique
<
LinuxBackend
>
();
#endif
if
(
d
->
backend
)
{
connect
(
d
->
backend
.
get
(),
&
GpuBackend
::
deviceAdded
,
this
,
[
this
](
GpuDevice
*
device
)
{
d
->
container
->
addObject
(
device
);
});
connect
(
d
->
backend
.
get
(),
&
GpuBackend
::
deviceRemoved
,
this
,
[
this
](
GpuDevice
*
device
)
{
d
->
container
->
removeObject
(
device
);
});
d
->
backend
->
start
();
}
}
GpuPlugin
::~
GpuPlugin
()
{
d
->
container
.
reset
();
if
(
d
->
backend
)
{
d
->
backend
->
stop
();
}
}
void
GpuPlugin
::
update
()
{
if
(
d
->
backend
)
{
d
->
backend
->
update
();
}
}
K_PLUGIN_CLASS_WITH_JSON
(
GpuPlugin
,
"metadata.json"
)
#include
"GpuPlugin.moc"
plugins/global/gpu/GpuPlugin.h
0 → 100644
View file @
237c8843
/*
Copyright (c) 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
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.
*/
#pragma once
#include
<memory>
#include
"SensorPlugin.h"
class
GpuPlugin
:
public
SensorPlugin
{
Q_OBJECT
public:
GpuPlugin
(
QObject
*
parent
,
const
QVariantList
&
args
);
~
GpuPlugin
();
QString
providerName
()
const
override
{
return
QStringLiteral
(
"gpu"
);
}
void
update
()
override
;
private:
class
Private
;
std
::
unique_ptr
<
Private
>
d
;
};
plugins/global/gpu/LinuxAmdGpu.cpp
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include
"LinuxAmdGpu.h"
#include
<libudev.h>
#include
<QDir>
#include
"SysFsSensor.h"
int
ppTableGetMax
(
const
QByteArray
&
table
)
{
const
auto
lines
=
table
.
split
(
'\n'
);
auto
line
=
lines
.
last
();
return
std
::
atoi
(
line
.
mid
(
line
.
indexOf
(
':'
)
+
1
).
data
());
}
int
ppTableGetCurrent
(
const
QByteArray
&
table
)
{
const
auto
lines
=
table
.
split
(
'\n'
);
int
current
=
0
;
for
(
auto
line
:
lines
)
{
if
(
!
line
.
contains
(
'*'
))
{
continue
;
}
current
=
std
::
atoi
(
line
.
mid
(
line
.
indexOf
(
':'
)
+
1
));
}
return
current
;
}
LinuxAmdGpu
::
LinuxAmdGpu
(
const
QString
&
id
,
const
QString
&
name
,
udev_device
*
device
)
:
GpuDevice
(
id
,
name
)
,
m_device
(
device
)
{
udev_device_ref
(
m_device
);
}
LinuxAmdGpu
::~
LinuxAmdGpu
()
{
udev_device_unref
(
m_device
);
}
void
LinuxAmdGpu
::
initialize
()
{
// Find temprature sensor paths.
// Temperature sensors are exposed in the "hwmon" subdirectory of the
// device, but in a subdirectory with a number appended that differs per
// device. So search through the hwmon directory for the files that we want.
QDir
hwmonDir
(
QString
::
fromLocal8Bit
(
udev_device_get_syspath
(
m_device
))
%
QStringLiteral
(
"/hwmon"
));
const
auto
entries
=
hwmonDir
.
entryList
({
QStringLiteral
(
"hwmon*"
)});
for
(
auto
entry
:
entries
)
{
QString
inputPath
=
entry
%
QStringLiteral
(
"/temp1_input"
);
QString
critPath
=
entry
%
QStringLiteral
(
"/temp1_crit"
);
if
(
hwmonDir
.
exists
(
inputPath
)
&&
hwmonDir
.
exists
(
critPath
))
{
m_coreTemperatureCurrentPath
=
QStringLiteral
(
"hwmon/"
)
%
inputPath
;
m_coreTemperatureMaxPath
=
QStringLiteral
(
"hwmon/"
)
%
critPath
;
break
;
}
}
GpuDevice
::
initialize
();
m_nameProperty
->
setValue
(
QString
::
fromLocal8Bit
(
udev_device_get_property_value
(
m_device
,
"ID_MODEL_FROM_DATABASE"
)));
auto
result
=
udev_device_get_sysattr_value
(
m_device
,
"mem_info_vram_total"
);
if
(
result
)
{
m_totalVramProperty
->
setValue
(
std
::
atoll
(
result
));
}
m_coreFrequencyProperty
->
setMax
(
ppTableGetMax
(
udev_device_get_sysattr_value
(
m_device
,
"pp_dpm_sclk"
)));
m_memoryFrequencyProperty
->
setMax
(
ppTableGetMax
(
udev_device_get_sysattr_value
(
m_device
,
"pp_dpm_mclk"
)));
result
=
udev_device_get_sysattr_value
(
m_device
,
m_coreTemperatureMaxPath
.
toLocal8Bit
());
if
(
result
)
{
m_coreTemperatureProperty
->
setMax
(
std
::
atoi
(
result
)
/
1000
);
}
}
void
LinuxAmdGpu
::
update
()
{
for
(
auto
sensor
:
m_sysFsSensors
)
{
sensor
->
update
();
}
}
void
LinuxAmdGpu
::
makeSensors
()
{
auto
devicePath
=
QString
::
fromLocal8Bit
(
udev_device_get_syspath
(
m_device
));
m_nameProperty
=
new
SensorProperty
(
QStringLiteral
(
"name"
),
this
);
m_totalVramProperty
=
new
SensorProperty
(
QStringLiteral
(
"totalVram"
),
this
);
auto
sensor
=
new
SysFsSensor
(
QStringLiteral
(
"usage"
),
devicePath
%
QStringLiteral
(
"/gpu_busy_percent"
),
this
);
m_usageProperty
=
sensor
;
m_sysFsSensors
<<
sensor
;
sensor
=
new
SysFsSensor
(
QStringLiteral
(
"usedVram"
),
devicePath
%
QStringLiteral
(
"/mem_info_vram_used"
),
this
);
m_usedVramProperty
=
sensor
;
m_sysFsSensors
<<
sensor
;
sensor
=
new
SysFsSensor
(
QStringLiteral
(
"coreFrequency"
),
devicePath
%
QStringLiteral
(
"/pp_dpm_sclk"
),
this
);
sensor
->
setConvertFunction
([](
const
QByteArray
&
input
)
{
return
ppTableGetCurrent
(
input
);
});
m_coreFrequencyProperty
=
sensor
;
m_sysFsSensors
<<
sensor
;
sensor
=
new
SysFsSensor
(
QStringLiteral
(
"memoryFrequency"
),
devicePath
%
QStringLiteral
(
"/pp_dpm_mclk"
),
this
);
sensor
->
setConvertFunction
([](
const
QByteArray
&
input
)
{
return
ppTableGetCurrent
(
input
);
});
m_memoryFrequencyProperty
=
sensor
;
m_sysFsSensors
<<
sensor
;
sensor
=
new
SysFsSensor
(
QStringLiteral
(
"coreTemperature"
),
devicePath
%
QLatin1Char
(
'/'
)
%
m_coreTemperatureCurrentPath
,
this
);
sensor
->
setConvertFunction
([](
const
QByteArray
&
input
)
{
auto
result
=
std
::
atoi
(
input
);
return
result
/
1000
;
});
m_coreTemperatureProperty
=
sensor
;
m_sysFsSensors
<<
sensor
;
m_memoryTemperatureProperty
=
new
SensorProperty
(
QStringLiteral
(
"memoryTemperature"
),
this
);
}
plugins/global/gpu/LinuxAmdGpu.h
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include
<QObject>
#include
"GpuDevice.h"
struct
udev_device
;
class
SysFsSensor
;
class
LinuxAmdGpu
:
public
GpuDevice
{
Q_OBJECT
public:
LinuxAmdGpu
(
const
QString
&
id
,
const
QString
&
name
,
udev_device
*
device
);
~
LinuxAmdGpu
()
override
;
void
initialize
()
override
;
void
update
()
override
;
protected:
void
makeSensors
()
override
;
private:
udev_device
*
m_device
;
QVector
<
SysFsSensor
*>
m_sysFsSensors
;
QString
m_coreTemperatureCurrentPath
;
QString
m_coreTemperatureMaxPath
;
};
plugins/global/gpu/LinuxBackend.cpp
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include
"LinuxBackend.h"
#include
<QDebug>
#include
<QDir>
#include
<KLocalizedString>
#include
<libudev.h>
#include
"LinuxAmdGpu.h"
// Vendor ID strings, as used in sysfs
static
const
char
*
amdVendor
=
"0x1002"
;
static
const
char
*
intelVendor
=
"0x8086"
;
static
const
char
*
nvidiaVendor
=
"0x10de"
;
LinuxBackend
::
LinuxBackend
(
QObject
*
parent
)
:
GpuBackend
(
parent
)
{
}
void
LinuxBackend
::
start
()
{
if
(
!
m_udev
)
{
m_udev
=
udev_new
();
}
auto
enumerate
=
udev_enumerate_new
(
m_udev
);
udev_enumerate_add_match_property
(
enumerate
,
"ID_PCI_CLASS_FROM_DATABASE"
,
"Display controller"
);
udev_enumerate_scan_devices
(
enumerate
);
int
gpuCounter
=
0
;
auto
devices
=
udev_enumerate_get_list_entry
(
enumerate
);
for
(
auto
entry
=
devices
;
entry
;
entry
=
udev_list_entry_get_next
(
entry
))
{
auto
path
=
udev_list_entry_get_name
(
entry
);
auto
device
=
udev_device_new_from_syspath
(
m_udev
,
path
);
auto
vendor
=
QByteArray
(
udev_device_get_sysattr_value
(
device
,
"vendor"
));
GpuDevice
*
gpu
=
nullptr
;
if
(
vendor
==
amdVendor
)
{
gpu
=
new
LinuxAmdGpu
{
QStringLiteral
(
"gpu%1"
).
arg
(
gpuCounter
),
i18nc
(
"@title %1 is GPU number"
,
"GPU %1"
,
gpuCounter
+
1
),
device
};
}
else
if
(
vendor
==
intelVendor
)
{
}
else
if
(
vendor
==
nvidiaVendor
)
{
}
if
(
gpu
)
{
gpuCounter
++
;
gpu
->
initialize
();
m_devices
.
append
(
gpu
);
Q_EMIT
deviceAdded
(
gpu
);
}
udev_device_unref
(
device
);
}
udev_enumerate_unref
(
enumerate
);
}
void
LinuxBackend
::
stop
()
{
qDeleteAll
(
m_devices
);
udev_unref
(
m_udev
);
}
void
LinuxBackend
::
update
()
{
for
(
auto
device
:
qAsConst
(
m_devices
))
{
device
->
update
();
}
}
plugins/global/gpu/LinuxBackend.h
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include
"GpuBackend.h"
struct
udev
;
class
GpuDevice
;
class
LinuxBackend
:
public
GpuBackend
{
Q_OBJECT
public:
LinuxBackend
(
QObject
*
parent
=
nullptr
);
void
start
()
override
;
void
stop
()
override
;
void
update
()
override
;
private:
udev
*
m_udev
;
QVector
<
GpuDevice
*>
m_devices
;
};
plugins/global/gpu/SysFsSensor.cpp
0 → 100644
View file @
237c8843
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include
"SysFsSensor.h"
#include
<QFile>
SysFsSensor
::
SysFsSensor
(
const
QString
&
id
,
const
QString
&
path
,
SensorObject
*
parent
)
:
SensorProperty
(
id
,
parent
)
{
m_path
=
path
;
m_convertFunction
=
[](
const
QByteArray
&
input
)
{
return
std
::
atoll
(
input
);
};
}
void
SysFsSensor
::
setConvertFunction
(
const
std
::
function
<
QVariant
(
const
QByteArray
&
)
>&
function
)
{
m_convertFunction
=
function
;
}
void
SysFsSensor
::
update
()
{
if
(
!
isSubscribed
())
{
return
;
}
QFile
file
(
m_path
);