summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJakob P. Liljenberg <admin@qvantnet.com>2024-01-03 16:34:01 +0100
committerGitHub <noreply@github.com>2024-01-03 16:34:01 +0100
commitef788efc536733a441949dab854b0a6bea5ef33e (patch)
tree4a27a7212369425705973fc29f9c8feff00b00ba /src
parentc90e3f9b1508f55d281495468297df409f974eb0 (diff)
parenta29545c4079e9bc5203e09965ac03fabe975bd7e (diff)
Merge branch 'main' into lldb-term-size
Diffstat (limited to 'src')
-rw-r--r--src/btop.cpp117
-rw-r--r--src/btop_config.cpp71
-rw-r--r--src/btop_config.hpp26
-rw-r--r--src/btop_draw.cpp659
-rw-r--r--src/btop_draw.hpp9
-rw-r--r--src/btop_input.cpp33
-rw-r--r--src/btop_input.hpp5
-rw-r--r--src/btop_menu.cpp126
-rw-r--r--src/btop_menu.hpp2
-rw-r--r--src/btop_shared.cpp12
-rw-r--r--src/btop_shared.hpp114
-rw-r--r--src/btop_theme.cpp14
-rw-r--r--src/btop_theme.hpp9
-rw-r--r--src/btop_tools.cpp99
-rw-r--r--src/btop_tools.hpp132
-rw-r--r--src/freebsd/btop_collect.cpp35
-rw-r--r--src/linux/btop_collect.cpp774
-rw-r--r--src/openbsd/btop_collect.cpp1295
-rw-r--r--src/openbsd/internal.h157
-rw-r--r--src/openbsd/sysctlbyname.cpp46
-rw-r--r--src/openbsd/sysctlbyname.h20
-rw-r--r--src/osx/btop_collect.cpp38
-rw-r--r--src/osx/sensors.cpp3
-rw-r--r--src/osx/sensors.hpp3
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,