summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraristocratos <gnmjpl@gmail.com>2021-06-30 22:28:12 +0200
committeraristocratos <gnmjpl@gmail.com>2021-06-30 22:28:12 +0200
commit3634633e21d7d1341deabffca069a46172dbe660 (patch)
treec8a8a6c975aaf436306d5dab3482f341761884f3
parent331665dc550588cce9e29fd8df7dc16e894180bc (diff)
Proc::collect() optimization and started on Proc::_collect_details()
-rw-r--r--Makefile31
-rw-r--r--README.md43
-rw-r--r--src/btop.cpp6
-rw-r--r--src/btop_config.cpp3
-rw-r--r--src/btop_draw.cpp10
-rw-r--r--src/btop_linux.cpp327
-rw-r--r--src/btop_sharedbin41180436 -> 0 bytes
-rw-r--r--src/btop_shared.hpp12
-rw-r--r--src/btop_tools.cpp4
-rw-r--r--src/btop_tools.hpp2
10 files changed, 264 insertions, 174 deletions
diff --git a/Makefile b/Makefile
index 3cf8d31..f2dc173 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,21 @@ PREFIX ?= /usr/local
DOCDIR ?= $(PREFIX)/share/btop/doc
#Compiler and Linker
-CXX := g++
+CXX := g++
+
+#If using g++ try to make sure we are using version 11 or 10
+ifeq ($(CXX),g++)
+ CXX_VERSION = $(shell $(CXX) -dumpversion)
+ ifneq ($(shell test $(CXX_VERSION) -ge 11; echo $$?),0)
+ ifneq ($(shell command -v g++-11),)
+ CXX := g++-11
+ else ifneq ($(shell test $(CXX_VERSION) -eq 10; echo $$?),0)
+ ifneq ($(shell command -v g++-10),)
+ CXX := g++-10
+ endif
+ endif
+ endif
+endif
#The Target Binary Program
TARGET := btop
@@ -20,9 +34,6 @@ OBJEXT := o
CXXFLAGS := -std=c++20 -pthread -O3 -Wall -Wextra -Wno-stringop-overread -pedantic
INC := -I$(INCDIR) -I$(SRCDIR)
-#---------------------------------------------------------------------------------
-#DO NOT EDIT BELOW THIS LINE
-#---------------------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
@@ -34,12 +45,12 @@ directories:
@mkdir -p $(TARGETDIR)
@mkdir -p $(BUILDDIR)
-#Clean only Objecst
+#Clean only Objects
clean:
@rm -rf $(BUILDDIR)
#Full Clean, Objects and Binaries
-dist-clean: clean
+distclean: clean
@rm -rf $(TARGETDIR)
install:
@@ -50,6 +61,14 @@ install:
@cp -pr themes $(DESTDIR)$(PREFIX)/share/btop
@chmod 755 $(DESTDIR)$(PREFIX)/bin/btop
+#Set suid bit for btop to root, will make btop run as root regardless of actual user
+su-setuid:
+ @su --session-command "make as-root-setuid" root
+
+as-root-setuid:
+ @chown root:root $(DESTDIR)$(PREFIX)/bin/btop
+ @chmod 4755 $(DESTDIR)$(PREFIX)/bin/btop
+
uninstall:
@rm -rf $(DESTDIR)$(PREFIX)/bin/btop
@rm -rf $(DESTDIR)$(DOCDIR)
diff --git a/README.md b/README.md
index 50e8026..581c4bd 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,6 @@
* [Themes](#themes)
* [Support and funding](#support-and-funding)
* [Prerequisites](#prerequisites) (Read this if you are having issues!)
-* [Dependencies](#dependencies)
* [Screenshots](#screenshots)
* [Installation](#installation)
* [Configurability](#configurability)
@@ -67,7 +66,7 @@ Btop++ uses the same theme files as bpytop and bashtop (some color values missin
See [themes](https://github.com/aristocratos/btop/tree/master/themes) folder for available themes.
-The `make install` command places the default themes in `[/usr/local]/share/btop/themes`.
+The `make install` command places the default themes in `[$PREFIX or /usr/local]/share/btop/themes`.
User created themes should be placed in `$XDG_CONFIG_HOME/btop/themes` or `$HOME/.config/btop/themes`.
Let me know if you want to contribute with new themes.
@@ -82,15 +81,16 @@ Any support is greatly appreciated!
## Prerequisites
-For correct display, a terminal with support for:
+For best experience, a terminal with support for:
* 24-bit truecolor ([See list of terminals with truecolor support](https://gist.github.com/XVilka/8346728))
* 256-color terminals are supported through 24-bit to 256-color conversion when setting "truecolor" to False in the options or with "-lc/--low-color" argument.
+ (16 color TTY mode now available as well.)
* Wide characters (Are sometimes problematic in web-based terminals)
Also needs a UTF8 locale and a font that covers:
-* Unicode Block “Braille Patterns” U+2800 - U+28FF
+* Unicode Block “Braille Patterns” U+2800 - U+28FF (Not needed in TTY mode or with graphs set to type: block or tty.)
* Unicode Block “Geometric Shapes” U+25A0 - U+25FF
* Unicode Block "Box Drawing" and "Block Elements" U+2500 - U+259F
@@ -108,14 +108,6 @@ If text are misaligned and you are using Konsole or Yakuake, turning off "Bi-Dir
Characters clipping in to each other or text/border misalignments is not bugs caused by bpytop, but most likely a fontconfig or terminal problem where the braille characters making up the graphs aren't rendered correctly.
Look to the creators of the terminal emulator you use to fix these issues if the previous mentioned fixes don't work for you.
-## Dependencies
-
-None
-
-### Compiling from source
-
-Needs at least G++ 10, preferably 11 (or higher) to make use of some C++20 functionality.
-
## Screenshots
Main UI showing details for a selected process.
@@ -134,7 +126,14 @@ Options menu.
#### Manual compilation and installation
-Requires GCC/G++ 10 or higher!
+Needs at least GCC/G++ 10, preferably 11 (or higher) to make use of some C++20 functionality.
+
+>Install dependencies (Ubuntu 21.04 Hirsute)
+
+``` bash
+sudo apt install git build-essential gcc-11 g++-11
+ # On earlier Ubuntu versions that don't have gcc-11 and g++-11 replace with gcc-10 and g++-10
+```
>Clone and compile
@@ -142,26 +141,42 @@ Requires GCC/G++ 10 or higher!
git clone https://github.com/aristocratos/btop.git
cd btop
make
+ # use "make -jX" where X is your number of cores for multithreaded compilation
```
>to install
``` bash
sudo make install
+ # use "make install PREFIX=/target/dir" to set target, default: /usr/local
+ # only use "sudo" when installing to a NON user owned directory
```
+>to make btop always run as root (to enable signal sending to any process and for /proc read permissions on some systems)
+
+``` bash
+make su-setuid
+```
+
+
>to uninstall
``` bash
sudo make uninstall
```
->to remove any compiled files
+>to remove any object files
```bash
make clean
```
+>to remove all object files, binaries and created directories
+
+```bash
+make distclean
+```
+
## Configurability
All options changeable from within UI.
diff --git a/src/btop.cpp b/src/btop.cpp
index 513205a..b1df9a1 100644
--- a/src/btop.cpp
+++ b/src/btop.cpp
@@ -599,7 +599,7 @@ int main(int argc, char **argv){
size_t lc;
string ostring;
uint64_t tsl, timestamp2, rcount = 0;
- list<uint64_t> avgtimes = {0};
+ list<uint64_t> avgtimes;
size_t timer = 2000;
bool filtering = false;
vector<string> greyscale;
@@ -657,8 +657,8 @@ int main(int argc, char **argv){
- if (rcount > 0) avgtimes.push_front(timestamp);
- if (avgtimes.size() > 100) avgtimes.pop_back();
+ avgtimes.push_front(timestamp);
+ if (avgtimes.size() > 30) avgtimes.pop_back();
cout << pbox << ostring << Fx::reset << "\n" << endl;
cout << Mv::to(Term::height - 4, 1) << "Processes call took: " << rjust(to_string(timestamp), 5) << " μs. Average: " <<
rjust(to_string(accumulate(avgtimes.begin(), avgtimes.end(), 0) / avgtimes.size()), 5) << " μs of " << avgtimes.size() <<
diff --git a/src/btop_config.cpp b/src/btop_config.cpp
index e97bbe5..0ed0864 100644
--- a/src/btop_config.cpp
+++ b/src/btop_config.cpp
@@ -211,12 +211,14 @@ namespace Config {
{"tty_mode", false},
{"force_tty", false},
{"lowcolor", false},
+ {"show_detailed", false},
};
unordered_flat_map<string, bool> boolsTmp;
unordered_flat_map<string, int> ints = {
{"update_ms", 2000},
{"proc_update_mult", 2},
+ {"detailed_pid", 0},
};
unordered_flat_map<string, int> intsTmp;
@@ -273,6 +275,7 @@ namespace Config {
}
void unlock(){
+ if (not locked) return;
atomic_wait_set(writelock);
for (auto& item : stringsTmp){
diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp
index 2459f92..bea804e 100644
--- a/src/btop_draw.cpp
+++ b/src/btop_draw.cpp
@@ -106,25 +106,25 @@ namespace Draw {
out = Fx::reset + lcolor;
- //* Draw horizontal lines
+ //? Draw horizontal lines
for (size_t hpos : {c.y, c.y + c.height - 1}){
out += Mv::to(hpos, c.x) + Symbols::h_line * (c.width - 1);
}
- //* Draw vertical lines and fill if enabled
+ //? Draw vertical lines and fill if enabled
for (size_t hpos : iota(c.y + 1, c.y + c.height - 1)){
out += Mv::to(hpos, c.x) + Symbols::v_line +
((c.fill) ? string(c.width - 2, ' ') : Mv::r(c.width - 2)) +
Symbols::v_line;
}
- //* Draw corners
+ //? Draw corners
out += Mv::to(c.y, c.x) + Symbols::left_up +
Mv::to(c.y, c.x + c.width - 1) + Symbols::right_up +
Mv::to(c.y + c.height - 1, c.x) + Symbols::left_down +
Mv::to(c.y + c.height - 1, c.x + c.width - 1) + Symbols::right_down;
- //* Draw titles if defined
+ //? Draw titles if defined
if (not c.title.empty()){
out += Mv::to(c.y, c.x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + c.title +
Fx::ub + lcolor + Symbols::title_right;
@@ -199,7 +199,7 @@ namespace Draw {
if (no_zero and horizon == height - 1 and i != -1 and result[ai] == 0) result[ai] = 1;
}
}
- //? Generate braille symbol from 5x5 2D vector
+ //? Generate graph symbol from 5x5 2D vector
graphs[current][horizon] += (height == 1 and result[0] + result[1] == 0) ? Mv::r(1) : graph_symbol[(result[0] * 5 + result[1])];
}
if (mult and i > data_offset) last = data_value;
diff --git a/src/btop_linux.cpp b/src/btop_linux.cpp
index dc6d5d8..fbcc048 100644
--- a/src/btop_linux.cpp
+++ b/src/btop_linux.cpp
@@ -95,6 +95,7 @@ namespace Proc {
namespace {
struct p_cache {
string name, cmd, user;
+ size_t name_offset;
uint64_t cpu_t = 0, cpu_s = 0;
string prefix = "";
size_t depth = 0;
@@ -120,8 +121,10 @@ namespace Proc {
"cpu lazy",
};
+ detail_container detailed;
+
//* Generate process tree list
- void _tree_gen(const proc_info& cur_proc, const vector<proc_info>& in_procs, vector<proc_info>& out_procs, int cur_depth, const bool collapsed, const string& prefix, const string& filter, bool found){
+ void _tree_gen(const proc_info& cur_proc, const vector<proc_info>& in_procs, vector<proc_info>& out_procs, int cur_depth, const bool collapsed, const string& filter, bool found=false){
auto cur_pos = out_procs.size();
bool filtering = false;
@@ -150,14 +153,46 @@ namespace Proc {
out_procs.back().threads += p.threads;
}
else children++;
- _tree_gen(p, in_procs, out_procs, cur_depth + 1, (collapsed ? true : cache.at(cur_proc.pid).collapsed), prefix, filter, found);
+ _tree_gen(p, in_procs, out_procs, cur_depth + 1, (collapsed ? true : cache.at(cur_proc.pid).collapsed), filter, found);
}
if (collapsed or filtering) return;
if (out_procs.size() > cur_pos + 1 and not out_procs.back().prefix.ends_with("] "))
out_procs.back().prefix.replace(out_procs.back().prefix.size() - 8, 8, " └─ ");
- out_procs.at(cur_pos).prefix = " │ "s * cur_depth + (children > 0 ? (cache.at(cur_proc.pid).collapsed ? "[+] " : "[-] ") : prefix);
+ out_procs.at(cur_pos).prefix = " │ "s * cur_depth + (children > 0 ? (cache.at(cur_proc.pid).collapsed ? "[+] " : "[-] ") : " ├─ ");
+ }
+
+ //* Get datiled info for selected process
+ void _collect_details(proc_info p){
+ fs::path pid_path = Shared::proc_path / std::to_string(p.pid);
+
+ detailed.entry = p;
+ ifstream d_read;
+
+ //* Get RSS mem from smaps
+ if (fs::exists(pid_path / "smaps")) {
+ pid_path /= "smaps";
+ d_read.open(pid_path);
+ if (d_read.good()) {
+ uint64_t rss = 0;
+ string val;
+ try {
+ while (not d_read.eof()) {
+ d_read.ignore(SSmax, 'R');
+ if (d_read.peek() == 's') {
+ d_read.ignore(SSmax, ':');
+ getline(d_read, val, 'k');
+ rss += stoull(val) << 10;
+ }
+ }
+ detailed.entry.mem = rss;
+ }
+ catch (std::invalid_argument const&) {}
+ catch (std::out_of_range const&) {}
+ }
+ d_read.close();
+ }
}
vector<proc_info> current_procs;
@@ -166,10 +201,12 @@ namespace Proc {
vector<proc_info>& collect(){
atomic_wait_set(collecting);
auto& sorting = Config::getS("proc_sorting");
- auto& reverse = Config::getB("proc_reversed");
+ auto reverse = Config::getB("proc_reversed");
auto& filter = Config::getS("proc_filter");
- auto& per_core = Config::getB("proc_per_core");
- auto& tree = Config::getB("proc_tree");
+ auto per_core = Config::getB("proc_per_core");
+ auto tree = Config::getB("proc_tree");
+ auto show_detailed = Config::getB("show_detailed");
+ size_t detailed_pid = Config::getI("detailed_pid");
ifstream pread;
string long_string;
string short_str;
@@ -178,6 +215,7 @@ namespace Proc {
procs.reserve((numpids + 10));
int npids = 0;
int cmult = (per_core) ? Global::coreCount : 1;
+ bool got_detailed = false;
//* Update uid_user map if /etc/passwd changed since last run
if (not Shared::passwd_path.empty() and fs::last_write_time(Shared::passwd_path) != Shared::passwd_time) {
@@ -218,154 +256,160 @@ namespace Proc {
bool new_cache = false;
string pid_str = d.path().filename();
- if (d.is_directory() and isdigit(pid_str[0])) {
- npids++;
- proc_info new_proc (stoul(pid_str));
-
- //* Cache program name, command and username
- if (not cache.contains(new_proc.pid)) {
- string name, cmd, user;
- new_cache = true;
- pread.open(d.path() / "comm");
- if (pread.good()) {
- getline(pread, name);
- pread.close();
+ if (not isdigit(pid_str[0])) continue;
+
+ npids++;
+ proc_info new_proc (stoul(pid_str));
+
+ //* Cache program name, command and username
+ if (not cache.contains(new_proc.pid)) {
+ string name, cmd, user;
+ new_cache = true;
+ pread.open(d.path() / "comm");
+ if (not pread.good()) continue;
+ getline(pread, name);
+ pread.close();
+ size_t name_offset = rng::count(name, ' ');
+
+
+ pread.open(d.path() / "cmdline");
+ if (not pread.good()) continue;
+ long_string.clear();
+ while(getline(pread, long_string, '\0')) cmd += long_string + ' ';
+ pread.close();
+ if (not cmd.empty()) cmd.pop_back();
+
+
+ pread.open(d.path() / "status");
+ if (not pread.good()) continue;
+ string uid;
+ string line;
+ while (not pread.eof()){
+ getline(pread, line, ':');
+ if (line == "Uid") {
+ pread.ignore();
+ getline(pread, uid, '\t');
+ break;
+ } else {
+ pread.ignore(SSmax, '\n');
}
- else continue;
-
- pread.open(d.path() / "cmdline");
- if (pread.good()) {
- string tmpstr;
- while(getline(pread, tmpstr, '\0')) cmd += tmpstr + ' ';
- pread.close();
- if (not cmd.empty()) cmd.pop_back();
+ }
+ pread.close();
+ user = (uid_user.contains(uid)) ? uid_user.at(uid) : uid;
+
+ cache[new_proc.pid] = {name, cmd, user, name_offset};
+ }
+
+ //* Match filter if defined
+ if (not tree and not filter.empty()
+ and not (show_detailed and new_proc.pid == detailed_pid)
+ and pid_str.find(filter) == string::npos
+ and cache[new_proc.pid].name.find(filter) == string::npos
+ and cache[new_proc.pid].cmd.find(filter) == string::npos
+ and cache[new_proc.pid].user.find(filter) == string::npos) {
+ if (new_cache) cache.erase(new_proc.pid);
+ continue;
+ }
+ new_proc.name = cache[new_proc.pid].name;
+ new_proc.cmd = cache[new_proc.pid].cmd;
+ new_proc.user = cache[new_proc.pid].user;
+
+ //* Parse /proc/[pid]/stat
+ pread.open(d.path() / "stat");
+ if (not pread.good()) continue;
+
+ //? Check cached value for whitespace characters in name and set offset to get correct fields from stat file
+ size_t& offset = cache.at(new_proc.pid).name_offset;
+ short_str.clear();
+ size_t x = 0, next_x = 3;
+ uint64_t cpu_t = 0;
+ try {
+ for (;;) {
+ while (++x - offset < next_x) {
+ pread.ignore(SSmax, ' ');
}
- else continue;
-
- pread.open(d.path() / "status");
- if (pread.good()) {
- string uid;
- while (not pread.eof()){
- string line;
- getline(pread, line, ':');
- if (line == "Uid") {
- pread.ignore();
- getline(pread, uid, '\t');
- break;
- } else {
- pread.ignore(SSmax, '\n');
- }
+
+ getline(pread, short_str, ' ');
+
+ switch (x-offset) {
+ case 3: { //? Process state
+ new_proc.state = short_str[0];
+ continue;
+ }
+ case 4: { //? Parent pid
+ new_proc.ppid = stoull(short_str);
+ next_x = 14;
+ continue;
+ }
+ case 14: { //? Process utime
+ cpu_t = stoull(short_str);
+ continue;
+ }
+ case 15: { //? Process stime
+ cpu_t += stoull(short_str);
+ next_x = 19;
+ continue;
+ }
+ case 19: { //? Nice value
+ new_proc.p_nice = stoull(short_str);
+ continue;
+ }
+ case 20: { //? Number of threads
+ new_proc.threads = stoull(short_str);
+ next_x = (new_cache) ? 22 : 24;
+ continue;
+ }
+ case 22: { //? Save cpu seconds to cache if missing
+ cache[new_proc.pid].cpu_s = stoull(short_str);
+ next_x = 24;
+ continue;
+ }
+ case 24: { //? RSS memory (can be inaccurate, but parsing smaps increases total cpu usage by ~ 20x)
+ new_proc.mem = stoull(short_str) * Shared::page_size;
+ next_x = 40;
+ continue;
+ }
+ case 40: { //? CPU number last executed on
+ new_proc.cpu_n = stoull(short_str);
+ goto stat_loop_done;
}
- pread.close();
- user = (uid_user.contains(uid)) ? uid_user.at(uid) : uid;
}
- else continue;
- cache[new_proc.pid] = {name, cmd, user};
}
- //* Match filter if defined
- if (not tree and not filter.empty()
- and pid_str.find(filter) == string::npos
- and cache[new_proc.pid].name.find(filter) == string::npos
- and cache[new_proc.pid].cmd.find(filter) == string::npos
- and cache[new_proc.pid].user.find(filter) == string::npos) {
- if (new_cache) cache.erase(new_proc.pid);
- continue;
- }
- new_proc.name = cache[new_proc.pid].name;
- new_proc.cmd = cache[new_proc.pid].cmd;
- new_proc.user = cache[new_proc.pid].user;
-
- //* Parse /proc/[pid]/stat
- pread.open(d.path() / "stat");
- if (pread.good()) {
-
- //? Check cached name for whitespace characters and set offset to get correct fields from stat file
- size_t offset = rng::count(cache.at(new_proc.pid).name, ' ');
- size_t x = 0, next_x = 3;
- uint64_t cpu_t = 0;
- try {
- while (not pread.eof()) {
- if (++x > 40 + offset) break;
-
- if (x-offset < next_x) {
- pread.ignore(SSmax, ' ');
- continue;
- }
- else
- getline(pread, short_str, ' ');
-
- switch (x-offset) {
- case 3: { //? Process state
- new_proc.state = short_str[0];
- break;
- }
- case 4: { //? Process parent pid
- new_proc.ppid = stoull(short_str);
- next_x = 14;
- break;
- }
- case 14: { //? Process utime
- cpu_t = stoull(short_str);
- break;
- }
- case 15: { //? Process stime
- cpu_t += stoull(short_str);
- next_x = 19;
- break;
- }
- case 19: { //? Process nice value
- new_proc.p_nice = stoull(short_str);
- break;
- }
- case 20: { //? Process number of threads
- new_proc.threads = stoull(short_str);
- next_x = (new_cache) ? 22 : 40;
- break;
- }
- case 22: { //? Cache cpu seconds
- cache[new_proc.pid].cpu_s = stoull(short_str);
- next_x = 40;
- break;
- }
- case 40: { //? CPU number last executed on
- new_proc.cpu_n = stoull(short_str);
- break;
- }
- }
- }
- pread.close();
+ }
+ catch (std::invalid_argument const&) { continue; }
+ catch (std::out_of_range const&) { continue; }
+ catch (std::ios_base::failure const&) {}
- }
- catch (...) {
- continue;
- }
+ stat_loop_done:
+ pread.close();
- if (x-offset < 22) continue;
+ if (x-offset < 24) continue;
- //? Process cpu usage since last update
- new_proc.cpu_p = round(cmult * 1000 * (cpu_t - cache[new_proc.pid].cpu_t) / (cputimes - old_cputimes)) / 10.0;
+ // _parse_smaps(new_proc);
- //? Process cumulative cpu usage since process start
- new_proc.cpu_c = ((double)cpu_t / Shared::clk_tck) / (uptime - (cache[new_proc.pid].cpu_s / Shared::clk_tck));
+ //? Process cpu usage since last update
+ new_proc.cpu_p = round(cmult * 1000 * (cpu_t - cache[new_proc.pid].cpu_t) / (cputimes - old_cputimes)) / 10.0;
- //? Update cache with latest cpu times
- cache[new_proc.pid].cpu_t = cpu_t;
- }
- else continue;
+ //? Process cumulative cpu usage since process start
+ new_proc.cpu_c = ((double)cpu_t / Shared::clk_tck) / (uptime - (cache[new_proc.pid].cpu_s / Shared::clk_tck));
- //* Get RSS memory in bytes from /proc/[pid]/statm
- pread.open(d.path() / "statm");
- if (pread.good()) {
- pread.ignore(SSmax, ' ');
- getline(pread, short_str, ' ');
- pread.close();
- new_proc.mem = stoull(short_str) * Shared::page_size;
- }
+ //? Update cache with latest cpu times
+ cache[new_proc.pid].cpu_t = cpu_t;
- //? Push process to vector
- procs.push_back(new_proc);
+ //? Update the details info box for process if active
+ if (show_detailed and new_proc.pid == detailed_pid) {
+ _collect_details(new_proc);
+ got_detailed = true;
}
+
+ //? Push process to vector
+ procs.push_back(new_proc);
+
+ }
+
+ if (show_detailed and not got_detailed) {
+ detailed.entry.state = 'X';
}
//* Sort processes
@@ -403,10 +447,9 @@ namespace Proc {
//? Stable sort to retain selected sorting among processes with the same parent
rng::stable_sort(procs, rng::less{}, &proc_info::ppid);
- string prefix = " ├─ ";
//? Start recursive iteration over processes with the lowest shared parent pids
for (auto& p : rng::equal_range(procs, procs.at(0).ppid, rng::less{}, &proc_info::ppid)) {
- _tree_gen(p, procs, tree_procs, 0, cache.at(p.pid).collapsed, prefix, filter, false);
+ _tree_gen(p, procs, tree_procs, 0, cache.at(p.pid).collapsed, filter);
}
procs.swap(tree_procs);
}
diff --git a/src/btop_shared b/src/btop_shared
deleted file mode 100644
index 152aa8d..0000000
--- a/src/btop_shared
+++ /dev/null
Binary files differ
diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp
index 3b4e5d0..94b83b0 100644
--- a/src/btop_shared.hpp
+++ b/src/btop_shared.hpp
@@ -32,7 +32,7 @@ namespace Global {
}
namespace Tools {
- //* Platform specific function for system_uptime
+ //* Platform specific function for system_uptime (seconds since last restart)
double system_uptime();
}
@@ -45,6 +45,8 @@ namespace Proc {
extern size_t numpids;
extern std::atomic<bool> stop;
extern std::atomic<bool> collecting;
+
+ //? Contains the valid sorting options for processes
extern vector<string> sort_vector;
//* Container for process information
@@ -60,6 +62,14 @@ namespace Proc {
string prefix = "";
};
+ //* Container for process info box
+ struct detail_container {
+ proc_info entry;
+ string elapsed, parent, status, io_read, io_write;
+ };
+
+ extern detail_container detailed;
+
extern vector<proc_info> current_procs;
//* Collects and sorts process information from /proc, saves and returns reference to Proc::current_procs;
diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp
index 2e50b5a..6d7195b 100644
--- a/src/btop_tools.cpp
+++ b/src/btop_tools.cpp
@@ -362,12 +362,12 @@ namespace Tools {
#if (__GNUC__ > 10)
//* Redirects to atomic wait
- void atomic_wait(atomic<bool>& atom, bool val){
+ void atomic_wait(const atomic<bool>& atom, bool val){
atom.wait(val);
}
#else
//* Crude implementation of atomic wait for GCC 10
- void atomic_wait(atomic<bool>& atom, bool val){
+ void atomic_wait(const atomic<bool>& atom, bool val){
while (atom == val) std::this_thread::sleep_for(std::chrono::microseconds(1));
}
#endif
diff --git a/src/btop_tools.hpp b/src/btop_tools.hpp
index 65faf20..8a77bf3 100644
--- a/src/btop_tools.hpp
+++ b/src/btop_tools.hpp
@@ -225,7 +225,7 @@ namespace Tools {
string strf_time(string strf);
//* Waits for <atom> to not be <val>
- void atomic_wait(std::atomic<bool>& atom, bool val=true);
+ void atomic_wait(const std::atomic<bool>& atom, bool val=true);
//* Waits for <atom> to not be <val> and then sets it to <val> again
void atomic_wait_set(std::atomic<bool>& atom, bool val=true);