diff --git a/radeon-profile/dxorg.cpp b/radeon-profile/dxorg.cpp index 5c294ae..b359314 100644 --- a/radeon-profile/dxorg.cpp +++ b/radeon-profile/dxorg.cpp @@ -3,6 +3,10 @@ #include "dxorg.h" #include "gpu.h" +extern "C" { +#include "radeon_ioctl.h" +} + #include #include #include @@ -25,6 +29,7 @@ daemonComm *dXorg::dcomm = new daemonComm(); void dXorg::configure(const QString &gpuName) { setupDriverModule(gpuName); + qDebug() << "Using module" << dXorg::driverModuleName; figureOutGpuDataFilePaths(gpuName); currentTempSensor = testSensor(); currentPowerMethod = getPowerMethod(); @@ -110,6 +115,31 @@ bool dXorg::daemonConnected() { } void dXorg::figureOutGpuDataFilePaths(const QString &gpuName) { + +#ifdef QT_DEBUG + // Example IOCTLs + // IOCTLs require root access + int fd = openCardFD(gpuName.toStdString().c_str()); + if(fd >= 0){ + int i; + unsigned u; + unsigned long ul; + float f; + + qDebug() << "Testing IOCTLs"; + if(!radeonCoreClock(fd, &u)) qDebug() << "Core clock:" << u << "MHz"; + if(!radeonMaxCoreClock(fd, &u)) qDebug() << "Max core clock:" << u/1000 << "MHz"; + if(!radeonMemoryClock(fd, &u)) qDebug() << "Memory clock:" << u << "MHz"; + if(!radeonTemperature(fd, &i)) qDebug() << "Temperature:" << i/1000.0f << "°C"; + if(!radeonVramUsage(fd,&ul)) qDebug() << "VRAM usage:" << ul/1024 << "KB"; + if(!radeonGpuUsage(fd, &f, 500000, 150)) qDebug() << "GPU usage:" << f << "%"; + if(!amdgpuVramUsage(fd,&ul)) qDebug() << "VRAM usage:" << ul/1024 << "KB"; + if(!amdgpuGpuUsage(fd, &f, 500000, 150)) qDebug() << "GPU usage:" << f << "%"; + + closeCardFD(fd); + } +#endif + gpuSysIndex = gpuName.at(gpuName.length()-1); QString devicePath = "/sys/class/drm/"+gpuName+"/device/"; diff --git a/radeon-profile/radeon-profile.pro b/radeon-profile/radeon-profile.pro index 8fa10c2..fdb5927 100644 --- a/radeon-profile/radeon-profile.pro +++ b/radeon-profile/radeon-profile.pro @@ -17,7 +17,7 @@ QMAKE_CXXFLAGS += -std=c++0x # http://doc.qt.io/qt-5/qtglobal.html#QtMsgType-enum # qDebug will work only when compiled for Debug # QtWarning, QtCritical and QtFatal will still work on Release -CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT +CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT NO_IOCTL SOURCES += main.cpp\ radeon_profile.cpp \ @@ -31,6 +31,7 @@ SOURCES += main.cpp\ daemonComm.cpp \ execTab.cpp \ execbin.cpp \ + radeon_ioctl.c \ dialog_rpevent.cpp \ eventsTab.cpp \ fanControlTab.cpp @@ -43,6 +44,7 @@ HEADERS += radeon_profile.h \ globalStuff.h \ daemonComm.h \ execbin.h \ + radeon_ioctl.h \ dialog_rpevent.h \ rpevent.h diff --git a/radeon-profile/radeon_ioctl.c b/radeon-profile/radeon_ioctl.c new file mode 100644 index 0000000..f47ff01 --- /dev/null +++ b/radeon-profile/radeon_ioctl.c @@ -0,0 +1,197 @@ +#include "radeon_ioctl.h" + + +#ifdef NO_IOCTL + + +int openCardFD(const char * card){(void)card; return -1;} +void closeCardFD(int fd){(void)fd;} +int radeonTemperature(int fd, int *data){(void)fd;(void)data; return -1;} +int radeonCoreClock(int fd, unsigned *data){(void)fd;(void)data; return -1;} +int radeonMemoryClock(int fd, unsigned *data){(void)fd;(void)data; return -1;} +int radeonMaxCoreClock(int fd, unsigned *data){(void)fd;(void)data; return -1;} +int radeonVramUsage(int fd, unsigned long *data){(void)fd;(void)data; return -1;} +int radeonGttUsage(int fd, unsigned long *data){(void)fd;(void)data; return -1;} +int radeonReadRegistry(int fd, unsigned *data){(void)fd;(void)data; return -1;} +int radeonGpuUsage(int fd, float *data, unsigned time, unsigned frequency){(void)fd;(void)data;(void)time;(void)frequency; return -1;} +int amdgpuVramSize(int fd, unsigned long *data){(void)fd;(void)data; return -1;} +int amdgpuVramUsage(int fd, unsigned long *data){(void)fd;(void)data; return -1;} +int amdgpuGttUsage(int fd, unsigned long *data){(void)fd;(void)data; return -1;} +int amdgpuReadRegistry(int fd, unsigned *data){(void)fd;(void)data; return -1;} +int amdgpuGpuUsage(int fd, float *data, unsigned time, unsigned frequency){(void)fd;(void)data;(void)time;(void)frequency; return -1;} + + +#else + + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLEAN(object) memset(&(object), 0, sizeof(object)) +#define PATH_SIZE 20 + +void errorDebug(const char * title){ +#ifdef QT_NO_DEBUG_OUTPUT + (void)title; +#else + perror(title); +#endif +} + +int openCardFD(const char * card){ + int fd; + char path[PATH_SIZE] = "/dev/dri/"; + + strncat(path, card, PATH_SIZE-strlen(path)-1); + fd= open(path,O_RDONLY); + + if(fd < 0) + errorDebug("open"); + + return fd; +} + +void closeCardFD(int fd){ + if(close(fd)) + errorDebug("close"); +} + +int gpuUsage(int fd, float *data, unsigned time, unsigned frequency, int(*accessRegistry)(int fd, unsigned *data)){ +#define REGISTRY_ADDRESS 0x8010 // http://support.amd.com/TechDocs/46142.pdf#page=246 +#define REGISTRY_MASK 1<<31 +#define ONE_SECOND 1000000 + const unsigned int sleep = ONE_SECOND/frequency; + unsigned int remaining, activeCount = 0, totalCount = 0, buffer; + int error; + for(remaining = time; (remaining > 0) && (remaining <= time); remaining -= (sleep - usleep(sleep)), totalCount++){ + buffer = REGISTRY_ADDRESS; + error = accessRegistry(fd, &buffer); + + if(error) + return error; + + if(REGISTRY_MASK & buffer) + activeCount++; + } + + if(totalCount == 0) + return -1; + + *data = (100.0f * activeCount) / totalCount; + +#ifndef QT_NO_DEBUG_OUTPUT + printf("%u active moments out of %u (%3.2f%%) in %umS (Sampling at %uHz)\n", activeCount, totalCount, *data, time/1000, frequency); +#endif + + return 0; +} + +/******************** RADEON ********************/ +#include // http://lxr.free-electrons.com/source/include/uapi/drm/radeon_drm.h#L993 + +int radeonGetValue(int fd, void *data, uint32_t command){ + int error; + struct drm_radeon_info buffer; + CLEAN(buffer); + buffer.request = command; + buffer.value = (uint64_t)data; + + error = ioctl(fd, DRM_IOCTL_RADEON_INFO, &buffer); + if(error) + errorDebug("ioctl radeon"); + + return error; +} + +int radeonTemperature(int fd, int *data){ + return radeonGetValue(fd, data, RADEON_INFO_CURRENT_GPU_TEMP); // http://lxr.free-electrons.com/source/drivers/gpu/drm/radeon/radeon_kms.c#L555 +} + +int radeonCoreClock(int fd, unsigned *data){ + return radeonGetValue(fd, data, RADEON_INFO_CURRENT_GPU_SCLK); // http://lxr.free-electrons.com/source/drivers/gpu/drm/radeon/radeon_kms.c#L562 +} + +int radeonMaxCoreClock(int fd, unsigned *data){ + return radeonGetValue(fd, data, RADEON_INFO_MAX_SCLK); // http://lxr.free-electrons.com/source/drivers/gpu/drm/radeon/radeon_kms.c#L511 +} + +int radeonMemoryClock(int fd, unsigned *data){ + return radeonGetValue(fd, data, RADEON_INFO_CURRENT_GPU_MCLK); // http://lxr.free-electrons.com/source/drivers/gpu/drm/radeon/radeon_kms.c#L569 +} + +int radeonVramUsage(int fd, unsigned long *data){ + return radeonGetValue(fd, data, RADEON_INFO_VRAM_USAGE); // http://lxr.free-electrons.com/source/drivers/gpu/drm/radeon/radeon_kms.c#L529 +} + +int radeonGttUsage(int fd, unsigned long *data){ + return radeonGetValue(fd, data, RADEON_INFO_GTT_USAGE); // http://lxr.free-electrons.com/source/drivers/gpu/drm/radeon/radeon_kms.c#L534 +} + +int radeonReadRegistry(int fd, unsigned *data){ + return radeonGetValue(fd, data, RADEON_INFO_READ_REG); // http://lxr.free-electrons.com/source/drivers/gpu/drm/radeon/radeon_kms.c#L576 +} + +int radeonGpuUsage(int fd, float *data, unsigned time, unsigned frequency){ + return gpuUsage(fd, data, time, frequency, radeonReadRegistry); +} + + +/******************** AMDGPU ********************/ +#include // http://lxr.free-electrons.com/source/include/uapi/drm/amdgpu_drm.h#L441 + +int amdgpuVramSize(int fd, unsigned long *data){ + int error; + struct drm_amdgpu_info_vram_gtt info; + struct drm_amdgpu_info buffer; + CLEAN(buffer); + buffer.query = AMDGPU_INFO_VRAM_GTT; // http://lxr.free-electrons.com/source/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c#L404 + buffer.return_pointer = (uint64_t)&info; + buffer.return_size = sizeof(info); + + error = ioctl(fd, DRM_IOCTL_AMDGPU_INFO, &buffer); + *data = info.vram_size; + + if(error) + errorDebug("ioctl amdgpu"); + + return error; +} + +int amdgpuGetValue(int fd, void *data, uint32_t command){ + int error; + struct drm_amdgpu_info buffer; + CLEAN(buffer); + buffer.query = command; + buffer.return_pointer = (uint64_t)data; + buffer.return_size = sizeof(unsigned long); + + error = ioctl(fd, DRM_IOCTL_AMDGPU_INFO, &buffer); + if(error) + errorDebug("ioctl amdgpu"); + + return error; +} + +int amdgpuVramUsage(int fd, unsigned long *data){ + return amdgpuGetValue(fd, data, AMDGPU_INFO_VRAM_USAGE); // http://lxr.free-electrons.com/source/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c#L381 +} + +int amdgpuGttUsage(int fd, unsigned long *data){ + return amdgpuGetValue(fd, data, AMDGPU_INFO_GTT_USAGE); // http://lxr.free-electrons.com/source/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c#L387 +} + +int amdgpuReadRegistry(int fd, unsigned *data){ + return amdgpuGetValue(fd, data, AMDGPU_INFO_READ_MMR_REG); // http://lxr.free-electrons.com/source/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c#L416 +} + +int amdgpuGpuUsage(int fd, float *data, unsigned time, unsigned frequency){ + return gpuUsage(fd, data, time, frequency, amdgpuReadRegistry); +} + +#endif diff --git a/radeon-profile/radeon_ioctl.h b/radeon-profile/radeon_ioctl.h new file mode 100644 index 0000000..0a7735c --- /dev/null +++ b/radeon-profile/radeon_ioctl.h @@ -0,0 +1,116 @@ +#ifndef RADEON_IOCTL_H +#define RADEON_IOCTL_H + + + +/** + * @brief openCardFD Open the file descriptor needed for ioctls + * @param card Name of the card to be opened (e.g. card0). + * @warning You can find the list of available cards by running 'ls /dev/dri/' + * @return File descriptor >=0 on success, error value <0 on failure + */ +int openCardFD(const char * card); + + +/** + * @brief closeCardFD Close a file descriptor + * @param fd The file descriptor to close + */ +void closeCardFD(int fd); + + +/** + * @brief radeonTemperature Get GPU temperature [RADEON driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, in °mC (milliCelsius) + * @return 0 on success, error value !=0 on failure + */ +int radeonTemperature(int fd, int *data); + + +/** + * @brief radeonCoreClock Get GPU current clock (sclk) [RADEON driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, in MHz + * @return 0 on success, error value !=0 on failure + */ +int radeonCoreClock(int fd, unsigned *data); + + +/** + * @brief radeonMaxCoreClock Get GPU maximum clock [RADEON driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, in KHz + * @return 0 on success, error value !=0 on failure + */ +int radeonMaxCoreClock(int fd, unsigned *data); + + +/** + * @brief radeonGpuUsage Get how busy the GPU is [RADEON driver] + * @brief amdgpuGpuUsage Get how busy the GPU is [AMDGPU driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, as percentage of time (o%=idle, 100%=full) + * @param time How much time to consider, in μS (microSeconds) + * @warning This function blocks the application for the whole time indicated in 'time' + * @param frequency How frequently to check if the GPU is busy during the time, in Hz + * @warning A frequency > 100 Hz is suggested (A low sampling frequency reduces precision) + * @return 0 on success, error value !=0 on failure + */ +int radeonGpuUsage(int fd, float *data, unsigned time, unsigned frequency); +int amdgpuGpuUsage(int fd, float *data, unsigned time, unsigned frequency); + + +/** + * @brief radeonMemoryClock Get VRAM memory current clock (mclk) [RADEON driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, in MHz + * @return 0 on success, error value !=0 on failure + */ +int radeonMemoryClock(int fd, unsigned *data); + + +/** + * @brief radeonVramUsage Get VRAM memory current usage [RADEON driver] + * @brief amdgpuVramUsage Get VRAM memory current usage [AMDGPU driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, in bytes + * @return 0 on success, error value !=0 on failure + */ +int radeonVramUsage(int fd, unsigned long *data); +int amdgpuVramUsage(int fd, unsigned long *data); + + +/** + * @brief amdgpuVramSize Get VRAM memory size [AMDGPU driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, in bytes + * @return 0 on success, error value !=0 on failure + */ +int amdgpuVramSize(int fd, unsigned long *data); + + +/** + * @brief radeonGttUsage Get GTT memory current usage [RADEON driver] + * @brief amdgpuGttUsage Get GTT memory current usage [AMDGPU driver] + * @param fd File descriptor to use + * @param data On success is filled with the value, in bytes + * @return 0 on success, error value !=0 on failure + */ +int radeonGttUsage(int fd, unsigned long *data); +int amdgpuGttUsage(int fd, unsigned long *data); + + +/** + * @brief radeonReadRegistry Read the content of a GPU register [RADEON driver] + * @brief amdgpuReadRegistry Read the content of a GPU register [AMDGPU driver] + * @param fd File descriptor to use + * @param data When called must contain the registry address. On success is filled with the content of the register. + * @return 0 on success, error value !=0 on failure + */ +int radeonReadRegistry(int fd, unsigned *data); +int amdgpuReadRegistry(int fd, unsigned *data); + + + +#endif diff --git a/radeon-profile/radeon_profile.cpp b/radeon-profile/radeon_profile.cpp index 46e102c..8db463a 100644 --- a/radeon-profile/radeon_profile.cpp +++ b/radeon-profile/radeon_profile.cpp @@ -35,6 +35,7 @@ radeon_profile::radeon_profile(QStringList a,QWidget *parent) : rangeX = 180; ticksCounter = 0; statsTickCounter = 0; + savedState = nullptr; ui->setupUi(this); timer = new QTimer(this); @@ -94,6 +95,7 @@ radeon_profile::radeon_profile(QStringList a,QWidget *parent) : connectSignals(); showWindow(); + qDebug() << "Initialization completed"; } radeon_profile::~radeon_profile() diff --git a/radeon-profile/radeon_profile.h b/radeon-profile/radeon_profile.h index 120891c..23bd961 100644 --- a/radeon-profile/radeon_profile.h +++ b/radeon-profile/radeon_profile.h @@ -173,7 +173,7 @@ private: QMap pmStats; unsigned int rangeX, ticksCounter, statsTickCounter; QButtonGroup pwmGroup; - currentStateInfo *savedState = nullptr; + currentStateInfo *savedState; Ui::radeon_profile *ui; void setupGraphs();