Start adding GPU feature detection to the UI

This commit is contained in:
jussi 2019-01-25 15:30:23 +02:00
parent 2ac0d2d1e9
commit de195cbf0b
4 changed files with 171 additions and 60 deletions

View File

@ -17,40 +17,56 @@ MainWindow::MainWindow(QWidget *parent) :
queryGPUSettings();
loadProfileSettings();
queryDriverSettings();
//getGPUName();
queryGPUs();
setupMonitorTab();
setupGraphMonitorTab();
tabHandler(ui->tabWidget->currentIndex());
ui->frequencySlider->setRange(minCoreClkOfsInt, maxCoreClkOfsInt);
ui->frequencySpinBox->setRange(minCoreClkOfsInt, maxCoreClkOfsInt);
// Create persistent nvidia pointer
nvidia *nvd = new nvidia;
nv = nvd;
nv->setupXNVCtrl();
nv->setupNVML(0);
nv->queryGPUFeatures();
qDebug() << nv->GPUList.size() << nv->GPUList[0].name << "gpus from main";
// Enable sliders according to GPU properties
if (nv->GPUList[0].overClockAvailable) {
ui->frequencySlider->setRange(nv->GPUList[0].minCoreClkOffset, nv->GPUList[0].maxCoreClkOffset);
ui->frequencySpinBox->setRange(nv->GPUList[0].minCoreClkOffset, nv->GPUList[0].maxCoreClkOffset);
ui->frequencySlider->setValue(coreFreqOfsInt);
ui->frequencySpinBox->setValue(coreFreqOfsInt);
ui->memClkSlider->setRange(nv->GPUList[0].minMemClkOffset, nv->GPUList[0].maxMemClkOffset);
ui->memClkSpinBox->setRange(nv->GPUList[0].minMemClkOffset, nv->GPUList[0].maxMemClkOffset);
ui->memClkSlider->setValue(memClkOfsInt);
ui->memClkSpinBox->setValue(memClkOfsInt);
} else {
ui->frequencySlider->setEnabled(false);
ui->frequencySpinBox->setEnabled(false);
}
ui->powerLimSlider->setRange(minPowerLimInt, maxPowerLimInt);
ui->powerLimSpinBox->setRange(minPowerLimInt, maxPowerLimInt);
ui->powerLimSlider->setValue(curPowerLimInt);
ui->powerLimSpinBox->setValue(curPowerLimInt);
ui->memClkSlider->setRange(minMemClkOfsInt, maxMemClkOfsInt);
ui->memClkSpinBox->setRange(minMemClkOfsInt, maxMemClkOfsInt);
ui->memClkSlider->setValue(memClkOfsInt);
ui->memClkSpinBox->setValue(memClkOfsInt);
ui->voltageSlider->setRange(minVoltOfsInt, maxVoltOfsInt);
ui->voltageSpinBox->setRange(minVoltOfsInt, maxVoltOfsInt);
if (nv->GPUList[0].overVoltAvailable) {
ui->voltageSlider->setRange(nv->GPUList[0].minVoltageOffset, nv->GPUList[0].maxVoltageOffset);
ui->voltageSpinBox->setRange(nv->GPUList[0].minVoltageOffset, nv->GPUList[0].maxVoltageOffset);
ui->voltageSlider->setValue(voltOfsInt);
ui->voltageSpinBox->setValue(voltOfsInt);
} else {
ui->voltageSlider->setEnabled(false);
ui->voltageSpinBox->setEnabled(false);
}
ui->fanSlider->setValue(fanSpeed);
ui->fanSpinBox->setValue(fanSpeed);
ui->fanSlider->setRange(0, 100);
ui->fanSpinBox->setRange(0, 100);
//QTimer *fanUpdateTimer = new QTimer(this);
connect(fanUpdateTimer, SIGNAL(timeout()), this, SLOT(fanSpeedUpdater()));
//connect(fanUpdateTimer, SIGNAL(timeout()), this, SLOT(tempUpdater()));
fanUpdateTimer->start(2000);
connect(ui->frequencySpinBox, SIGNAL(valueChanged(int)), SLOT(resetTimer()));
@ -60,9 +76,6 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(tabHandler(int)));
connect(monitorUpdater, SIGNAL(timeout()), SLOT(updateMonitor()));
nvidia nv;
nv.setupXNVCtrl();
}
MainWindow::~MainWindow()
@ -322,15 +335,31 @@ void MainWindow::setupGraphMonitorTab()
}
void MainWindow::updateMonitor()
{
// This function takes around 300ms to complete, so it would be smoother to execute it in another thread
// Update the values for plots
nv->queryGPUTemp(0);
nv->queryGPUPowerDraw(0);
nv->queryGPUFrequencies(0);
nv->queryGPUUtils(0);
nv->queryGPUVoltage(0);
nv->queryGPUFanSpeed(0);
monitor mon;
plotCmdsList[0].valueq = nv->GPUList[0].temp;
plotCmdsList[1].valueq = nv->GPUList[0].powerDraw/1000;
plotCmdsList[2].valueq = nv->GPUList[0].coreFreq;
plotCmdsList[3].valueq = nv->GPUList[0].memFreq;
plotCmdsList[4].valueq = nv->GPUList[0].coreUtil;
plotCmdsList[5].valueq = nv->GPUList[0].memUtil;
plotCmdsList[6].valueq = nv->GPUList[0].voltage/1000;
plotCmdsList[7].valueq = nv->GPUList[0].fanSpeed;
qDebug() << monitorUpdater->remainingTime();
//monitor mon;
//QThread *thread = new QThread(this);
//mon.moveToThread(thread);
//thread->start();
mon.queryValues();
fanSpeedUpdater();
gputemp->setText(1, mon.temp + "°C");
//mon.queryValues();
//fanSpeedUpdater();
/*gputemp->setText(1, mon.temp + "°C");
powerdraw->setText(1, mon.powerdraw + "W");
voltage->setText(1, mon.voltage + "mV");
coreclock->setText(1, mon.coreclock + " MHz");
@ -338,7 +367,7 @@ void MainWindow::updateMonitor()
coreutil->setText(1, mon.coreutil + " %");
memutil->setText(1, mon.memutil + " %");
fanspeed->setText(1, QString::number(fanSpeed) + " %");
memusage->setText(1, mon.usedmem + "/" + mon.totalmem);
memusage->setText(1, mon.usedmem + "/" + mon.totalmem);*/
// Decrement all time values by one
@ -355,15 +384,6 @@ void MainWindow::updateMonitor()
if (qv_time.size() > plotVectorSize) {
qv_time.removeFirst();
}
// Update the values for plots
plotCmdsList[0].valueq = mon.temp.toDouble();
plotCmdsList[1].valueq = mon.powerdraw.toDouble();
plotCmdsList[2].valueq = mon.coreclock.toDouble();
plotCmdsList[3].valueq = mon.memclock.toDouble();
plotCmdsList[4].valueq = mon.coreutil.toDouble();
plotCmdsList[5].valueq = mon.memutil.toDouble();
plotCmdsList[6].valueq = mon.voltage.toDouble();
plotCmdsList[7].valueq = fanSpeed;
for (int i=0; i<plotCmdsList.size(); i++) {
// Check if the max/min values need to be updated
@ -440,12 +460,7 @@ void MainWindow::updateMonitor()
}
void MainWindow::plotHovered(QMouseEvent *event)
{
//plotHoverUpdater->start(1000);
QPoint cursor = event->pos();
//qDebug() << childAt(cursor);
//QWidget *widget = childAt(cursor);
//QCustomPlot *plot = widget->findChild<QCustomPlot*>(QString(), Qt::FindDirectChildrenOnly);
//plot->xAxis->setRange(-15, 0);
int plotIndex = 0;
for (int i=0; i<plotCmdsList.size(); i++) {
@ -455,7 +470,6 @@ void MainWindow::plotHovered(QMouseEvent *event)
}
}
double pointerxcoord = plotCmdsList[plotIndex].plot->xAxis->pixelToCoord(cursor.x());
//qDebug() << pointerxcoord << plotVectorSize;
plotCmdsList[plotIndex].tracer->position->setCoords(pointerxcoord, plotCmdsList[plotIndex].plot->yAxis->range().upper);
// Find the y-value for the corresponding coordinate
int valIndex = 0;
@ -467,8 +481,6 @@ void MainWindow::plotHovered(QMouseEvent *event)
valIndex = i;
}
}
//qDebug() << plotCmdsList[plotIndex].vector[valIndex];
//QCPItemText *text = new QCPItemText(plotCmdsList[plotIndex].plot);
plotCmdsList[plotIndex].valText->setText(QString::number(plotCmdsList[plotIndex].vector[valIndex]));
// Make the text stay inside the plot
if (pointerxcoord > -plotVectorSize*0.06) {
@ -478,7 +490,7 @@ void MainWindow::plotHovered(QMouseEvent *event)
} else {
plotCmdsList[plotIndex].valText->position->setCoords(pointerxcoord, plotCmdsList[plotIndex].plot->yAxis->range().upper - plotCmdsList[plotIndex].plot->yAxis->range().size()*0.05);
}
//QThread::msleep(10);
QThread::msleep(10);
} else {
// If the cursor is not within the x-range, clear the text
plotCmdsList[plotIndex].valText->setText("");

View File

@ -7,6 +7,7 @@
#include <QProcess>
#include <QList>
#include <QByteArray>
#include "nvidia.h"
//#include <NVCtrl/NVCtrl.h>
namespace Ui {
@ -158,6 +159,7 @@ private:
bool noProfiles = true;
QStringList UUIDList;
QString latestUUID;
nvidia *nv;
QTimer *resettimer = new QTimer(this);
QTimer *fanUpdateTimer = new QTimer(this);
@ -242,6 +244,8 @@ private:
plotCmds voltageplot;
plotCmds fanspeedplot;
QVector <plotCmds> plotCmdsList;
};
#endif // MAINWINDOW_H

View File

@ -9,7 +9,6 @@ nvidia::nvidia(QObject *parent) : QObject(parent)
}
bool nvidia::setupXNVCtrl()
{
setupNVML();
// Open the x-server connection and check if the extension exists
dpy = XOpenDisplay(nullptr);
Bool ret;
@ -39,7 +38,8 @@ void nvidia::queryGPUCount()
GPU gpu;
GPUList.append(gpu);
}
qDebug() << gpuCount;
qDebug() << GPUList.size() << "gpus";
//setupNVML(0);
}
void nvidia::queryGPUNames()
{
@ -148,17 +148,26 @@ void nvidia::queryGPUFeatures()
qDebug() << "fanctl on";
GPUList[i].manualFanCtrl = true;
}
// Query amount of VRAM
ret = XNVCTRLQueryTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
i,
0,
NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY,
&GPUList[i].totalVRAM);
qDebug() << GPUList[i].totalVRAM << "vram";
}
queryGPUVoltage(0);
queryGPUTemp(0);
queryGPUFrequencies(0);
queryGPUFanSpeed(0);
//queryGPUVoltage(0);
//queryGPUTemp(0);
//queryGPUFrequencies(0);
//queryGPUFanSpeed(0);
//queryGPUUsedVRAM(0);
//assignGPUFanSpeed(0, 60);
//assignGPUFreqOffset(0, 10);
//assignGPUMemClockOffset(0, 10);
//assignGPUVoltageOffset(0, 5000);
assignGPUFanCtlMode(0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE);
//assignGPUFanCtlMode(0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE);
}
void nvidia::queryGPUVoltage(int GPUIndex)
{
@ -176,6 +185,7 @@ void nvidia::queryGPUVoltage(int GPUIndex)
}
void nvidia::queryGPUTemp(int GPUIndex)
{
qDebug() << GPUList.size();
Bool ret;
ret = XNVCTRLQueryTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_THERMAL_SENSOR,
@ -183,6 +193,9 @@ void nvidia::queryGPUTemp(int GPUIndex)
0,
NV_CTRL_THERMAL_SENSOR_READING,
&GPUList[GPUIndex].temp);
if (!ret) {
qDebug() << "failed to query GPU temperature";
}
qDebug() << GPUList[GPUIndex].temp;
}
void nvidia::queryGPUFrequencies(int GPUIndex)
@ -216,6 +229,19 @@ void nvidia::queryGPUFanSpeed(int GPUIndex)
qDebug() << GPUList[GPUIndex].fanSpeed;
}
void nvidia::queryGPUUsedVRAM(int GPUIndex)
{
Bool ret = XNVCTRLQueryTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
GPUIndex,
0,
NV_CTRL_USED_DEDICATED_GPU_MEMORY,
&GPUList[GPUIndex].usedVRAM);
if (!ret) {
qDebug() << "failed to query used VRAM";
}
qDebug() << GPUList[GPUIndex].usedVRAM << "usedvram";
}
bool nvidia::assignGPUFanSpeed(int GPUIndex, int targetValue)
{
Bool ret;
@ -283,21 +309,74 @@ bool nvidia::assignGPUVoltageOffset(int GPUIndex, int targetValue)
qDebug() << temp;
return true;
}*/
bool nvidia::setupNVML()
bool nvidia::setupNVML(int GPUIndex)
{
nvmlDevice_t dev;
nvmlDevice_t *dev = new nvmlDevice_t;
device = dev;
nvmlReturn_t ret = nvmlInit();
int i;
char name[64];
nvmlDeviceGetHandleByIndex(i, &dev);
nvmlDeviceGetName(dev, name, sizeof(name)/sizeof(name[0]));
nvmlDeviceGetHandleByIndex(GPUIndex, dev);
//nvmlDeviceGetName(dev, name, sizeof(name)/sizeof(name[0]));
qDebug() << name << "from nvml";
if (NVML_SUCCESS != ret) {
return false;
}
//queryGPUUtils(0);
//queryGPUPowerLimitLimits(0);
//queryGPUPowerDraw(0);
//qDebug() << assignGPUPowerLimit(150000);
return true;
}
void nvidia::queryGPUUtils(int GPUIndex)
{
nvmlUtilization_t utils;
nvmlReturn_t ret = nvmlDeviceGetUtilizationRates(*device, &utils);
if (NVML_SUCCESS != ret) {
qDebug() << "failed to query GPU utilizations";
}
qDebug() << utils.gpu << utils.memory << "utils";
GPUList[GPUIndex].memUtil = utils.memory;
GPUList[GPUIndex].coreUtil = utils.gpu;
}
void nvidia::queryGPUPowerDraw(int GPUIndex)
{
uint usg;
nvmlReturn_t ret = nvmlDeviceGetPowerUsage(*device, &usg);
if (NVML_SUCCESS != ret) {
qDebug() << "failed to query power usage";
} else {
GPUList[GPUIndex].powerDraw = usg;
qDebug() << usg << "pwrusg";
}
}
void nvidia::queryGPUPowerLimitLimits(int GPUIndex)
{
uint maxlim;
uint minlim;
nvmlReturn_t ret = nvmlDeviceGetPowerManagementLimitConstraints(*device, &minlim, &maxlim);
if (NVML_SUCCESS != ret) {
qDebug() << "failed to query power limit constraints";
} else {
GPUList[GPUIndex].minPowerLim = minlim;
GPUList[GPUIndex].maxPowerLim = maxlim;
qDebug() << minlim << maxlim << "powerlims";
}
}
void nvidia::queryGPUPowerLimit(int GPUIndex)
{
uint lim;
nvmlReturn_t ret = nvmlDeviceGetPowerManagementLimit(*device, &lim);
if (NVML_SUCCESS != ret) {
qDebug() << "failed to query power limit";
} else {
GPUList[GPUIndex].powerLim = lim;
}
}
bool nvidia::assignGPUPowerLimit(uint targetValue)
{
nvmlReturn_t ret = nvmlDeviceSetPowerManagementLimit(*device, targetValue);
if (NVML_SUCCESS != ret) {
return false;
}
return true;
}
void nvidia::queryGPUUtils(int GPUIndex)
{
}

