diff --git a/src/btop_config.cpp b/src/btop_config.cpp index aa4d81319..ef3bfeb6b 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -306,7 +306,8 @@ namespace Config { {"proc_aggregate", false}, #ifdef GPU_SUPPORT {"nvml_measure_pcie_speeds", true}, - {"gpu_mirror_graph", true}, + {"rsmi_measure_pcie_speeds", true}, + {"gpu_mirror_graph", true} #endif }; std::unordered_map boolsTmp; @@ -320,7 +321,7 @@ namespace Config { {"selected_depth", 0}, {"proc_start", 0}, {"proc_selected", 0}, - {"proc_last_selected", 0}, + {"proc_last_selected", 0} }; std::unordered_map intsTmp; diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index 9b51bf9a0..fbeb38a74 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -537,7 +537,8 @@ namespace Cpu { #ifdef GPU_SUPPORT const auto& show_gpu_info = Config::getS("show_gpu_info"); const bool gpu_always = show_gpu_info == "On"; - bool show_gpu = (gpus.size() > 0 and (gpu_always or (show_gpu_info == "Auto" and Gpu::shown == 0))); + const bool gpu_auto = show_gpu_info == "Auto"; + const bool show_gpu = (gpus.size() > 0 and (gpu_always or (gpu_auto and Gpu::shown < Gpu::count))); #else (void)gpus; #endif @@ -576,6 +577,7 @@ namespace Cpu { graph_up_height = (single_graph ? height - 2 : ceil((double)(height - 2) / 2) - (mid_line and height % 2 != 0)); graph_low_height = height - 2 - graph_up_height - mid_line; const int button_y = cpu_bottom ? y + height - 1 : y; + lavg_str_len = 0; out += box; //? Buttons on title @@ -601,72 +603,38 @@ namespace Cpu { gpu_temp_graphs.resize(gpus.size()); gpu_mem_graphs.resize(gpus.size()); gpu_meters.resize(gpus.size()); - graph_width = graph_default_width/(int)gpus.size() - (int)gpus.size() + 1 + graph_default_width%gpus.size(); - for (unsigned long i = 0;;) { + const int gpu_draw_count = gpu_always ? Gpu::count : Gpu::count - Gpu::shown; + graph_width = gpu_draw_count <= 0 ? graph_default_width : graph_default_width/gpu_draw_count - gpu_draw_count + 1 + graph_default_width%gpu_draw_count; + for (size_t i = 0; i < gpus.size(); i++) { + if (gpu_auto and v_contains(Gpu::shown_panels, i)) + continue; auto& gpu = gpus[i]; auto& graph = graphs[i]; - //? GPU graphs/meters - if (gpu.supported_functions.temp_info) - gpu_temp_graphs[i] = Draw::Graph{ 5, 1, "temp", gpu.temp, graph_symbol, false, false, gpu.temp_max, -23 }; - if (gpu.supported_functions.mem_used and gpu.supported_functions.mem_total) - gpu_mem_graphs[i] = Draw::Graph{ 5, 1, "used", safeVal(gpu.gpu_percent, "gpu-vram-totals"s), graph_symbol }; + //? GPU graphs if (gpu.supported_functions.gpu_utilization) { - gpu_meter_width = b_width - 12 - (int)floating_humanizer(gpu.mem_total, true).size() - (show_temps ? 24 : 12) - (int)to_string(i).size() + (gpus.size() == 1)*2 - (gpus.size() > 9 and i <= 9); - gpu_meters[i] = Draw::Meter{gpu_meter_width, "cpu" }; - } - - bool utilization_support = gpu.supported_functions.gpu_utilization; - if (++i < gpus.size()) { - if (utilization_support) + if (i + 1 < gpus.size()) { graph = Draw::Graph{graph_width, graph_height, "cpu", safeVal(gpu.gpu_percent, graph_field), graph_symbol, invert, true}; - } else { - if (utilization_support) + } + else { graph = Draw::Graph{ graph_width + graph_default_width%graph_width - (int)gpus.size() + 1, graph_height, "cpu", safeVal(gpu.gpu_percent, graph_field), graph_symbol, invert, true }; - break; + } } } } else { graphs.resize(1); graph_width = graph_default_width; graphs[0] = Draw::Graph{ graph_width, graph_height, "cpu", safeVal(Gpu::shared_gpu_percent, graph_field), graph_symbol, invert, true }; - gpu_temp_graphs.resize(gpus.size()); - gpu_mem_graphs.resize(gpus.size()); - gpu_meters.resize(gpus.size()); - for (unsigned long i = 0; i < gpus.size(); ++i) { - if (gpus[i].supported_functions.temp_info) - gpu_temp_graphs[i] = Draw::Graph{ 5, 1, "temp", gpus[i].temp, graph_symbol, false, false, gpus[i].temp_max, -23 }; - if (gpus[i].supported_functions.mem_used and gpus[i].supported_functions.mem_total) - gpu_mem_graphs[i] = Draw::Graph{ 5, 1, "used", safeVal(gpus[i].gpu_percent, "gpu-vram-totals"s), graph_symbol }; - if (gpus[i].supported_functions.gpu_utilization) { - gpu_meter_width = b_width - 12 - (int)floating_humanizer(gpus[i].mem_total, true).size() - (show_temps ? 24 : 12) - (int)to_string(i).size() + (gpus.size() == 1)*2 - (gpus.size() > 9 and i <= 9); - gpu_meters[i] = Draw::Meter{gpu_meter_width, "cpu" }; - } - } } - } else { + } + else { #endif graphs.resize(1); graph_width = graph_default_width; graphs[0] = Draw::Graph{ graph_width, graph_height, "cpu", safeVal(cpu.cpu_percent, graph_field), graph_symbol, invert, true }; #ifdef GPU_SUPPORT - if (std::cmp_less(Gpu::shown, gpus.size())) { - gpu_temp_graphs.resize(gpus.size()); - gpu_mem_graphs.resize(gpus.size()); - gpu_meters.resize(gpus.size()); - for (unsigned long i = 0; i < gpus.size(); ++i) { - if (gpus[i].supported_functions.temp_info) - gpu_temp_graphs[i] = Draw::Graph{ 5, 1, "temp", gpus[i].temp, graph_symbol, false, false, gpus[i].temp_max, -23 }; - if (gpus[i].supported_functions.mem_used and gpus[i].supported_functions.mem_total) - gpu_mem_graphs[i] = Draw::Graph{ 5, 1, "used", safeVal(gpus[i].gpu_percent, "gpu-vram-totals"s), graph_symbol }; - if (gpus[i].supported_functions.gpu_utilization) { - gpu_meter_width = b_width - 12 - (int)floating_humanizer(gpus[i].mem_total, true).size() - (show_temps ? 24 : 12) - (int)to_string(i).size() + (gpus.size() == 1)*2 - (gpus.size() > 9 and i <= 9); - gpu_meters[i] = Draw::Meter{gpu_meter_width, "cpu" }; - } - } - } } #endif }; @@ -675,6 +643,37 @@ namespace Cpu { if (not single_graph) init_graphs(graphs_lower, graph_low_height, graph_low_width, graph_lo_field, Config::getB("cpu_invert_lower")); + #ifdef GPU_SUPPORT + if (show_gpu and b_columns > 1) { + gpu_temp_graphs.resize(gpus.size()); + gpu_mem_graphs.resize(gpus.size()); + gpu_meters.resize(gpus.size()); + + for (size_t i = 0; i < gpus.size(); i++) { + if (gpu_auto and v_contains(Gpu::shown_panels, i)) + continue; + auto& gpu = gpus[i]; + + //? GPU graphs/meters + auto width_left = b_width - 10 - (gpus.size() > 9 ? 2 : gpus.size() > 1 ? 1 : 0); + if (gpu.supported_functions.temp_info and show_temps) { + gpu_temp_graphs[i] = Draw::Graph{ 5, 1, "temp", gpu.temp, graph_symbol, false, false, gpu.temp_max, -23 }; + width_left -= 11; + } + if (gpu.supported_functions.mem_used and gpu.supported_functions.mem_total and b_columns > 1) { + gpu_mem_graphs[i] = Draw::Graph{ 5, 1, "used", safeVal(gpu.gpu_percent, "gpu-vram-totals"s), graph_symbol }; + width_left -= 5; + } + width_left -= (gpu.supported_functions.mem_used ? 5 : 0); + width_left -= (gpu.supported_functions.mem_total ? 6 : 0); + width_left -= (gpu.supported_functions.pwr_usage ? 5 : 0); + if (gpu.supported_functions.gpu_utilization) { + gpu_meters[i] = Draw::Meter{width_left, "cpu" }; + } + } + } + #endif + cpu_meter = Draw::Meter{b_width - (show_temps ? 23 - (b_column_size <= 1 and b_columns == 1 ? 6 : 0) : 11), "cpu"}; if (mid_line) { @@ -752,17 +751,18 @@ namespace Cpu { #ifdef GPU_SUPPORT if (graph_field.starts_with("gpu")) if (graph_field.find("totals") != string::npos) - for (unsigned long i = 0;;) { + for (size_t i = 0; i < gpus.size(); i++) { + if (gpu_auto and v_contains(Gpu::shown_panels, i)) + continue; out += graphs[i](safeVal(gpus[i].gpu_percent, graph_field), (data_same or redraw)); - if (gpus.size() > 1) { + if (Gpu::count - Gpu::shown > 1) { auto i_str = to_string(i); - out += Mv::l(graph_width-1) + Mv::u(graph_height/2) + (graph_width > 5 ? "GPU " : "") + i_str - + Mv::d(graph_height/2) + Mv::r(graph_width - 1 - (graph_width > 5)*4 - i_str.size()); + out += Mv::l(graph_width-1) + Mv::u(graph_height/2) + (graph_width > 5 ? "GPU" : "") + i_str + + Mv::d(graph_height/2) + Mv::r(graph_width - 1 - (graph_width > 5)*3 - i_str.size()); } - if (++i < graphs.size()) + if (i + 1 < graphs.size()) out += Theme::c("div_line") + (Symbols::v_line + Mv::l(1) + Mv::u(1))*graph_height + Mv::r(1) + Mv::d(1); - else break; } else out += graphs[0](safeVal(Gpu::shared_gpu_percent, graph_field), (data_same or redraw)); @@ -845,23 +845,15 @@ namespace Cpu { if (cy < b_height - 1 and cc <= b_columns) { string lavg_pre; int sep = 1; - if (b_column_size == 2 and show_temps) { lavg_pre = "Load AVG:"; sep = 3; } + if (b_column_size == 2 and show_temps) { lavg_pre = "Load AVG: "; sep = 3; } else if (b_column_size == 2 or (b_column_size == 1 and show_temps)) { lavg_pre = "LAV:"; } - else if (b_column_size == 1 or (b_column_size == 0 and show_temps)) { lavg_pre = "L"; } + else if (b_column_size == 1 or (b_column_size == 0 and show_temps)) { lavg_pre = "L "; } string lavg; for (const auto& val : cpu.load_avg) { lavg += string(sep, ' ') + (lavg_pre.size() < 3 ? to_string((int)round(val)) : to_string(val).substr(0, 4)); } string lavg_str = lavg_pre + lavg; - // if previous load average string is longer than current - // then right pad the current string with spaces until - // the current string is the same length as the previous - // otherwise set the lavg_str_len. - // - // When a shorter string gets written, the remaining characters - // from the previous string get left behind. This "erases" the - // leftover characters from the previous string. if (lavg_str_len > lavg_str.length()) { lavg_str += string(lavg_str_len - lavg_str.length(), ' '); } else { @@ -879,37 +871,45 @@ namespace Cpu { //? Gpu brief info if (show_gpu) { for (unsigned long i = 0; i < gpus.size(); ++i) { - if (gpu_always or not v_contains(Gpu::shown_panels, i)) { - out += Mv::to(b_y + ++cy, b_x + 1) + Theme::c("main_fg") + Fx::b + "GPU"; - if (show_temps and gpus[i].supported_functions.temp_info and b_width < 34) { - const auto [temp, unit] = celsius_to(gpus[i].temp.back(), temp_scale); - if (temp < 100) out += " "; - } - if (gpus.size() > 1) out += rjust(to_string(i), 1 + (gpus.size() > 9)); - if (gpus[i].supported_functions.gpu_utilization) { - string meter = gpu_meters[i](safeVal(gpus[i].gpu_percent, "gpu-totals"s).back()); - out += (meter.size() > 1 ? " " : "") + meter - + Theme::g("cpu").at(clamp(safeVal(gpus[i].gpu_percent, "gpu-totals"s).back(), 0ll, 100ll)) + rjust(to_string(safeVal(gpus[i].gpu_percent, "gpu-totals"s).back()), 4) + Theme::c("main_fg") + '%'; - } else out += Mv::r(gpu_meter_width); - - if (gpus[i].supported_functions.mem_used) { - out += ' ' + Theme::c("inactive_fg") + graph_bg * 6 + Mv::l(6) + Theme::g("used").at(safeVal(gpus[i].gpu_percent, "gpu-vram-totals"s).back()) - + gpu_mem_graphs[i](safeVal(gpus[i].gpu_percent, "gpu-vram-totals"s), data_same or redraw) + Theme::c("main_fg") - + rjust(floating_humanizer(gpus[i].mem_used, true), 5); - if (gpus[i].supported_functions.mem_total) - out += Theme::c("inactive_fg") + '/' + Theme::c("main_fg") + floating_humanizer(gpus[i].mem_total, true); - else out += Mv::r(5); - } else out += Mv::r(17); - if (show_temps and gpus[i].supported_functions.temp_info) { - const auto [temp, unit] = celsius_to(gpus[i].temp.back(), temp_scale); - if (b_width > 38) - out += ' ' + Theme::c("inactive_fg") + graph_bg * 6 + Mv::l(6) + Theme::g("temp").at(clamp(gpus[i].temp.back() * 100 / gpus[i].temp_max, 0ll, 100ll)) - + gpu_temp_graphs[i](gpus[i].temp, data_same or redraw); - else out += Theme::g("temp").at(clamp(gpus[i].temp.back() * 100 / gpus[i].temp_max, 0ll, 100ll)); - out += rjust(to_string(temp), 3 + (b_width >= 34 or temp > 99)) + Theme::c("main_fg") + unit; + if (gpu_auto and v_contains(Gpu::shown_panels, i)) + continue; + out += Mv::to(b_y + ++cy, b_x + 1) + Theme::c("main_fg") + Fx::b + "GPU"; + if (gpus.size() > 1) out += rjust(to_string(i), 1 + (gpus.size() > 9)); + if (gpus[i].supported_functions.gpu_utilization) { + out += ' '; + if (b_columns > 1) { + out += gpu_meters[i](safeVal(gpus[i].gpu_percent, "gpu-totals"s).back()) + + Theme::g("cpu").at(clamp(safeVal(gpus[i].gpu_percent, "gpu-totals"s).back(), 0ll, 100ll)); } + out += rjust(to_string(safeVal(gpus[i].gpu_percent, "gpu-totals"s).back()), 3) + Theme::c("main_fg") + '%'; + if (b_columns == 1) + out += ' '; + } + if (gpus[i].supported_functions.mem_used and gpus[i].supported_functions.mem_total and b_columns > 1) { + out += ' ' + Theme::c("inactive_fg") + graph_bg * 5 + Mv::l(5) + Theme::g("used").at(safeVal(gpus[i].gpu_percent, "gpu-vram-totals"s).back()) + + gpu_mem_graphs[i](safeVal(gpus[i].gpu_percent, "gpu-vram-totals"s), data_same or redraw); } - if (cy < b_height - 1) break; + if (gpus[i].supported_functions.mem_used) { + out += Theme::c("main_fg") + + rjust(floating_humanizer(gpus[i].mem_used, true), 5); + } + if (gpus[i].supported_functions.mem_total) { + out += Theme::c("inactive_fg") + '/' + Theme::c("main_fg") + ljust(floating_humanizer(gpus[i].mem_total, true), 4); + } + if (show_temps and gpus[i].supported_functions.temp_info) { + const auto [temp, unit] = celsius_to(gpus[i].temp.back(), temp_scale); + out += ' '; + if (b_columns > 1) + out += Theme::c("inactive_fg") + graph_bg * 5 + Mv::l(5) + Theme::g("temp").at(clamp(gpus[i].temp.back() * 100 / gpus[i].temp_max, 0ll, 100ll)) + + gpu_temp_graphs[i](gpus[i].temp, data_same or redraw); + else out += Theme::g("temp").at(clamp(gpus[i].temp.back() * 100 / gpus[i].temp_max, 0ll, 100ll)); + out += rjust(to_string(temp), 3) + Theme::c("main_fg") + unit; + } + if (gpus[i].supported_functions.pwr_usage) { + out += ' ' + Theme::g("cached").at(clamp(safeVal(gpus[i].gpu_percent, "gpu-pwr-totals"s).back(), 0ll, 100ll)) + rjust(to_string(gpus[i].pwr_usage/1000), 3) + Theme::c("main_fg") + 'W'; + } + + if (cy > b_height - 1) break; } } #endif @@ -930,7 +930,8 @@ namespace Gpu { vector b_x_vec = {}, b_y_vec = {}; vector redraw = {}; int shown = 0; - vector shown_panels = {}; + int count = 0; + vector shown_panels = {}; int graph_up_height; vector graph_upper_vec = {}, graph_lower_vec = {}; vector temp_graph_vec = {}; @@ -987,7 +988,7 @@ namespace Gpu { 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"}; + pwr_meter = Draw::Meter{b_width - (gpu.supported_functions.pwr_state and gpu.pwr_state != 32 ? 24 : 11), "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) @@ -1990,19 +1991,16 @@ namespace Draw { Gpu::box.clear(); Gpu::width = 0; Gpu::shown_panels.clear(); - if (not Gpu::gpu_names.empty()) { + if (Gpu::count > 0) { std::istringstream iss(boxes, std::istringstream::in); string current; - while (iss >> current) - if ( current == "gpu0" - or current == "gpu1" - or current == "gpu2" - or current == "gpu3" - or current == "gpu4" - or current == "gpu5" - ) Gpu::shown_panels.push_back(current.back()-'0'); + while (iss >> current) { + if (current.starts_with("gpu")) + Gpu::shown_panels.push_back(current.back()-'0'); + } } Gpu::shown = Gpu::shown_panels.size(); + #endif Mem::shown = s_contains(boxes, "mem"); Net::shown = s_contains(boxes, "net"); @@ -2012,23 +2010,20 @@ namespace Draw { if (Cpu::shown) { using namespace Cpu; #ifdef GPU_SUPPORT - const bool show_gpu_on = Config::getS("show_gpu_info") == "On"; - const bool gpus_shown_in_cpu_panel = Gpu::gpu_names.size() > 0 and ( - show_gpu_on or (Config::getS("show_gpu_info") == "Auto" and Gpu::shown == 0) - ); - const int gpus_height_offset = (Gpu::gpu_names.size() - Gpu::shown)*gpus_shown_in_cpu_panel; - int gpus_extra_height = gpus_shown_in_cpu_panel ? Gpu::gpu_names.size() - (show_gpu_on ? 0 : Gpu::shown) : 0; + int gpus_extra_height = + Config::getS("show_gpu_info") == "On" ? Gpu::count + : Config::getS("show_gpu_info") == "Auto" ? Gpu::count - Gpu::shown + : 0; #endif const bool show_temp = (Config::getB("check_temp") and got_sensors); width = round((double)Term::width * width_p / 100); #ifdef GPU_SUPPORT if (Gpu::shown != 0 and not (Mem::shown or Net::shown or Proc::shown)) { - height = Term::height - Gpu::min_height*Gpu::shown - gpus_height_offset; + height = Term::height - Gpu::min_height*Gpu::shown - gpus_extra_height; } else { height = max(8, (int)ceil((double)Term::height * (trim(boxes) == "cpu" ? 100 : height_p/(Gpu::shown+1) + (Gpu::shown != 0)*5) / 100)); } - if (height <= Term::height-gpus_height_offset) height += gpus_height_offset; - if (height - gpus_extra_height < 7) gpus_extra_height = height - 7; + if (height <= Term::height-gpus_extra_height) height += gpus_extra_height; #else height = max(8, (int)ceil((double)Term::height * (trim(boxes) == "cpu" ? 100 : height_p) / 100)); #endif @@ -2036,7 +2031,7 @@ namespace Draw { y = cpu_bottom ? Term::height - height + 1 : 1; #ifdef GPU_SUPPORT - b_columns = max(1, (int)ceil((double)(Shared::coreCount + 1) / (height - gpus_extra_height - 5))); + b_columns = max(2, (int)ceil((double)(Shared::coreCount + 1) / (height - gpus_extra_height - 5))); #else b_columns = max(1, (int)ceil((double)(Shared::coreCount + 1) / (height - 5))); #endif @@ -2058,6 +2053,7 @@ namespace Draw { if (b_column_size == 0) b_width = (8 + 6 * show_temp) * b_columns + 1; #ifdef GPU_SUPPORT + //gpus_extra_height = max(0, gpus_extra_height - 1); b_height = min(height - 2, (int)ceil((double)Shared::coreCount / b_columns) + 4 + gpus_extra_height); #else b_height = min(height - 2, (int)ceil((double)Shared::coreCount / b_columns) + 4); diff --git a/src/btop_menu.cpp b/src/btop_menu.cpp index be5f8c1d7..488886a5f 100644 --- a/src/btop_menu.cpp +++ b/src/btop_menu.cpp @@ -517,6 +517,12 @@ namespace Menu { "May impact performance on certain cards.", "", "True or False."}, + {"rsmi_measure_pcie_speeds", + "Measure PCIe throughput on AMD cards.", + "", + "May impact performance on certain cards.", + "", + "True or False."}, {"graph_symbol_gpu", "Graph symbol to use for graphs in gpu box.", "", diff --git a/src/btop_shared.cpp b/src/btop_shared.cpp index f4d86c95b..1b8e526ab 100644 --- a/src/btop_shared.cpp +++ b/src/btop_shared.cpp @@ -36,7 +36,7 @@ namespace Gpu { {"gpu-vram-total", {}}, {"gpu-pwr-total", {}}, }; - long long gpu_pwr_total_max; + long long gpu_pwr_total_max = 0; } #endif diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp index f1f974ed4..0cf08eb44 100644 --- a/src/btop_shared.hpp +++ b/src/btop_shared.hpp @@ -111,7 +111,8 @@ namespace Gpu { extern vector x_vec, y_vec; extern vector redraw; extern int shown; - extern vector shown_panels; + extern int count; + extern vector shown_panels; extern vector gpu_names; extern vector gpu_b_height_offsets; extern long long gpu_pwr_total_max; diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 7ddedd474..c3592d5bb 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -305,6 +305,7 @@ namespace Shared { Cpu::available_fields.push_back(key); using namespace Gpu; + count = gpus.size(); gpu_b_height_offsets.resize(gpus.size()); for (size_t i = 0; i < gpu_b_height_offsets.size(); ++i) gpu_b_height_offsets[i] = gpus[i].supported_functions.gpu_utilization @@ -1575,7 +1576,7 @@ namespace Gpu { } //? PCIe link speeds - if (gpus_slice[i].supported_functions.pcie_txrx) { + if (gpus_slice[i].supported_functions.pcie_txrx and Config::getB("rsmi_measure_pcie_speeds")) { uint64_t tx, rx; result = rsmi_dev_pci_throughput_get(i, &tx, &rx, 0); if (result != RSMI_STATUS_SUCCESS) { @@ -1756,6 +1757,8 @@ namespace Gpu { while (cmp_greater(shared_gpu_percent.at("gpu-vram-total").size(), width * 2)) shared_gpu_percent.at("gpu-vram-total").pop_front(); } + count = gpus.size(); + return gpus; } }