Skip to content
GitLab
Menu
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
f0c691d4
Commit
f0c691d4
authored
Oct 07, 2020
by
Arjen Hiemstra
Browse files
Add initial NVidia GPU support to GPU plugin
Ported from the "nvidia" plugin
parent
237c8843
Changes
5
Hide whitespace changes
Inline
Side-by-side
plugins/global/gpu/CMakeLists.txt
View file @
f0c691d4
...
...
@@ -3,8 +3,10 @@ set(KSYSGUARD_GPU_PLUGIN_SOURCES
GpuBackend.cpp
GpuDevice.cpp
LinuxAmdGpu.cpp
LinuxNvidiaGpu.cpp
LinuxBackend.cpp
SysFsSensor.cpp
NvidiaSmiProcess.cpp
)
add_library
(
ksysguard_plugin_gpu MODULE
${
KSYSGUARD_GPU_PLUGIN_SOURCES
}
)
...
...
plugins/global/gpu/LinuxNvidiaGpu.cpp
0 → 100644
View file @
f0c691d4
/*
* 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 "LinuxNvidiaGpu.h"
#include "NvidiaSmiProcess.h"
NvidiaSmiProcess
*
LinuxNvidiaGpu
::
s_smiProcess
=
nullptr
;
LinuxNvidiaGpu
::
LinuxNvidiaGpu
(
int
index
,
const
QString
&
id
,
const
QString
&
name
)
:
GpuDevice
(
id
,
name
)
,
m_index
(
index
)
{
if
(
!
s_smiProcess
)
{
s_smiProcess
=
new
NvidiaSmiProcess
();
}
connect
(
s_smiProcess
,
&
NvidiaSmiProcess
::
dataReceived
,
this
,
&
LinuxNvidiaGpu
::
onDataReceived
);
}
LinuxNvidiaGpu
::~
LinuxNvidiaGpu
()
{
}
void
LinuxNvidiaGpu
::
initialize
()
{
GpuDevice
::
initialize
();
for
(
auto
sensor
:
{
m_usageProperty
,
m_totalVramProperty
,
m_usedVramProperty
,
m_temperatureProperty
,
m_coreFrequencyProperty
,
m_memoryFrequencyProperty
})
{
connect
(
sensor
,
&
SensorProperty
::
subscribedChanged
,
sensor
,
[
sensor
]()
{
if
(
sensor
->
isSubscribed
())
{
LinuxNvidiaGpu
::
s_smiProcess
->
ref
();
}
else
{
LinuxNvidiaGpu
::
s_smiProcess
->
unref
();
}
});
}
auto
queryResult
=
s_smiProcess
->
query
();
if
(
m_index
>=
queryResult
.
length
())
{
qWarning
()
<<
"Could not retrieve information for NVidia GPU"
<<
m_index
;
}
else
{
auto
data
=
queryResult
.
at
(
m_index
);
m_nameProperty
->
setValue
(
data
.
name
);
m_totalVramProperty
->
setValue
(
data
.
totalMemory
);
m_usedVramProperty
->
setMax
(
data
.
totalMemory
);
m_coreFrequencyProperty
->
setMax
(
data
.
maxCoreFrequency
);
m_memoryFrequencyProperty
->
setMax
(
data
.
maxMemoryFrequency
);
m_temperatureProperty
->
setMax
(
data
.
maxTemperature
);
}
m_usedVramProperty
->
setUnit
(
KSysGuard
::
UnitMegaByte
);
m_totalVramProperty
->
setUnit
(
KSysGuard
::
UnitMegaByte
);
}
void
LinuxNvidiaGpu
::
onDataReceived
(
const
NvidiaSmiProcess
::
GpuData
&
data
)
{
if
(
data
.
index
!=
m_index
)
{
return
;
}
m_usageProperty
->
setValue
(
data
.
usage
);
m_usedVramProperty
->
setValue
(
data
.
memoryUsed
);
m_coreFrequencyProperty
->
setValue
(
data
.
coreFrequency
);
m_memoryFrequencyProperty
->
setValue
(
data
.
memoryFrequency
);
m_temperatureProperty
->
setValue
(
data
.
temperature
);
}
plugins/global/gpu/LinuxNvidiaGpu.h
0 → 100644
View file @
f0c691d4
/*
* 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"
#include "NvidiaSmiProcess.h"
class
LinuxNvidiaGpu
:
public
GpuDevice
{
Q_OBJECT
public:
LinuxNvidiaGpu
(
int
index
,
const
QString
&
id
,
const
QString
&
name
);
~
LinuxNvidiaGpu
()
override
;
void
initialize
()
override
;
private:
void
onDataReceived
(
const
NvidiaSmiProcess
::
GpuData
&
data
);
int
m_index
=
0
;
static
NvidiaSmiProcess
*
s_smiProcess
;
};
plugins/global/gpu/NvidiaSmiProcess.cpp
0 → 100644
View file @
f0c691d4
/*
* SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "NvidiaSmiProcess.h"
#include <QStandardPaths>
NvidiaSmiProcess
::
NvidiaSmiProcess
()
{
m_smiPath
=
QStandardPaths
::
findExecutable
(
"nvidia-smi"
);
}
bool
NvidiaSmiProcess
::
isSupported
()
const
{
return
!
m_smiPath
.
isEmpty
();
}
QVector
<
NvidiaSmiProcess
::
GpuQueryResult
>
NvidiaSmiProcess
::
query
()
{
QVector
<
NvidiaSmiProcess
::
GpuQueryResult
>
result
;
if
(
!
isSupported
())
{
return
result
;
}
// Read and parse the result of "nvidia-smi query"
// This seems to be the only way to get certain values like total memory or
// maximum temperature. Unfortunately the output isn't very easily parseable
// so we have to do some trickery to parse things.
QProcess
queryProcess
;
queryProcess
.
setProgram
(
m_smiPath
);
queryProcess
.
setArguments
({
QStringLiteral
(
"query"
)});
queryProcess
.
start
();
queryProcess
.
waitForReadyRead
();
int
gpuCounter
=
0
;
GpuQueryResult
&
data
=
result
[
0
];
bool
readMemory
=
false
;
bool
readMaxClocks
=
false
;
while
(
queryProcess
.
canReadLine
())
{
auto
line
=
queryProcess
.
readLine
();
if
(
line
.
startsWith
(
"GPU "
))
{
// Start of GPU properties block.
result
.
append
(
GpuQueryResult
{});
data
=
result
[
gpuCounter
];
gpuCounter
++
;
}
if
((
readMemory
||
readMaxClocks
)
&&
!
line
.
startsWith
(
" "
))
{
readMemory
=
false
;
readMaxClocks
=
false
;
}
if
(
line
.
startsWith
(
" Product Name"
))
{
data
.
name
=
line
.
mid
(
line
.
indexOf
(
':'
)).
trimmed
();
}
if
(
line
.
startsWith
(
" FB Memory Usage"
)
||
line
.
startsWith
(
" BAR1 Memory Usage"
))
{
readMemory
=
true
;
}
if
(
line
.
startsWith
(
" Max Clocks"
))
{
readMaxClocks
=
true
;
}
if
(
line
.
startsWith
(
" Total"
)
&&
readMemory
)
{
data
.
totalMemory
+=
std
::
atoi
(
line
.
mid
(
line
.
indexOf
(
':'
)));
}
if
(
line
.
startsWith
(
" GPU Shutdown Temp"
))
{
data
.
maxTemperature
=
std
::
atoi
(
line
.
mid
(
line
.
indexOf
(
':'
)));
}
if
(
line
.
startsWith
(
" Graphics"
)
&&
readMaxClocks
)
{
data
.
maxCoreFrequency
=
std
::
atoi
(
line
.
mid
(
line
.
indexOf
(
':'
)));
}
if
(
line
.
startsWith
(
" Memory"
)
&&
readMaxClocks
)
{
data
.
maxMemoryFrequency
=
std
::
atoi
(
line
.
mid
(
line
.
indexOf
(
':'
)));
}
}
return
result
;
}
void
NvidiaSmiProcess
::
ref
()
{
if
(
!
isSupported
())
{
return
;
}
m_references
++
;
if
(
m_process
)
{
return
;
}
m_process
=
std
::
make_unique
<
QProcess
>
();
m_process
->
setProgram
(
m_smiPath
);
m_process
->
setArguments
({
QStringLiteral
(
"dmon"
),
// Monitor
QStringLiteral
(
"-d"
),
QStringLiteral
(
"2"
),
// 2 seconds delay, to match daemon update rate
QStringLiteral
(
"-s"
),
QStringLiteral
(
"pucm"
)
// Include all relevant statistics
});
connect
(
m_process
.
get
(),
&
QProcess
::
readyReadStandardOutput
,
this
,
&
NvidiaSmiProcess
::
readStatisticsData
);
m_process
->
start
();
}
void
NvidiaSmiProcess
::
unref
()
{
if
(
!
isSupported
())
{
return
;
}
m_references
--
;
if
(
!
m_process
||
m_references
>
0
)
{
return
;
}
m_process
->
terminate
();
m_process
->
waitForFinished
();
m_process
.
reset
();
}
void
NvidiaSmiProcess
::
readStatisticsData
()
{
while
(
m_process
->
canReadLine
())
{
const
QString
line
=
m_process
->
readLine
();
if
(
line
.
startsWith
(
QLatin1Char
(
'#'
)))
{
continue
;
}
const
QVector
<
QStringRef
>
parts
=
line
.
splitRef
(
QLatin1Char
(
' '
),
Qt
::
SkipEmptyParts
);
// format at time of writing is
// # gpu pwr gtemp mtemp sm mem enc dec mclk pclk fb bar1
if
(
parts
.
count
()
!=
12
)
{
continue
;
}
bool
ok
;
int
index
=
parts
[
0
].
toInt
(
&
ok
);
if
(
!
ok
)
{
continue
;
}
GpuData
data
;
data
.
index
=
index
;
data
.
power
=
parts
[
1
].
toUInt
();
data
.
temperature
=
parts
[
2
].
toUInt
();
// GPU usage equals "SM" usage + "ENC" usage + "DEC" usage
data
.
usage
=
parts
[
4
].
toUInt
()
+
parts
[
6
].
toUInt
()
+
parts
[
7
].
toUInt
();
// Total memory used equals "FB" usage + "BAR1" usage
data
.
memoryUsed
=
parts
[
10
].
toUInt
()
+
parts
[
11
].
toUInt
();
data
.
memoryFrequency
=
parts
[
8
].
toUInt
();
data
.
coreFrequency
=
parts
[
9
].
toUInt
();
Q_EMIT
dataReceived
(
data
);
}
}
plugins/global/gpu/NvidiaSmiProcess.h
0 → 100644
View file @
f0c691d4
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <memory>
#include <QObject>
#include <QProcess>
class
NvidiaSmiProcess
:
public
QObject
{
Q_OBJECT
public:
struct
GpuData
{
int
index
=
-
1
;
uint
power
=
0
;
uint
temperature
=
0
;
uint
usage
=
0
;
uint
memoryUsed
=
0
;
uint
coreFrequency
=
0
;
uint
memoryFrequency
=
0
;
};
struct
GpuQueryResult
{
QString
name
;
uint
totalMemory
=
0
;
uint
maxCoreFrequency
=
0
;
uint
maxMemoryFrequency
=
0
;
uint
maxTemperature
=
0
;
};
NvidiaSmiProcess
();
bool
isSupported
()
const
;
QVector
<
GpuQueryResult
>
query
();
void
ref
();
void
unref
();
Q_SIGNAL
void
dataReceived
(
const
GpuData
&
data
);
private:
void
readStatisticsData
();
QString
m_smiPath
;
std
::
unique_ptr
<
QProcess
>
m_process
=
nullptr
;
int
m_references
=
0
;
};
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment