Commit 98b81734 authored by David Edmundson's avatar David Edmundson
Browse files

Add plugin showing nvidia GPU load stats

This plugin shows the process GPU load and GPU memory usage for users of
Nvidia graphic cards.

Data is fetched by running the (fortunately lightweight) process
nvidia-smi to extract data. If this binary is not available this plugin
does nothing and the columns will not be available.

It's not feasible to try try and reverse engineer nvidia-smi to recreate
the functionality to do it without the extra executable. The headers are
hidden within a giant proprietary SDK, and internally it's just opening
a completely arbitrary address in /dev/mem
parent a1fa73da
if (libpcap_FOUND)
add_subdirectory(process/network)
endif()
add_subdirectory(process/nvidia)
add_library(ksysguard_plugin_nvidia MODULE nvidia.cpp)
target_link_libraries(ksysguard_plugin_nvidia Qt5::Core KF5::ProcessCore KF5::I18n KF5::CoreAddons)
install(TARGETS ksysguard_plugin_nvidia DESTINATION ${KDE_INSTALL_PLUGINDIR}/ksysguard/process)
/* This file is part of the KDE project
Copyright (C) 2019 David Edmundson <davidedmundson@kde.org>
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 "nvidia.h"
#include <QStandardPaths>
#include <QProcess>
#include <QDebug>
#include <KLocalizedString>
#include <KPluginFactory>
#include <processcore/process.h>
using namespace KSysGuard;
NvidiaPlugin::NvidiaPlugin(QObject *parent, const QVariantList &args)
: ProcessDataProvider(parent, args)
{
m_sniExecutablePath = QStandardPaths::findExecutable(QStringLiteral("nvidia-smi"));
if (m_sniExecutablePath.isEmpty()) {
return;
}
m_usage = new ProcessAttribute(QStringLiteral("nvidia_usage"), i18n("GPU Usage"), this);
m_usage->setUnit(KSysGuard::UnitPercent);
m_memory = new ProcessAttribute(QStringLiteral("nvidia_memory"), i18n("GPU Memory"), this);
m_memory->setUnit(KSysGuard::UnitPercent);
addProcessAttribute(m_usage);
addProcessAttribute(m_memory);
}
void NvidiaPlugin::handleEnabledChanged(bool enabled)
{
if (enabled) {
if (!m_process) {
setup();
}
m_process->start();
} else {
if (m_process) {
m_process->terminate();
}
}
}
void NvidiaPlugin::setup()
{
m_process = new QProcess(this);
m_process->setProgram(m_sniExecutablePath);
m_process->setArguments({QStringLiteral("pmon")});
connect(m_process, &QProcess::readyReadStandardOutput, this, [=]() {
while (m_process->canReadLine()) {
const QString line = QString::fromLatin1(m_process->readLine());
if (line.startsWith(QLatin1Char('#'))) { //comment line
if (line != QLatin1String("# gpu pid type sm mem enc dec command\n") &&
line != QLatin1String("# Idx # C/G % % % % name\n")) {
//header format doesn't match what we expected, bail before we send any garbage
m_process->terminate();
}
continue;
}
const auto parts = line.splitRef(QLatin1Char(' '), QString::SkipEmptyParts);
// format at time of writing is
// # gpu pid type sm mem enc dec command
if (parts.count() != 9) {
continue;
}
long pid = parts[1].toUInt();
int sm = parts[3].toUInt();
int mem = parts[4].toUInt();
KSysGuard::Process *process = getProcess(pid);
if(!process) {
continue; //can in race condition etc
}
m_usage->setData(process, sm);
m_memory->setData(process, mem);
}
});
}
K_PLUGIN_FACTORY_WITH_JSON(PluginFactory, "nvidia.json", registerPlugin<NvidiaPlugin>();)
#include "nvidia.moc"
/* This file is part of the KDE project
Copyright (C) 2019 David Edmundson <davidedmundson@kde.org>
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 <processcore/process_data_provider.h>
#include <processcore/process_attribute.h>
class QProcess;
class NvidiaPlugin : public KSysGuard::ProcessDataProvider
{
Q_OBJECT
public:
NvidiaPlugin(QObject *parent, const QVariantList &args);
void handleEnabledChanged(bool enabled) override;
private:
void setup();
KSysGuard::ProcessAttribute *m_usage = nullptr;
KSysGuard::ProcessAttribute *m_memory = nullptr;
QString m_sniExecutablePath;
QProcess *m_process = nullptr;
};
{
"KPlugin": {
"Description": "Stats of per-process GPU resources for Nvidia cards"
}
}
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