diff options
author | Jakob P. Liljenberg <admin@qvantnet.com> | 2024-01-03 16:34:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-03 16:34:01 +0100 |
commit | ef788efc536733a441949dab854b0a6bea5ef33e (patch) | |
tree | 4a27a7212369425705973fc29f9c8feff00b00ba /src | |
parent | c90e3f9b1508f55d281495468297df409f974eb0 (diff) | |
parent | a29545c4079e9bc5203e09965ac03fabe975bd7e (diff) |
Merge branch 'main' into lldb-term-size
Diffstat (limited to 'src')
-rw-r--r-- | src/btop.cpp | 117 | ||||
-rw-r--r-- | src/btop_config.cpp | 71 | ||||
-rw-r--r-- | src/btop_config.hpp | 26 | ||||
-rw-r--r-- | src/btop_draw.cpp | 659 | ||||
-rw-r--r-- | src/btop_draw.hpp | 9 | ||||
-rw-r--r-- | src/btop_input.cpp | 33 | ||||
-rw-r--r-- | src/btop_input.hpp | 5 | ||||
-rw-r--r-- | src/btop_menu.cpp | 126 | ||||
-rw-r--r-- | src/btop_menu.hpp | 2 | ||||
-rw-r--r-- | src/btop_shared.cpp | 12 | ||||
-rw-r--r-- | src/btop_shared.hpp | 114 | ||||
-rw-r--r-- | src/btop_theme.cpp | 14 | ||||
-rw-r--r-- | src/btop_theme.hpp | 9 | ||||
-rw-r--r-- | src/btop_tools.cpp | 99 | ||||
-rw-r--r-- | src/btop_tools.hpp | 132 | ||||
-rw-r--r-- | src/freebsd/btop_collect.cpp | 35 | ||||
-rw-r--r-- | src/linux/btop_collect.cpp | 774 | ||||
-rw-r--r-- | src/openbsd/btop_collect.cpp | 1295 | ||||
-rw-r--r-- | src/openbsd/internal.h | 157 | ||||
-rw-r--r-- | src/openbsd/sysctlbyname.cpp | 46 | ||||
-rw-r--r-- | src/openbsd/sysctlbyname.h | 20 | ||||
-rw-r--r-- | src/osx/btop_collect.cpp | 38 | ||||
-rw-r--r-- | src/osx/sensors.cpp | 3 | ||||
-rw-r--r-- | src/osx/sensors.hpp | 3 |
24 files changed, 3511 insertions, 288 deletions
diff --git a/src/btop.cpp b/src/btop.cpp index e53ec02..48d0482 100644 --- a/src/btop.cpp +++ b/src/btop.cpp @@ -32,6 +32,7 @@ tab-size = 4 #include <tuple> #include <regex> #include <chrono> +#include <utility> #ifdef __APPLE__ #include <CoreFoundation/CoreFoundation.h> #include <mach-o/dyld.h> @@ -75,7 +76,7 @@ namespace Global { {"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"}, {"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"}, }; - const string Version = "1.2.13"; + const string Version = "1.3.0"; int coreCount; string overlay; @@ -183,8 +184,11 @@ void term_resize(bool force) { if (force and refreshed) force = false; } else return; - - static const array<string, 4> all_boxes = {"cpu", "mem", "net", "proc"}; +#ifdef GPU_SUPPORT + static const array<string, 10> all_boxes = {"gpu5", "cpu", "mem", "net", "proc", "gpu0", "gpu1", "gpu2", "gpu3", "gpu4"}; +#else + static const array<string, 5> all_boxes = {"", "cpu", "mem", "net", "proc"}; +#endif Global::resized = true; if (Runner::active) Runner::stop(); Term::refresh(); @@ -222,10 +226,18 @@ void term_resize(bool force) { auto key = Input::get(); if (key == "q") clean_quit(0); - else if (is_in(key, "1", "2", "3", "4")) { - Config::current_preset = -1; - Config::toggle_box(all_boxes.at(std::stoi(key) - 1)); - boxes = Config::getS("shown_boxes"); + else if (key.size() == 1 and isint(key)) { + auto intKey = stoi(key); + #ifdef GPU_SUPPORT + if ((intKey == 0 and Gpu::gpu_names.size() >= 5) or (intKey >= 5 and std::cmp_greater_equal(Gpu::gpu_names.size(), intKey - 4))) { + #else + if (intKey > 0 and intKey < 5) { + #endif + auto box = all_boxes.at(intKey); + Config::current_preset = -1; + Config::toggle_box(box); + boxes = Config::getS("shown_boxes"); + } } } min_size = Term::get_min_size(boxes); @@ -243,7 +255,7 @@ void clean_quit(int sig) { Global::quitting = true; Runner::stop(); if (Global::_runner_started) { - #ifdef __APPLE__ + #if defined __APPLE__ || defined __OpenBSD__ if (pthread_join(Runner::runner_id, nullptr) != 0) { Logger::warning("Failed to join _runner thread on exit!"); pthread_cancel(Runner::runner_id); @@ -258,6 +270,11 @@ void clean_quit(int sig) { #endif } +#ifdef GPU_SUPPORT + Gpu::Nvml::shutdown(); + Gpu::Rsmi::shutdown(); +#endif + Config::write(); if (Term::initialized) { @@ -274,7 +291,7 @@ void clean_quit(int sig) { const auto excode = (sig != -1 ? sig : 0); -#ifdef __APPLE__ +#if defined __APPLE__ || defined __OpenBSD__ _Exit(excode); #else quick_exit(excode); @@ -388,7 +405,9 @@ namespace Runner { enum debug_actions { collect_begin, + collect_done, draw_begin, + draw_begin_only, draw_done }; @@ -398,7 +417,7 @@ namespace Runner { }; string debug_bg; - unordered_flat_map<string, array<uint64_t, 2>> debug_times; + std::unordered_map<string, array<uint64_t, 2>> debug_times; class MyNumPunct : public std::numpunct<char> { @@ -424,6 +443,13 @@ namespace Runner { case collect_begin: debug_times[name].at(collect) = time_micros(); return; + case collect_done: + debug_times[name].at(collect) = time_micros() - debug_times[name].at(collect); + debug_times["total"].at(collect) += debug_times[name].at(collect); + return; + case draw_begin_only: + debug_times[name].at(draw) = time_micros(); + return; case draw_begin: debug_times[name].at(draw) = time_micros(); debug_times[name].at(collect) = debug_times[name].at(draw) - debug_times[name].at(collect); @@ -480,10 +506,14 @@ namespace Runner { //! DEBUG stats if (Global::debug) { - if (debug_bg.empty() or redraw) - Runner::debug_bg = Draw::createBox(2, 2, 33, 8, "", true, "μs"); - - + if (debug_bg.empty() or redraw) + Runner::debug_bg = Draw::createBox(2, 2, 33, + #ifdef GPU_SUPPORT + 9, + #else + 8, + #endif + "", true, "μs"); debug_times.clear(); debug_times["total"] = {0, 0}; @@ -493,6 +523,29 @@ namespace Runner { //* Run collection and draw functions for all boxes try { + #ifdef GPU_SUPPORT + //? GPU data collection + const bool gpu_in_cpu_panel = Gpu::gpu_names.size() > 0 and ( + Config::getS("cpu_graph_lower").starts_with("gpu-") or Config::getS("cpu_graph_upper").starts_with("gpu-") + or (Gpu::shown == 0 and Config::getS("show_gpu_info") != "Off") + ); + + vector<unsigned int> gpu_panels = {}; + for (auto& box : conf.boxes) + if (box.starts_with("gpu")) + gpu_panels.push_back(box.back()-'0'); + + vector<Gpu::gpu_info> gpus; + if (gpu_in_cpu_panel or not gpu_panels.empty()) { + if (Global::debug) debug_timer("gpu", collect_begin); + gpus = Gpu::collect(conf.no_update); + if (Global::debug) debug_timer("gpu", collect_done); + } + auto& gpus_ref = gpus; + #else + vector<Gpu::gpu_info> gpus_ref{}; + #endif + //? CPU if (v_contains(conf.boxes, "cpu")) { try { @@ -512,7 +565,7 @@ namespace Runner { if (Global::debug) debug_timer("cpu", draw_begin); //? Draw box - if (not pause_output) output += Cpu::draw(cpu, conf.force_redraw, conf.no_update); + if (not pause_output) output += Cpu::draw(cpu, gpus_ref, conf.force_redraw, conf.no_update); if (Global::debug) debug_timer("cpu", draw_done); } @@ -520,7 +573,24 @@ namespace Runner { throw std::runtime_error("Cpu:: -> " + string{e.what()}); } } + #ifdef GPU_SUPPORT + //? GPU + if (not gpu_panels.empty() and not gpus_ref.empty()) { + try { + if (Global::debug) debug_timer("gpu", draw_begin_only); + + //? Draw box + if (not pause_output) + for (unsigned long i = 0; i < gpu_panels.size(); ++i) + output += Gpu::draw(gpus_ref[gpu_panels[i]], i, conf.force_redraw, conf.no_update); + if (Global::debug) debug_timer("gpu", draw_done); + } + catch (const std::exception& e) { + throw std::runtime_error("Gpu:: -> " + string{e.what()}); + } + } + #endif //? MEM if (v_contains(conf.boxes, "mem")) { try { @@ -580,6 +650,7 @@ namespace Runner { throw std::runtime_error("Proc:: -> " + string{e.what()}); } } + } catch (const std::exception& e) { Global::exit_error_msg = "Exception in runner thread -> " + string{e.what()}; @@ -610,8 +681,9 @@ namespace Runner { "{mv3}{hiFg}2 {mainFg}| Show MEM box" "{mv4}{hiFg}3 {mainFg}| Show NET box" "{mv5}{hiFg}4 {mainFg}| Show PROC box" - "{mv6}{hiFg}esc {mainFg}| Show menu" - "{mv7}{hiFg}q {mainFg}| Quit", + "{mv6}{hiFg}5-0 {mainFg}| Show GPU boxes" + "{mv7}{hiFg}esc {mainFg}| Show menu" + "{mv8}{hiFg}q {mainFg}| Quit", "banner"_a = Draw::banner_gen(y, 0, true), "titleFg"_a = Theme::c("title"), "b"_a = Fx::b, "hiFg"_a = Theme::c("hi_fg"), "mainFg"_a = Theme::c("main_fg"), "mv1"_a = Mv::to(y+6, x), @@ -620,7 +692,8 @@ namespace Runner { "mv4"_a = Mv::to(y+10, x), "mv5"_a = Mv::to(y+11, x), "mv6"_a = Mv::to(y+12, x-2), - "mv7"_a = Mv::to(y+13, x) + "mv7"_a = Mv::to(y+13, x-2), + "mv8"_a = Mv::to(y+14, x) ); } output += empty_bg; @@ -634,7 +707,11 @@ namespace Runner { "post"_a = Theme::c("main_fg") + Fx::ub ); static auto loc = std::locale(std::locale::classic(), new MyNumPunct); + #ifdef GPU_SUPPORT + for (const string name : {"cpu", "mem", "net", "proc", "gpu", "total"}) { + #else for (const string name : {"cpu", "mem", "net", "proc", "total"}) { + #endif if (not debug_times.contains(name)) debug_times[name] = {0,0}; const auto& [time_collect, time_draw] = debug_times.at(name); if (name == "total") output += Fx::b; @@ -854,7 +931,7 @@ int main(int argc, char **argv) { catch (...) { found.clear(); } } } - + // #ifdef __APPLE__ if (found.empty()) { CFLocaleRef cflocale = CFLocaleCopyCurrent(); @@ -898,7 +975,7 @@ int main(int argc, char **argv) { Config::set("tty_mode", true); Logger::info("Forcing tty mode: setting 16 color mode and using tty friendly graph symbols"); } -#ifndef __APPLE__ +#if not defined __APPLE__ && not defined __OpenBSD__ else if (not Global::arg_tty and Term::current_tty.starts_with("/dev/tty")) { Config::set("tty_mode", true); Logger::info("Real tty detected: setting 16 color mode and using tty friendly graph symbols"); diff --git a/src/btop_config.cpp b/src/btop_config.cpp index fc71e41..6ddfd43 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -21,6 +21,7 @@ tab-size = 4 #include <fstream> #include <ranges> #include <string_view> +#include <utility> #include <fmt/core.h> @@ -73,14 +74,16 @@ namespace Config { "#* Note that \"tty\" only has half the horizontal resolution of the other two, so will show a shorter historical view."}, {"graph_symbol_cpu", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."}, - +#ifdef GPU_SUPPORT + {"graph_symbol_gpu", "# Graph symbol to use for graphs in gpu box, \"default\", \"braille\", \"block\" or \"tty\"."}, +#endif {"graph_symbol_mem", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."}, {"graph_symbol_net", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."}, {"graph_symbol_proc", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."}, - {"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\", separate values with whitespace."}, + {"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\" and \"gpu0\" through \"gpu5\", separate values with whitespace."}, {"update_ms", "#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs."}, @@ -114,7 +117,9 @@ namespace Config { {"cpu_graph_lower", "#* Sets the CPU stat shown in lower half of the CPU graph, \"total\" is always available.\n" "#* Select from a list of detected attributes from the options menu."}, - + #ifdef GPU_SUPPORT + {"show_gpu_info", "#* If gpu info should be shown in the cpu box. Available values = \"Auto\", \"On\" and \"Off\"."}, + #endif {"cpu_invert_lower", "#* Toggles if the lower CPU graph should be inverted."}, {"cpu_single_graph", "#* Set to True to completely disable the lower CPU graph."}, @@ -194,21 +199,36 @@ namespace Config { {"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."}, {"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n" - "#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."} + "#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."}, + #ifdef GPU_SUPPORT + + {"nvml_measure_pcie_speeds", + "#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards."}, + + {"gpu_mirror_graph", "#* Horizontally mirror the GPU graph."}, + + {"custom_gpu_name0", "#* Custom gpu0 model name, empty string to disable."}, + {"custom_gpu_name1", "#* Custom gpu1 model name, empty string to disable."}, + {"custom_gpu_name2", "#* Custom gpu2 model name, empty string to disable."}, + {"custom_gpu_name3", "#* Custom gpu3 model name, empty string to disable."}, + {"custom_gpu_name4", "#* Custom gpu4 model name, empty string to disable."}, + {"custom_gpu_name5", "#* Custom gpu5 model name, empty string to disable."}, + #endif }; - unordered_flat_map<std::string_view, string> strings = { + std::unordered_map<std::string_view, string> strings = { {"color_theme", "Default"}, {"shown_boxes", "cpu mem net proc"}, {"graph_symbol", "braille"}, {"presets", "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty"}, {"graph_symbol_cpu", "default"}, + {"graph_symbol_gpu", "default"}, {"graph_symbol_mem", "default"}, {"graph_symbol_net", "default"}, {"graph_symbol_proc", "default"}, {"proc_sorting", "cpu lazy"}, - {"cpu_graph_upper", "total"}, - {"cpu_graph_lower", "total"}, + {"cpu_graph_upper", "Auto"}, + {"cpu_graph_lower", "Auto"}, {"cpu_sensor", "Auto"}, {"selected_battery", "Auto"}, {"cpu_core_map", ""}, @@ -222,10 +242,19 @@ namespace Config { {"proc_filter", ""}, {"proc_command", ""}, {"selected_name", ""}, + #ifdef GPU_SUPPORT + {"custom_gpu_name0", ""}, + {"custom_gpu_name1", ""}, + {"custom_gpu_name2", ""}, + {"custom_gpu_name3", ""}, + {"custom_gpu_name4", ""}, + {"custom_gpu_name5", ""}, + {"show_gpu_info", "Auto"} + #endif }; - unordered_flat_map<std::string_view, string> stringsTmp; + std::unordered_map<std::string_view, string> stringsTmp; - unordered_flat_map<std::string_view, bool> bools = { + std::unordered_map<std::string_view, bool> bools = { {"theme_background", true}, {"truecolor", true}, {"rounded_corners", true}, @@ -271,10 +300,14 @@ namespace Config { {"show_detailed", false}, {"proc_filtering", false}, {"proc_aggregate", false}, + #ifdef GPU_SUPPORT + {"nvml_measure_pcie_speeds", true}, + {"gpu_mirror_graph", true}, + #endif }; - unordered_flat_map<std::string_view, bool> boolsTmp; + std::unordered_map<std::string_view, bool> boolsTmp; - unordered_flat_map<std::string_view, int> ints = { + std::unordered_map<std::string_view, int> ints = { {"update_ms", 2000}, {"net_download", 100}, {"net_upload", 100}, @@ -285,7 +318,7 @@ namespace Config { {"proc_selected", 0}, {"proc_last_selected", 0}, }; - unordered_flat_map<std::string_view, int> intsTmp; + std::unordered_map<std::string_view, int> intsTmp; bool _locked(const std::string_view name) { atomic_wait(writelock, true); @@ -321,7 +354,7 @@ namespace Config { validError = "Malformatted preset in config value presets!"; return false; } - if (not is_in(vals.at(0), "cpu", "mem", "net", "proc")) { + if (not is_in(vals.at(0), "cpu", "mem", "net", "proc", "gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5")) { validError = "Invalid box name in config value presets!"; return false; } @@ -417,6 +450,11 @@ namespace Config { else if (name == "shown_boxes" and not value.empty() and not check_boxes(value)) validError = "Invalid box name(s) in shown_boxes!"; + #ifdef GPU_SUPPORT + else if (name == "show_gpu_info" and not v_contains(show_gpu_values, value)) + validError = "Invalid value for show_gpu_info: " + value; + #endif + else if (name == "presets" and not presetsValid(value)) return false; @@ -519,6 +557,13 @@ namespace Config { auto new_boxes = ssplit(boxes); for (auto& box : new_boxes) { if (not v_contains(valid_boxes, box)) return false; + #ifdef GPU_SUPPORT + if (box.starts_with("gpu")) { + size_t gpu_num = stoi(box.substr(3)); + if (gpu_num == 0) gpu_num = 5; + if (std::cmp_greater(gpu_num, Gpu::gpu_names.size())) return false; + } + #endif } current_boxes = std::move(new_boxes); return true; diff --git a/src/btop_config.hpp b/src/btop_config.hpp index e5f4ac1..2b586af 100644 --- a/src/btop_config.hpp +++ b/src/btop_config.hpp @@ -22,11 +22,10 @@ tab-size = 4 #include <vector> #include <filesystem> -#include <robin_hood.h> +#include <unordered_map> using std::string; using std::vector; -using robin_hood::unordered_flat_map; //* Functions and variables for reading and writing the btop config file namespace Config { @@ -34,18 +33,25 @@ namespace Config { extern std::filesystem::path conf_dir; extern std::filesystem::path conf_file; - extern unordered_flat_map<std::string_view, string> strings; - extern unordered_flat_map<std::string_view, string> stringsTmp; - extern unordered_flat_map<std::string_view, bool> bools; - extern unordered_flat_map<std::string_view, bool> boolsTmp; - extern unordered_flat_map<std::string_view, int> ints; - extern unordered_flat_map<std::string_view, int> intsTmp; + extern std::unordered_map<std::string_view, string> strings; + extern std::unordered_map<std::string_view, string> stringsTmp; + extern std::unordered_map<std::string_view, bool> bools; + extern std::unordered_map<std::string_view, bool> boolsTmp; + extern std::unordered_map<std::string_view, int> ints; + extern std::unordered_map<std::string_view, int> intsTmp; const vector<string> valid_graph_symbols = { "braille", "block", "tty" }; const vector<string> valid_graph_symbols_def = { "default", "braille", "block", "tty" }; - const vector<string> valid_boxes = { "cpu", "mem", "net", "proc" }; + const vector<string> valid_boxes = { + "cpu", "mem", "net", "proc" +#ifdef GPU_SUPPORT + ,"gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5" +#endif + }; const vector<string> temp_scales = { "celsius", "fahrenheit", "kelvin", "rankine" }; - +#ifdef GPU_SUPPORT + const vector<string> show_gpu_values = { "Auto", "On", "Off" }; +#endif extern vector<string> current_boxes; extern vector<string> preset_list; extern vector<string> available_batteries; diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index b7ddc74..0ceaa2f 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -20,7 +20,9 @@ tab-size = 4 #include <algorithm> #include <cmath> #include <ranges> +#include <stdexcept> #include <string> +#include <utility> #include "btop_draw.hpp" #include "btop_config.hpp" @@ -30,6 +32,7 @@ tab-size = 4 #include "btop_input.hpp" #include "btop_menu.hpp" + using std::array; using std::clamp; using std::cmp_equal; @@ -52,7 +55,7 @@ namespace Symbols { const array<string, 10> superscript = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" }; - const unordered_flat_map<string, vector<string>> graph_symbols = { + const std::unordered_map<string, vector<string>> graph_symbols = { { "braille_up", { " ", "⢀", "⢠", "⢰", "⢸", "⡀", "⣀", "⣠", "⣰", "⣸", @@ -298,7 +301,7 @@ namespace Draw { return false; } - static const unordered_flat_map<string, string> clock_custom_format = { + static const std::unordered_map<string, string> clock_custom_format = { {"/user", Tools::username()}, {"/host", Tools::hostname()}, {"/uptime", ""} @@ -509,44 +512,69 @@ namespace Cpu { int x = 1, y = 1, width = 20, height; int b_columns, b_column_size; int b_x, b_y, b_width, b_height; - int graph_up_height; long unsigned int lavg_str_len = 0; + int graph_up_height, graph_low_height; + int graph_up_width, graph_low_width; + int gpu_meter_width; bool shown = true, redraw = true, mid_line = false; string box; - Draw::Graph graph_upper; - Draw::Graph graph_lower; + vector<Draw::Graph> graphs_upper; + vector<Draw::Graph> graphs_lower; Draw::Meter cpu_meter; + vector<Draw::Meter> gpu_meters; vector<Draw::Graph> core_graphs; vector<Draw::Graph> temp_graphs; + vector<Draw::Graph> gpu_temp_graphs; + vector<Draw::Graph> gpu_mem_graphs; - string draw(const cpu_info& cpu, bool force_redraw, bool data_same) { + string draw(const cpu_info& cpu, const vector<Gpu::gpu_info>& gpus, bool force_redraw, bool data_same) { if (Runner::stopping) return ""; if (force_redraw) redraw = true; bool show_temps = (Config::getB("check_temp") and got_sensors); auto single_graph = Config::getB("cpu_single_graph"); bool hide_cores = show_temps and (cpu_temp_only or not Config::getB("show_coretemp")); const int extra_width = (hide_cores ? max(6, 6 * b_column_size) : 0); - auto& graph_up_field = Config::getS("cpu_graph_upper"); - auto& graph_lo_field = Config::getS("cpu_graph_lower"); + #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))); + #else + (void)gpus; + #endif + auto graph_up_field = Config::getS("cpu_graph_upper"); + if (graph_up_field == "Auto" or not v_contains(Cpu::available_fields, graph_up_field)) + graph_up_field = "total"; + auto graph_lo_field = Config::getS("cpu_graph_lower"); + if (graph_lo_field == "Auto" or not v_contains(Cpu::available_fields, graph_lo_field)) { + #ifdef GPU_SUPPORT + graph_lo_field = show_gpu ? "gpu-totals" : graph_up_field; + #else + graph_lo_field = graph_up_field; + #endif + } auto tty_mode = Config::getB("tty_mode"); auto& graph_symbol = (tty_mode ? "tty" : Config::getS("graph_symbol_cpu")); auto& graph_bg = Symbols::graph_symbols.at((graph_symbol == "default" ? Config::getS("graph_symbol") + "_up" : graph_symbol + "_up")).at(6); auto& temp_scale = Config::getS("temp_scale"); auto cpu_bottom = Config::getB("cpu_bottom"); + const string& title_left = Theme::c("cpu_box") + (cpu_bottom ? Symbols::title_left_down : Symbols::title_left); const string& title_right = Theme::c("cpu_box") + (cpu_bottom ? Symbols::title_right_down : Symbols::title_right); static int bat_pos = 0, bat_len = 0; - if (cpu.cpu_percent.at("total").empty() - or cpu.core_percent.at(0).empty() - or (show_temps and cpu.temp.at(0).empty())) return ""; + if (safeVal(cpu.cpu_percent, "total"s).empty() + or safeVal(cpu.core_percent, 0).empty() + or (show_temps and safeVal(cpu.temp, 0).empty())) return ""; + if (safeVal(cpu.cpu_percent, "total"s).empty() + or safeVal(cpu.core_percent, 0).empty() + or (show_temps and safeVal(cpu.temp, 0).empty())) return ""; string out; out.reserve(width * height); //* Redraw elements not needed to be updated every cycle if (redraw) { mid_line = (not single_graph and graph_up_field != graph_lo_field); - graph_up_height = (single_graph ? height - 2 : ceil((double)(height - 2) / 2) - (mid_line and height % 2 != 0 ? 1 : 0)); - const int graph_low_height = height - 2 - graph_up_height - (mid_line ? 1 : 0); + 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; out += box; @@ -563,17 +591,91 @@ namespace Cpu { Input::mouse_mappings["+"] = {button_y, x + width - 5, 1, 2}; //? Graphs & meters - graph_upper = Draw::Graph{x + width - b_width - 3, graph_up_height, "cpu", cpu.cpu_percent.at(graph_up_field), graph_symbol, false, true}; + const int graph_default_width = x + width - b_width - 3; + + auto init_graphs = [&](vector<Draw::Graph>& graphs, const int graph_height, int& graph_width, const string& graph_field, bool invert) { + #ifdef GPU_SUPPORT + if (graph_field.starts_with("gpu")) { + if (graph_field.find("totals") != string::npos) { + graphs.resize(gpus.size()); + 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;;) { + 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 }; + 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) + graph = Draw::Graph{graph_width, graph_height, "cpu", safeVal(gpu.gpu_percent, graph_field), graph_symbol, invert, true}; + } else { + if (utilization_support) + 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 { + #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 + }; + + init_graphs(graphs_upper, graph_up_height, graph_up_width, graph_up_field, false); + if (not single_graph) + init_graphs(graphs_lower, graph_low_height, graph_low_width, graph_lo_field, Config::getB("cpu_invert_lower")); + cpu_meter = Draw::Meter{b_width - (show_temps ? 23 - (b_column_size <= 1 and b_columns == 1 ? 6 : 0) : 11), "cpu"}; - if (not single_graph) { - graph_lower = Draw::Graph{ - x + width - b_width - 3, - graph_low_height, "cpu", - cpu.cpu_percent.at(graph_lo_field), - graph_symbol, - Config::getB("cpu_invert_lower"), true - }; - } if (mid_line) { out += Mv::to(y + graph_up_height + 1, x) + Fx::ub + Theme::c("cpu_box") + Symbols::div_left + Theme::c("div_line") @@ -591,10 +693,10 @@ namespace Cpu { if (show_temps) { temp_graphs.clear(); - temp_graphs.emplace_back(5, 1, "temp", cpu.temp.at(0), graph_symbol, false, false, cpu.temp_max, -23); + temp_graphs.emplace_back(5, 1, "temp", safeVal(cpu.temp, 0), graph_symbol, false, false, cpu.temp_max, -23); if (not hide_cores and b_column_size > 1) { for (const auto& i : iota((size_t)1, cpu.temp.size())) { - temp_graphs.emplace_back(5, 1, "temp", cpu.temp.at(i), graph_symbol, false, false, cpu.temp_max, -23); + temp_graphs.emplace_back(5, 1, "temp", safeVal(cpu.temp, i), graph_symbol, false, false, cpu.temp_max, -23); } } } @@ -606,7 +708,7 @@ namespace Cpu { static long old_seconds{}; // defaults to = 0 static string old_status; static Draw::Meter bat_meter {10, "cpu", true}; - static const unordered_flat_map<string, string> bat_symbols = { + static const std::unordered_map<string, string> bat_symbols = { {"charging", "▲"}, {"discharging", "▼"}, {"full", "■"}, @@ -641,10 +743,39 @@ namespace Cpu { } try { - //? Cpu graphs - out += Fx::ub + Mv::to(y + 1, x + 1) + graph_upper(cpu.cpu_percent.at(graph_up_field), (data_same or redraw)); - if (not single_graph) - out += Mv::to( y + graph_up_height + 1 + (mid_line ? 1 : 0), x + 1) + graph_lower(cpu.cpu_percent.at(graph_lo_field), (data_same or redraw)); + //? Cpu/Gpu graphs + out += Fx::ub + Mv::to(y + 1, x + 1); + auto draw_graphs = [&](vector<Draw::Graph>& graphs, const int graph_height, const int graph_width, const string& graph_field) { + #ifdef GPU_SUPPORT + if (graph_field.starts_with("gpu")) + if (graph_field.find("totals") != string::npos) + for (unsigned long i = 0;;) { + out += graphs[i](safeVal(gpus[i].gpu_percent, graph_field), (data_same or redraw)); + if (gpus.size() > 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()); + } + + if (++i < 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)); + else + #else + (void)graph_height; + (void)graph_width; + #endif + out += graphs[0](safeVal(cpu.cpu_percent, graph_field), (data_same or redraw)); + }; + + draw_graphs(graphs_upper, graph_up_height, graph_up_width, graph_up_field); + if (not single_graph) { + out += Mv::to(y + graph_up_height + 1 + mid_line, x + 1); + draw_graphs(graphs_lower, graph_low_height, graph_low_width, graph_lo_field); + } //? Uptime if (Config::getB("show_uptime")) { @@ -662,14 +793,14 @@ namespace Cpu { out += Mv::to(b_y, b_x + b_width - 10) + Fx::ub + Theme::c("div_line") + Symbols::h_line * (7 - cpuHz.size()) + Symbols::title_left + Fx::b + Theme::c("title") + cpuHz + Fx::ub + Theme::c("div_line") + Symbols::title_right; - out += Mv::to(b_y + 1, b_x + 1) + Theme::c("main_fg") + Fx::b + "CPU " + cpu_meter(cpu.cpu_percent.at("total").back()) - + Theme::g("cpu").at(clamp(cpu.cpu_percent.at("total").back(), 0ll, 100ll)) + rjust(to_string(cpu.cpu_percent.at("total").back()), 4) + Theme::c("main_fg") + '%'; + out += Mv::to(b_y + 1, b_x + 1) + Theme::c("main_fg") + Fx::b + "CPU " + cpu_meter(safeVal(cpu.cpu_percent, |