View File

@ -4,6 +4,7 @@
#include <QObject>
#include <QDebug>
#include <QtX11Extras/QX11Info>
#include <QProcess>
#include "/opt/cuda/include/nvml.h"
class nvidia : public QObject
@ -38,6 +39,12 @@ public:
int temp;
int voltage;
int fanSpeed;
uint powerDraw;
uint coreUtil;
uint memUtil;
uint minPowerLim;
uint maxPowerLim;
uint powerLim;
int totalVRAM;
int usedVRAM;
@ -46,11 +53,13 @@ public:
int gpuCount = 0;
private:
Display *dpy;
nvmlDevice_t *device;
signals:
public slots:
bool setupXNVCtrl();
bool setupNVML();
bool setupNVML(int GPUIndex);
void queryGPUCount();
void queryGPUNames();
void queryGPUUIDs();
@ -59,13 +68,20 @@ public slots:
void queryGPUTemp(int GPUIndex);
void queryGPUFrequencies(int GPUIndex);
void queryGPUFanSpeed(int GPUIndex);
void queryGPUUsedVRAM(int GPUIndex);
void queryGPUUtils(int GPUIndex);
void queryGPUPowerDraw(int GPUIndex);
void queryGPUPowerLimit(int GPUIndex);
void queryGPUPowerLimitLimits(int GPUIndex);
bool assignGPUFanSpeed(int GPUIndex, int targetValue);
bool assignGPUFanCtlMode(int GPUIndex, int targetValue);
bool assignGPUFreqOffset(int GPUIndex, int targetValue);
bool assignGPUMemClockOffset(int GPUIndex, int targetValue);
bool assignGPUVoltageOffset(int GPUIndex, int targetValue);
// NVML functions know the GPU index already based on the dev object passed in setupNVML()
bool assignGPUPowerLimit(uint targetValue);
private slots:
};