Commit 1cd660c3 authored by David Redondo's avatar David Redondo 🏎
Browse files

Intel test

parent 15a03830
......@@ -5,7 +5,12 @@ add_library(ksystemstats_plugin_gpu MODULE GpuPlugin.cpp GpuBackend.cpp GpuDevic
target_link_libraries(ksystemstats_plugin_gpu Qt::Core KF5::CoreAddons KF5::I18n KSysGuard::SystemStats UDev::UDev)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_sources(ksystemstats_plugin_gpu PRIVATE LinuxAmdGpu.cpp LinuxNvidiaGpu.cpp LinuxBackend.cpp NvidiaSmiProcess.cpp)
target_sources(ksystemstats_plugin_gpu PRIVATE LinuxAmdGpu.cpp LinuxIntelGpu.cpp LinuxNvidiaGpu.cpp LinuxBackend.cpp NvidiaSmiProcess.cpp)
endif()
install(TARGETS ksystemstats_plugin_gpu DESTINATION ${KSYSTEMSTATS_PLUGIN_INSTALL_DIR})
add_executable(ksystemstats_intel_helper IntelHelper.cpp)
configure_file(IntelHelperLocation.h.cmake IntelHelperLocation.h)
install(TARGETS ksystemstats_intel_helper DESTINATION ${KDE_INSTALL_LIBEXECDIR})
/*
* SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include <array>
#include <chrono>
#include <cinttypes>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <map>
#include <iostream>
#include <drm/i915_drm.h>
#include <linux/perf_event.h>
#include <sys/capability.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
constexpr auto eventSourceDir = "/sys/bus/event_source/devices/i915";
int i915Type()
{
const std::string path = eventSourceDir + std::string("/type");
std::ifstream typeFile(path);
if (!typeFile.is_open()) {
std::cerr << "Could not open " << path;
std::exit(1);
}
int type = -1;
if(!(typeFile >> type)) {
std::cerr << "Error reading type";
std::exit(1);
}
return type;
}
int perf_open(int type, int config, int group_fd)
{
perf_event_attr pe;
std::memset(&pe, 0, sizeof(pe));
pe.type = type;
pe.size = sizeof(pe);
pe.config = config;
pe.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_ENABLED;
return syscall(SYS_perf_event_open, &pe, -1, 0, group_fd, PERF_FLAG_FD_CLOEXEC);
}
template <int n>
struct read_format {
std::uint64_t count;
std::uint64_t time_enabled;
struct value {
std::uint64_t value;
std::uint64_t id;
};
std::array<value, n> values;
};
int main()
{
const int type = i915Type();
int group_fd = -1;
// TODO Should we also add sema and wait usages?
constexpr std::array events = {I915_PMU_INTERRUPTS,
I915_PMU_ACTUAL_FREQUENCY,
I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_RENDER, 0),
I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_COPY, 0),
I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_VIDEO, 0),
I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_VIDEO_ENHANCE, 0)};
std::map<std::uint64_t, int> idToEvent;
for (const auto event : events) {
const int fd = perf_open(type, event, group_fd);
if (group_fd == -1) {
group_fd = fd;
}
if (fd != -1) {
std::uint64_t id;
ioctl(fd, PERF_EVENT_IOC_ID, &id);
idToEvent.emplace(id, event);
}
}
if (group_fd == -1) {
std::cerr << "Failed opening any event" << std::endl;
return -1;
}
read_format<events.size()> data;
while (true) {
if (read(group_fd, &data, sizeof(data)) < 0) {
std::cerr << "Error reading events" << std::endl;
return errno;
}
std::cout << data.time_enabled;
for (auto value = data.values.cbegin(); value != data.values.cbegin() + data.count; ++value) {
if (!idToEvent.count(value->id)) {
std::cerr << "Unknown event id" << value->id << "\n";
continue;
}
switch (idToEvent[value->id]) {
case I915_PMU_INTERRUPTS:
std::cout << "|Interrupts";
break;
case I915_PMU_ACTUAL_FREQUENCY:
std::cout << "|Frequency";
break;
case I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_RENDER, 0):
std::cout << "|Render";
break;
case I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_COPY, 0):
std::cout << "|Copy";
break;
case I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_VIDEO, 0):
std::cout << "|Video";
break;
case I915_PMU_ENGINE_BUSY(I915_ENGINE_CLASS_VIDEO_ENHANCE, 0):
std::cout << "|Enhance";
break;
}
std::cout << "|" << value->value;
}
std::cout << std::endl;
sleep(1);
}
}
/*
* SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
*
* SPDX-License-Identifier: CC0-1.0
*/
#pragma once
constexpr auto helperLocation = "@KDE_INSTALL_FULL_LIBEXECDIR@/ksystemstats_intel_helper";
......@@ -13,6 +13,7 @@
#include <libudev.h>
#include "LinuxAmdGpu.h"
#include "LinuxIntelGpu.h"
#include "LinuxNvidiaGpu.h"
// Vendor ID strings, as used in sysfs
......@@ -54,6 +55,8 @@ void LinuxBackend::start()
gpu = new LinuxAmdGpu{gpuId, gpuName, device};
} else if (vendor == nvidiaVendor) {
gpu = new LinuxNvidiaGpu{gpuCounter, gpuId, gpuName};
} else if (vendor == intelVendor) {
gpu = new LinuxIntelGpu(gpuId, gpuName);
} else {
qDebug() << "Found unsupported GPU:" << path;
udev_device_unref(device);
......
/*
* SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "LinuxIntelGpu.h"
#include "IntelHelperLocation.h"
#include <QProcess>
#include <QStandardPaths>
LinuxIntelGpu::LinuxIntelGpu(const QString &id, const QString &name)
: GpuDevice(id, name)
{
m_helperProcess = new QProcess(this);
m_helperProcess->setProgram(helperLocation);
connect(m_helperProcess, &QProcess::readyReadStandardOutput, this, &LinuxIntelGpu::readPerfData);
connect(m_helperProcess, &QProcess::readyReadStandardError, this, [this] {
qCritical() << m_helperProcess->readAllStandardError();
});
connect(this, &GpuDevice::subscribedChanged, this, [this](bool subscribed) {
if (subscribed) {
m_helperProcess->start();
} else {
m_helperProcess->terminate();
}
});
}
void LinuxIntelGpu::readPerfData()
{
while (m_helperProcess->canReadLine()) {
const QString line = m_helperProcess->readLine();
auto parts = line.split("|");
if (parts.size() <= 1 || parts.size() % 2 == 0) {
continue;
}
quint64 timestamp = parts[0].toULong();
quint64 timediff = timestamp - lastTimeStamp;
double timeDiffSeconds = timediff / 1e9;
lastTimeStamp = timestamp;
quint64 usage = 0;
for (int i = 1; i < parts.size(); i += 2) {
if (parts[i] == QLatin1String("Frequency")) {
quint64 frequencyCount = parts[i + 1].toULong();
m_coreFrequencyProperty->setValue((frequencyCount - lastFrequencyCount) / timeDiffSeconds);
lastFrequencyCount = frequencyCount;
} else if (parts[i] == QLatin1String("Render") || parts[i] == QLatin1String("Copy") || parts[i] == QLatin1String("Video")
|| parts[i] == QLatin1String("Enhance")) {
// FIXME just adding all the "engines" is wrong (confirmed by testing, can go over 100%)
// Either average or maybe use max, both can be potentially misleading
usage += parts[i + 1].toULong();
}
}
m_usageProperty->setValue((usage - lastUsages) * 100 / timediff);
lastUsages = usage;
}
}
/*
* SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include "GpuDevice.h"
class QProcess;
class LinuxIntelGpu : public GpuDevice
{
Q_OBJECT
public:
LinuxIntelGpu(const QString &id, const QString &name);
private:
void readPerfData();
QProcess *m_helperProcess;
quint64 lastTimeStamp;
quint64 lastUsages;
quint64 lastFrequencyCount;
};
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