You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MangoHud/src/gpu.cpp

152 lines
4.5 KiB
C++

#include "gpu.h"
#include <inttypes.h>
#include <memory>
#include <functional>
#include <thread>
#include <cstring>
#include <spdlog/spdlog.h>
#include "nvctrl.h"
#include "timing.hpp"
#include "file_utils.h"
#ifdef HAVE_NVML
#include "nvidia_info.h"
#endif
#include "amdgpu.h"
using namespace std::chrono_literals;
std::shared_ptr<gpu_device> g_active_gpu;
std::unordered_map<std::string /*device*/, std::shared_ptr<gpu_device>> g_gpu_devices;
bool NVCtrlInfo::init()
{
#ifdef HAVE_XNVCTRL
// FIXME correct device index
return checkXNVCtrl();
#else
return false;
#endif
}
void NVCtrlInfo::update(const struct overlay_params& params)
{
#ifdef HAVE_XNVCTRL
if (nvctrlSuccess) {
getNvctrlInfo();
info.load = nvctrl_info.load;
info.temp = nvctrl_info.temp;
info.memory_used = nvctrl_info.memoryUsed;
info.core_clock = nvctrl_info.CoreClock;
info.memory_clock = nvctrl_info.MemClock;
info.power_usage = 0;
info.memory_total = nvctrl_info.memoryTotal;
return;
}
#endif
}
void getAmdGpuInfo(amdgpu_files& amdgpu, gpu_info& gpu_info, bool has_metrics){
int64_t value = 0;
if (!has_metrics){
if (amdgpu.busy) {
rewind(amdgpu.busy);
fflush(amdgpu.busy);
int value = 0;
if (fscanf(amdgpu.busy, "%d", &value) != 1)
value = 0;
gpu_info.load = value;
}
if (amdgpu.core_clock) {
rewind(amdgpu.core_clock);
fflush(amdgpu.core_clock);
if (fscanf(amdgpu.core_clock, "%" PRId64, &value) != 1)
value = 0;
gpu_info.core_clock = value / 1000000;
}
if (amdgpu.memory_clock) {
rewind(amdgpu.memory_clock);
fflush(amdgpu.memory_clock);
if (fscanf(amdgpu.memory_clock, "%" PRId64, &value) != 1)
value = 0;
gpu_info.memory_clock = value / 1000000;
}
if (amdgpu.power_usage) {
rewind(amdgpu.power_usage);
fflush(amdgpu.power_usage);
if (fscanf(amdgpu.power_usage, "%" PRId64, &value) != 1)
value = 0;
gpu_info.power_usage = value / 1000000;
}
}
if (amdgpu.vram_total) {
rewind(amdgpu.vram_total);
fflush(amdgpu.vram_total);
if (fscanf(amdgpu.vram_total, "%" PRId64, &value) != 1)
value = 0;
gpu_info.memory_total = value;
}
if (amdgpu.vram_used) {
rewind(amdgpu.vram_used);
fflush(amdgpu.vram_used);
if (fscanf(amdgpu.vram_used, "%" PRId64, &value) != 1)
value = 0;
gpu_info.memory_used = value;
}
// On some GPUs SMU can sometimes return the wrong temperature.
// As HWMON is way more visible than the SMU metrics, let's always trust it as it is the most likely to work
if (amdgpu.temp){
rewind(amdgpu.temp);
fflush(amdgpu.temp);
int value = 0;
if (fscanf(amdgpu.temp, "%d", &value) != 1)
value = 0;
gpu_info.temp = value / 1000;
}
if (amdgpu.gtt_used) {
rewind(amdgpu.gtt_used);
fflush(amdgpu.gtt_used);
if (fscanf(amdgpu.gtt_used, "%" PRId64, &value) != 1)
value = 0;
gpu_info.gtt_used = value;
}
}
bool AMDGPUHWMonInfo::init()
{
const auto device_path = sysfs_path + "/device";
const auto hwmon_path = device_path + "/hwmon/";
files.busy = fopen((device_path + "/gpu_busy_percent").c_str(), "r");
files.vram_total = fopen((device_path + "/mem_info_vram_total").c_str(), "r");
files.vram_used = fopen((device_path + "/mem_info_vram_used").c_str(), "r");
files.gtt_used = fopen((device_path + "/mem_info_gtt_used").c_str(), "r");
const auto dirs = ls(hwmon_path, "hwmon", LS_DIRS);
for (const auto& dir : dirs) {
if (!files.core_clock)
files.core_clock = fopen((hwmon_path + dir + "/freq1_input").c_str(), "r");
if (!files.memory_clock)
files.memory_clock = fopen((hwmon_path + dir + "/freq2_input").c_str(), "r");
if (!files.temp)
files.temp = fopen((hwmon_path + dir + "/temp1_input").c_str(), "r");
if (!files.power_usage)
files.power_usage = fopen((hwmon_path + dir + "/power1_average").c_str(), "r");
}
return files.busy && files.temp && files.vram_total && files.vram_used;
}
void AMDGPUHWMonInfo::update(const struct overlay_params& params)
{
getAmdGpuInfo(files, info, false);
}