diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index 8bc32d3..604e8c7 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -808,7 +808,7 @@ namespace Cpu { for (unsigned long i = 0; i < gpus.size(); ++i) { if (not v_contains(Gpu::shown_panels, i)) { out += Mv::to(b_y + b_height - 1 - gpus.size() + ++shown_panels_count - (Gpu::shown == 0), b_x + 1) - + Theme::c("main_fg") + Fx::b + "GPU " + (gpus.size() > 1 ? rjust(to_string(i) + ' ', 1 + gpus.size() > 9) : ""); + + Theme::c("main_fg") + Fx::b + "GPU " + (gpus.size() > 1 ? ((gpus.size() > 9 and i <= 9 ? " " : "") + to_string(i) + ' ') : ""); if (gpus[i].supported_functions.gpu_utilization) out += gpu_meters[i](gpus[i].gpu_percent.back()) + Theme::g("cpu").at(gpus[i].gpu_percent.back()) + rjust(to_string(gpus[i].gpu_percent.back()), 4) + Theme::c("main_fg") + '%'; @@ -842,8 +842,8 @@ namespace Gpu { int width_p = 100, height_p = 32; int min_width = 41, min_height = 9; int width = 41, height; - vector x_vec = {}, y_vec = {}; - int b_width, b_height; + vector x_vec = {}, y_vec = {}, b_height_vec = {}; + int b_width; vector b_x_vec = {}, b_y_vec = {}; vector redraw = {}, mid_line = {}; int shown = 0; @@ -873,7 +873,7 @@ namespace Gpu { auto& pwr_meter = pwr_meter_vec[index]; if (force_redraw) redraw[index] = true; - bool show_temps = (Config::getB("check_temp")); + bool show_temps = gpu.supported_functions.temp_info and (Config::getB("check_temp")); auto tty_mode = Config::getB("tty_mode"); auto& temp_scale = Config::getS("temp_scale"); auto& graph_symbol = (tty_mode ? "tty" : Config::getS("graph_symbol_cpu")); // TODO graph_symbol_gpu @@ -888,93 +888,120 @@ namespace Gpu { const int graph_low_height = height - 2 - graph_up_height - (mid_line[index] ? 1 : 0); out += box[index]; - graph_upper = Draw::Graph{x + width - b_width - 3, graph_up_height, "cpu", gpu.gpu_percent, graph_symbol, false, true}; // TODO cpu -> gpu - if (not single_graph) { - graph_lower = Draw::Graph{ - x + width - b_width - 3, - graph_low_height, "cpu", - gpu.gpu_percent, - graph_symbol, - Config::getB("cpu_invert_lower"), true - }; - } - - gpu_meter = Draw::Meter{b_width - (show_temps ? 24 : 11), "cpu"}; - temp_graph = Draw::Graph{6, 1, "temp", gpu.temp, graph_symbol, false, false, gpu.temp_max, -23}; - - pwr_meter = Draw::Meter{b_width - 24, "cached"}; - - 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 - mem_used_graph = Draw::Graph{b_width/2 - 2, 4, "used", gpu.mem_used_percent, graph_symbol}; + if (gpu.supported_functions.gpu_utilization) { + graph_upper = Draw::Graph{x + width - b_width - 3, graph_up_height, "cpu", gpu.gpu_percent, graph_symbol, false, true}; // TODO cpu -> gpu + if (not single_graph) { + graph_lower = Draw::Graph{ + x + width - b_width - 3, + graph_low_height, "cpu", + gpu.gpu_percent, + graph_symbol, + Config::getB("cpu_invert_lower"), true + }; + } + gpu_meter = Draw::Meter{b_width - (show_temps ? 24 : 11), "cpu"}; + } + if (gpu.supported_functions.temp_info) + temp_graph = Draw::Graph{6, 1, "temp", gpu.temp, graph_symbol, false, false, gpu.temp_max, -23}; + if (gpu.supported_functions.pwr_usage) + pwr_meter = Draw::Meter{b_width - 24, "cached"}; + if (gpu.supported_functions.mem_utilization) + 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", gpu.mem_used_percent, graph_symbol}; } //* General GPU info - //? Gpu graph, clock speed & meter - out += Fx::ub + Mv::to(y + 1, x + 1) + graph_upper(gpu.gpu_percent, (data_same or redraw[index])); - if (not single_graph) - out += Mv::to(y + graph_up_height + 1 + mid_line[index], x + 1) + graph_lower(gpu.gpu_percent, (data_same or redraw[index])); + //? Gpu graph, meter & clock speed + if (gpu.supported_functions.gpu_utilization) { + out += Fx::ub + Mv::to(y + 1, x + 1) + graph_upper(gpu.gpu_percent, (data_same or redraw[index])); + if (not single_graph) + out += Mv::to(y + graph_up_height + 1 + mid_line[index], x + 1) + graph_lower(gpu.gpu_percent, (data_same or redraw[index])); - if (Config::getB("show_cpu_freq")) { // TODO show_gpu_freq + out += Mv::to(b_y + 1, b_x + 1) + Theme::c("main_fg") + Fx::b + "GPU " + gpu_meter(gpu.gpu_percent.back()) + + Theme::g("cpu").at(gpu.gpu_percent.back()) + rjust(to_string(gpu.gpu_percent.back()), 4) + Theme::c("main_fg") + '%'; + + //? Temperature graph, I assume the device supports utilization if it supports temperature + if (show_temps) { + const auto [temp, unit] = celsius_to(gpu.temp.back(), temp_scale); + out += ' ' + Theme::c("inactive_fg") + graph_bg * 6 + Mv::l(6) + Theme::g("temp").at(clamp(gpu.temp.back() * 100 / gpu.temp_max, 0ll, 100ll)) + + temp_graph(gpu.temp, data_same or redraw[index]); + out += rjust(to_string(temp), 4) + Theme::c("main_fg") + unit; + } + out += Theme::c("div_line") + Symbols::v_line; + } + + if (gpu.supported_functions.gpu_clock and Config::getB("show_cpu_freq")) { // TODO show_gpu_freq string clock_speed_string = to_string(gpu.gpu_clock_speed); out += Mv::to(b_y, b_x + b_width - 12) + 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; } - out += Mv::to(b_y + 1, b_x + 1) + Theme::c("main_fg") + Fx::b + "GPU " + gpu_meter(gpu.gpu_percent.back()) - + Theme::g("cpu").at(gpu.gpu_percent.back()) + rjust(to_string(gpu.gpu_percent.back()), 4) + Theme::c("main_fg") + '%'; - - //? Temperature graph - if (show_temps) { - const auto [temp, unit] = celsius_to(gpu.temp.back(), temp_scale); - out += ' ' + Theme::c("inactive_fg") + graph_bg * 6 + Mv::l(6) + Theme::g("temp").at(clamp(gpu.temp.back() * 100 / gpu.temp_max, 0ll, 100ll)) - + temp_graph(gpu.temp, data_same or redraw[index]); - out += rjust(to_string(temp), 4) + Theme::c("main_fg") + unit; - } - out += Theme::c("div_line") + Symbols::v_line; - //? Power usage meter, power state - out += Mv::to(b_y + 2, b_x + 1) + Theme::c("main_fg") + Fx::b + "PWR " + pwr_meter(gpu.pwr_percent.back()) - + Theme::g("cached").at(gpu.pwr_percent.back()) + rjust(to_string(gpu.pwr_usage/1000), 4) + Theme::c("main_fg") + 'W'; - if (gpu.pwr_state != 32) // NVML_PSTATE_UNKNOWN; unsupported or non-nvidia card - out += std::string(" P-state: ") + (gpu.pwr_state > 9 ? "" : " ") + 'P' + Theme::g("cached").at(gpu.pwr_state) + to_string(gpu.pwr_state); - - //? Memory section header & clock speed - string used_memory_string = floating_humanizer(gpu.mem_used); - out += Mv::to(b_y + 3, b_x) + Theme::c("div_line") + Symbols::div_left + Symbols::h_line + Symbols::title_left + Fx::b + Theme::c("title") + "vram" - + Theme::c("div_line") + Fx::ub + Symbols::title_right + Symbols::h_line*(b_width/2-8) + Symbols::div_up + Symbols::h_line - + Theme::c("title") + "Used:" + Theme::c("div_line") + Symbols::h_line*(b_width/2+b_width%2-9-used_memory_string.size()) + Theme::c("title") + used_memory_string + Theme::c("div_line") + Symbols::h_line + Symbols::div_right; - if (Config::getB("show_cpu_freq")) { // TODO show_gpu_freq - 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()) - + Symbols::title_left + Fx::b + Theme::c("title") + clock_speed_string + " Mhz" + Fx::ub + Theme::c("div_line") + Symbols::title_right; + if (gpu.supported_functions.pwr_usage) { + out += Mv::to(b_y + 2, b_x + 1) + Theme::c("main_fg") + Fx::b + "PWR " + pwr_meter(gpu.pwr_percent.back()) + + Theme::g("cached").at(gpu.pwr_percent.back()) + rjust(to_string(gpu.pwr_usage/1000), 4) + Theme::c("main_fg") + 'W'; + if (gpu.supported_functions.pwr_state and gpu.pwr_state != 32) // NVML_PSTATE_UNKNOWN; unsupported or non-nvidia card + out += std::string(" P-state: ") + (gpu.pwr_state > 9 ? "" : " ") + 'P' + Theme::g("cached").at(gpu.pwr_state) + to_string(gpu.pwr_state); } - //? Memory usage borders - out += Mv::to(b_y + 5, b_x) + Theme::c("div_line") + Symbols::div_left+Symbols::h_line + Theme::c("title") + "Utilization:" + Theme::c("div_line") + Symbols::h_line*(b_width/2-14) - + Symbols::div_right + Mv::u(1)+Mv::l(1) + Symbols::v_line + Mv::l(1)+Mv::d(2) + (Symbols::v_line + Mv::l(1)+Mv::d(1))*2; + if (gpu.supported_functions.mem_total or gpu.supported_functions.mem_used) { + out += Mv::to(b_y + 3, b_x); + if (gpu.supported_functions.mem_total and gpu.supported_functions.mem_used) { + string used_memory_string = floating_humanizer(gpu.mem_used); - //? Total memory usage - out += Mv::to(b_y + 4, b_x + 2) + Theme::c("main_fg") + Fx::b + "Total:" + rjust(floating_humanizer(gpu.mem_total), b_width/2-9) + Fx::ub; + auto offset = (gpu.supported_functions.mem_total or gpu.supported_functions.mem_used) + * (1 + 2*(gpu.supported_functions.mem_total and gpu.supported_functions.mem_used) + 2*gpu.supported_functions.mem_utilization); - //? Memory usage graphs & percentage - out += Mv::to(b_y+6, b_x+1) + Theme::c("inactive_fg") + mem_util_graph(gpu.mem_utilization_percent, (data_same or redraw[index])) - + Mv::u(3) + Mv::r(1) + mem_used_graph(gpu.mem_used_percent, (data_same or redraw[index])); - out += Mv::to(b_y+6, b_x+1) + rjust(to_string(gpu.mem_utilization_percent.back()), 3) + '%' + Mv::u(2) + Mv::r(b_width/2-3) + rjust(to_string(gpu.mem_used_percent.back()), 3) + '%'; + //? Used graph, memory section header, total vram + out += Theme::c("div_line") + Symbols::div_left + Symbols::h_line + Symbols::title_left + Fx::b + Theme::c("title") + "vram" + Theme::c("div_line") + Fx::ub + Symbols::title_right + + Symbols::h_line*(b_width/2-8) + Symbols::div_up + Mv::d(offset)+Mv::l(1) + Symbols::div_down + Mv::l(1)+Mv::u(1) + (Symbols::v_line + Mv::l(1)+Mv::u(1))*(offset-1) + Symbols::div_up + + Symbols::h_line + Theme::c("title") + "Used:" + Theme::c("div_line") + + Symbols::h_line*(b_width/2+b_width%2-9-used_memory_string.size()) + Theme::c("title") + used_memory_string + Theme::c("div_line") + Symbols::h_line + Symbols::div_right + + Mv::d(1) + Mv::l(b_width/2-1) + mem_used_graph(gpu.mem_used_percent, (data_same or redraw[index])) + + Mv::l(b_width-3) + Mv::u(1+2*gpu.supported_functions.mem_utilization) + Theme::c("main_fg") + Fx::b + "Total:" + rjust(floating_humanizer(gpu.mem_total), b_width/2-9) + Fx::ub + + Mv::r(3) + rjust(to_string(gpu.mem_used_percent.back()), 3) + '%'; + + //? Memory utilization + if (gpu.supported_functions.mem_utilization) + out += Mv::l(b_width/2+6) + Mv::d(1) + Theme::c("div_line") + Symbols::div_left+Symbols::h_line + Theme::c("title") + "Utilization:" + Theme::c("div_line") + Symbols::h_line*(b_width/2-14) + Symbols::div_right + + Mv::l(b_width/2) + Mv::d(1) + mem_util_graph(gpu.mem_utilization_percent, (data_same or redraw[index])) + + Mv::l(b_width/2-1) + Mv::u(1) + rjust(to_string(gpu.mem_utilization_percent.back()), 3) + '%'; + + //? Memory clock speed + if (gpu.supported_functions.mem_clock and Config::getB("show_cpu_freq")) { // TODO show_gpu_freq + 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()) + + Symbols::title_left + Fx::b + Theme::c("title") + clock_speed_string + " Mhz" + Fx::ub + Theme::c("div_line") + Symbols::title_right; + } + } else { + out += Theme::c("main_fg") + Mv::r(1); + bool clock_shown = gpu.supported_functions.mem_clock and Config::getB("show_cpu_freq"); // TODO show_gpu_freq + if (gpu.supported_functions.mem_total) + out += "VRAM total:" + rjust(floating_humanizer(gpu.mem_total), b_width/(1 + clock_shown)-14); + else out += "VRAM usage:" + rjust(floating_humanizer(gpu.mem_used), b_width/(1 + clock_shown)-14); + + if (clock_shown) + out += " VRAM clock:" + rjust(to_string(gpu.mem_clock_speed) + " Mhz", b_width/2-13); + } + } //? Processes section header //out += Mv::to(b_y+8, b_x) + Theme::c("div_line") + Symbols::div_left + Symbols::h_line + Symbols::title_left + Theme::c("main_fg") + Fx::b + "gpu-proc" + Fx::ub + Theme::c("div_line") // + Symbols::title_right + Symbols::h_line*(b_width/2-12) + Symbols::div_down + Symbols::h_line*(b_width/2-2) + Symbols::div_right; //? PCIe link throughput - string tx_string = floating_humanizer(gpu.pcie_tx, 0, 1, 0, 1); - string rx_string = floating_humanizer(gpu.pcie_rx, 0, 1, 0, 1); - out += Mv::to(b_y + b_height - 1, b_x+2) + Theme::c("div_line") - + Symbols::title_left_down + Theme::c("title") + Fx::b + "TX:" + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + Symbols::h_line*(b_width/2-9-tx_string.size()) - + Symbols::title_left_down + Theme::c("title") + Fx::b + tx_string + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + Symbols::div_down - + Symbols::title_left_down + Theme::c("title") + Fx::b + "RX:" + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + Symbols::h_line*(b_width/2+b_width%2-9-rx_string.size()) - + Symbols::title_left_down + Theme::c("title") + Fx::b + rx_string + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + Symbols::round_right_down; + if (gpu.supported_functions.pcie_txrx) { + string tx_string = floating_humanizer(gpu.pcie_tx, 0, 1, 0, 1); + string rx_string = floating_humanizer(gpu.pcie_rx, 0, 1, 0, 1); + out += Mv::to(b_y + b_height_vec[index] - 1, b_x+2) + Theme::c("div_line") + + Symbols::title_left_down + Theme::c("title") + Fx::b + "TX:" + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + Symbols::h_line*(b_width/2-9-tx_string.size()) + + Symbols::title_left_down + Theme::c("title") + Fx::b + tx_string + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + (gpu.supported_functions.mem_total and gpu.supported_functions.mem_used ? Symbols::div_down : Symbols::h_line) + + Symbols::title_left_down + Theme::c("title") + Fx::b + "RX:" + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + Symbols::h_line*(b_width/2+b_width%2-9-rx_string.size()) + + Symbols::title_left_down + Theme::c("title") + Fx::b + rx_string + Fx::ub + Theme::c("div_line") + Symbols::title_right_down + Symbols::round_right_down; + } redraw[index] = false; return out + Fx::reset; @@ -1935,6 +1962,7 @@ namespace Draw { using namespace Gpu; x_vec.resize(shown); y_vec.resize(shown); b_x_vec.resize(shown); b_y_vec.resize(shown); + b_height_vec.resize(shown); box.resize(shown); graph_upper_vec.resize(shown); graph_lower_vec.resize(shown); temp_graph_vec.resize(shown); @@ -1952,14 +1980,14 @@ namespace Draw { x_vec[i] = 1; y_vec[i] = 1 + i*height + (not Config::getB("cpu_bottom"))*Cpu::shown*Cpu::height; 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 = 9; - b_width = clamp(width/2, min_width, b_height*6); + b_height_vec[i] = 2 + gpu_b_height_offsets[shown_panels[i]]; + b_width = clamp(width/2, min_width, 64); //? Main statistics box b_x_vec[i] = x_vec[i] + width - b_width - 1; - b_y_vec[i] = y_vec[i] + ceil((double)(height - 2) / 2) - ceil((double)(b_height) / 2) + 1; + b_y_vec[i] = y_vec[i] + ceil((double)(height - 2) / 2) - ceil((double)(b_height_vec[i]) / 2) + 1; - box[i] += createBox(b_x_vec[i], b_y_vec[i], b_width, b_height, "", false, gpu_names[shown_panels[i]].substr(0, b_width-5)); + box[i] += createBox(b_x_vec[i], b_y_vec[i], b_width, b_height_vec[i], "", false, gpu_names[shown_panels[i]].substr(0, b_width-5)); } } diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp index 726c337..db0c397 100644 --- a/src/btop_shared.hpp +++ b/src/btop_shared.hpp @@ -94,6 +94,7 @@ namespace Gpu { extern int shown; extern vector shown_panels; extern vector gpu_names; + extern vector gpu_b_height_offsets; extern deque average_gpu_percent; const array mem_names { "used"s, "free"s }; diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index d25f7e2..6b31a48 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -98,6 +98,7 @@ namespace Cpu { namespace Gpu { vector gpus; vector gpu_names; + vector gpu_b_height_offsets; deque average_gpu_percent = {}; //? NVIDIA data collection @@ -189,6 +190,14 @@ namespace Shared { Cpu::available_fields.push_back("gpu-average"); if (Config::strings.at("cpu_graph_lower") == "default") Config::strings.at("cpu_graph_lower") = "gpu-totals"; + + using namespace Gpu; + gpu_b_height_offsets.resize(gpus.size()); + for (ulong 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.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); } //? Init for namespace Mem @@ -1121,7 +1130,7 @@ namespace Gpu { int64_t temp_max; result = rsmi_dev_temp_metric_get(i, RSMI_TEMP_TYPE_EDGE, RSMI_TEMP_MAX, &temp_max); if (result != RSMI_STATUS_SUCCESS) - Logger::warning("ROCm SMI: Failed to get maximum GPU temperature, defaulting to 110"); + Logger::warning("ROCm SMI: Failed to get maximum GPU temperature, defaulting to 110°C"); else gpus[offset].temp_max = (long long)temp_max; } initialized = true;