Merge pull request #1165 from sam-kirby/feat/encdec

Add encode and decode meters on Nvidia GPUs
This commit is contained in:
Jakob P. Liljenberg
2025-07-28 14:52:13 +02:00
committed by GitHub
3 changed files with 60 additions and 6 deletions

View File

@@ -947,6 +947,7 @@ namespace Gpu {
vector<Draw::Graph> mem_used_graph_vec = {}, mem_util_graph_vec = {};
vector<Draw::Meter> gpu_meter_vec = {};
vector<Draw::Meter> pwr_meter_vec = {};
vector<Draw::Meter> enc_meter_vec = {};
vector<string> box = {};
string draw(const gpu_info& gpu, unsigned long index, bool force_redraw, bool data_same) {
@@ -964,6 +965,7 @@ namespace Gpu {
auto& mem_util_graph = mem_util_graph_vec[index];
auto& gpu_meter = gpu_meter_vec[index];
auto& pwr_meter = pwr_meter_vec[index];
auto& enc_meter = enc_meter_vec[index];
if (force_redraw) redraw[index] = true;
bool show_temps = gpu.supported_functions.temp_info and (Config::getB("check_temp"));
@@ -1002,6 +1004,8 @@ namespace Gpu {
mem_util_graph = Draw::Graph{b_width/2 - 1, 2, "free", gpu.mem_utilization_percent, graph_symbol, 0, 0, 100, 4}; // offset so the graph isn't empty at 0-5% utilization
if (gpu.supported_functions.mem_used and gpu.supported_functions.mem_total)
mem_used_graph = Draw::Graph{b_width/2 - 2, 2 + 2*(gpu.supported_functions.mem_utilization), "used", safeVal(gpu.gpu_percent, "gpu-vram-totals"s), graph_symbol};
if (gpu.supported_functions.encoder_utilization)
enc_meter = Draw::Meter{b_width/2 - 10, "cpu"};
}
@@ -1041,8 +1045,17 @@ namespace Gpu {
out += std::string(" P-state: ") + (gpu.pwr_state > 9 ? "" : " ") + 'P' + Theme::g("cached").at(clamp(gpu.pwr_state, 0ll, 100ll)) + to_string(gpu.pwr_state);
}
//? Encode and Decode meters
bool drawnEncDec = gpu.supported_functions.encoder_utilization and gpu.supported_functions.decoder_utilization;
if (drawnEncDec) {
out += Mv::to(b_y + 3, b_x +1) + Theme::c("main_fg") + Fx::b + "ENC " + enc_meter(gpu.encoder_utilization)
+ Theme::g("cpu").at(clamp(gpu.encoder_utilization, 0ll, 100ll)) + rjust(to_string(gpu.encoder_utilization), 4) + Theme::c("main_fg") + '%'
+ Theme::c("div_line") + Symbols::v_line + Theme::c("main_fg") + Fx::b + "DEC " + enc_meter(gpu.decoder_utilization)
+ Theme::g("cpu").at(clamp(gpu.decoder_utilization, 0ll, 100ll)) + rjust(to_string(gpu.decoder_utilization), 4) + Theme::c("main_fg") + '%';
}
if (gpu.supported_functions.mem_total or gpu.supported_functions.mem_used) {
out += Mv::to(b_y + 3, b_x);
out += Mv::to(b_y + (drawnEncDec ? 4 : 3), b_x);
if (gpu.supported_functions.mem_total and gpu.supported_functions.mem_used) {
string used_memory_string = floating_humanizer(gpu.mem_used);
@@ -1067,7 +1080,7 @@ namespace Gpu {
//? Memory clock speed
if (gpu.supported_functions.mem_clock) {
string clock_speed_string = to_string(gpu.mem_clock_speed);
out += Mv::to(b_y + 3, b_x + b_width/2 - 11) + Theme::c("div_line") + Symbols::h_line*(5-clock_speed_string.size())
out += Mv::to(b_y + (drawnEncDec ? 4 : 3), b_x + b_width/2 - 11) + Theme::c("div_line") + Symbols::h_line*(5-clock_speed_string.size())
+ Symbols::title_left + Fx::b + Theme::c("title") + clock_speed_string + " MHz" + Fx::ub + Theme::c("div_line") + Symbols::title_right;
}
} else {
@@ -2100,6 +2113,7 @@ namespace Draw {
mem_used_graph_vec.resize(shown); mem_util_graph_vec.resize(shown);
gpu_meter_vec.resize(shown);
pwr_meter_vec.resize(shown);
enc_meter_vec.resize(shown);
redraw.resize(shown);
for (auto i = 0; i < shown; ++i) {
redraw[i] = true;
@@ -2120,7 +2134,7 @@ namespace Draw {
box[i] = createBox(x_vec[i], y_vec[i], width, height, Theme::c("cpu_box"), true, std::string("gpu") + (char)(shown_panels[i]+'0'), "", (shown_panels[i]+5)%10); // TODO gpu_box
b_height_vec[i] = 2 + gpu_b_height_offsets[shown_panels[i]];
b_width = clamp(width/2, min_width, 64);
b_width = clamp(width/2, min_width, 65);
//? Main statistics box
b_x_vec[i] = x_vec[i] + width - b_width - 1;

View File

@@ -139,7 +139,9 @@ namespace Gpu {
temp_info = true,
mem_total = true,
mem_used = true,
pcie_txrx = true;
pcie_txrx = true,
encoder_utilization = true,
decoder_utilization = true;
};
//* Per-device container for GPU info
@@ -166,6 +168,9 @@ namespace Gpu {
long long pcie_tx = 0; // KB/s
long long pcie_rx = 0;
long long encoder_utilization = 0;
long long decoder_utilization = 0;
gpu_info_supported supported_functions;
// vector<proc_info> graphics_processes = {}; // TODO

View File

@@ -151,6 +151,8 @@ namespace Gpu {
nvmlReturn_t (*nvmlDeviceGetTemperature)(nvmlDevice_t, nvmlTemperatureSensors_t, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetMemoryInfo)(nvmlDevice_t, nvmlMemory_t*);
nvmlReturn_t (*nvmlDeviceGetPcieThroughput)(nvmlDevice_t, nvmlPcieUtilCounter_t, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetEncoderUtilization)(nvmlDevice_t, unsigned int*, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetDecoderUtilization)(nvmlDevice_t, unsigned int*, unsigned int*);
//? Data
void* nvml_dl_handle;
@@ -308,6 +310,7 @@ namespace Shared {
for (size_t i = 0; i < gpu_b_height_offsets.size(); ++i)
gpu_b_height_offsets[i] = gpus[i].supported_functions.gpu_utilization
+ gpus[i].supported_functions.pwr_usage
+ (gpus[i].supported_functions.encoder_utilization or gpus[i].supported_functions.decoder_utilization)
+ (gpus[i].supported_functions.mem_total or gpus[i].supported_functions.mem_used)
* (1 + 2*(gpus[i].supported_functions.mem_total and gpus[i].supported_functions.mem_used) + 2*gpus[i].supported_functions.mem_utilization);
}
@@ -1062,6 +1065,8 @@ namespace Gpu {
LOAD_SYM(nvmlDeviceGetTemperature);
LOAD_SYM(nvmlDeviceGetMemoryInfo);
LOAD_SYM(nvmlDeviceGetPcieThroughput);
LOAD_SYM(nvmlDeviceGetEncoderUtilization);
LOAD_SYM(nvmlDeviceGetDecoderUtilization);
#undef LOAD_SYM
@@ -1117,7 +1122,7 @@ namespace Gpu {
result = nvmlDeviceGetHandleByIndex(i, devices.data() + i);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get device handle: ") + nvmlErrorString(result));
gpus[i].supported_functions = {false, false, false, false, false, false, false, false};
gpus[i].supported_functions = {false, false, false, false, false, false, false, false, false, false};
continue;
}
@@ -1264,6 +1269,30 @@ namespace Gpu {
}
}
// nvTimer.stop_rename_reset("Nv enc");
//? Encoder info
if (gpus_slice[i].supported_functions.encoder_utilization) {
unsigned int utilization;
unsigned int samplingPeriodUs;
result = nvmlDeviceGetEncoderUtilization(devices[i], &utilization, &samplingPeriodUs);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get encoder utilization: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.encoder_utilization = false;
} else gpus_slice[i].encoder_utilization = (long long)utilization;
}
// nvTimer.stop_rename_reset("Nv dec");
//? Decoder info
if (gpus_slice[i].supported_functions.decoder_utilization) {
unsigned int utilization;
unsigned int samplingPeriodUs;
result = nvmlDeviceGetDecoderUtilization(devices[i], &utilization, &samplingPeriodUs);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get decoder utilization: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.decoder_utilization = false;
} else gpus_slice[i].decoder_utilization = (long long)utilization;
}
//? TODO: Processes using GPU
/*unsigned int proc_info_len;
nvmlProcessInfo_t* proc_info = 0;
@@ -1437,6 +1466,10 @@ namespace Gpu {
if (result != RSMI_STATUS_SUCCESS)
Logger::warning("ROCm SMI: Failed to get maximum GPU temperature, defaulting to 110°C");
else gpus_slice[i].temp_max = (long long)temp_max;
//? Disable encoder and decoder utilisation on AMD
gpus_slice[i].supported_functions.encoder_utilization = false;
gpus_slice[i].supported_functions.decoder_utilization = false;
}
//? GPU utilization
@@ -1668,7 +1701,9 @@ namespace Gpu {
.temp_info = false,
.mem_total = false,
.mem_used = false,
.pcie_txrx = false
.pcie_txrx = false,
.encoder_utilization = false,
.decoder_utilization = false
};
gpus_slice->pwr_max_usage = 10'000; //? 10W