diff --git a/processplugins/CMakeLists.txt b/processplugins/CMakeLists.txt --- a/processplugins/CMakeLists.txt +++ b/processplugins/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(xres) +add_subdirectory(nvidia) diff --git a/processplugins/nvidia/CMakeLists.txt b/processplugins/nvidia/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/processplugins/nvidia/CMakeLists.txt @@ -0,0 +1,3 @@ +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) diff --git a/processplugins/nvidia/nvidia.h b/processplugins/nvidia/nvidia.h new file mode 100644 --- /dev/null +++ b/processplugins/nvidia/nvidia.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + + Copyright (C) 2019 David Edmundson + + 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 + +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; +}; diff --git a/processplugins/nvidia/nvidia.cpp b/processplugins/nvidia/nvidia.cpp new file mode 100644 --- /dev/null +++ b/processplugins/nvidia/nvidia.cpp @@ -0,0 +1,106 @@ +/* This file is part of the KDE project + + Copyright (C) 2019 David Edmundson + + 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 +#include +#include + +#include +#include + +#include + +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();) + +#include "nvidia.moc" diff --git a/processplugins/nvidia/nvidia.json b/processplugins/nvidia/nvidia.json new file mode 100644 --- /dev/null +++ b/processplugins/nvidia/nvidia.json @@ -0,0 +1,5 @@ +{ + "KPlugin": { + "Description": "Stats of per-process GPU resources for Nvidia cards" + } +}