mirror of
https://github.com/aristocratos/btop.git
synced 2024-05-20 20:32:50 +12:00
Changed: Rewrite of process sorting and tree generation including fixes for tree sorting and mouse support
This commit is contained in:
parent
102b6dbc9d
commit
6b1b9f8142
|
@ -264,6 +264,7 @@ namespace Config {
|
|||
{"net_upload", 100},
|
||||
{"detailed_pid", 0},
|
||||
{"selected_pid", 0},
|
||||
{"selected_depth", 0},
|
||||
{"proc_start", 0},
|
||||
{"proc_selected", 0},
|
||||
{"proc_last_selected", 0},
|
||||
|
@ -472,6 +473,7 @@ namespace Config {
|
|||
strings.at("selected_name") = Proc::selected_name;
|
||||
ints.at("proc_start") = Proc::start;
|
||||
ints.at("proc_selected") = Proc::selected;
|
||||
ints.at("selected_depth") = Proc::selected_depth;
|
||||
}
|
||||
|
||||
for (auto& item : stringsTmp) {
|
||||
|
|
|
@ -1022,7 +1022,7 @@ namespace Proc {
|
|||
int x, y, width = 20, height;
|
||||
int start, selected, select_max;
|
||||
bool shown = true, redraw = true;
|
||||
int selected_pid = 0;
|
||||
int selected_pid = 0, selected_depth = 0;
|
||||
string selected_name;
|
||||
unordered_flat_map<size_t, Draw::Graph> p_graphs;
|
||||
unordered_flat_map<size_t, bool> p_wide_cmd;
|
||||
|
@ -1345,6 +1345,7 @@ namespace Proc {
|
|||
if (is_selected) {
|
||||
selected_pid = (int)p.pid;
|
||||
selected_name = p.name;
|
||||
selected_depth = p.depth;
|
||||
}
|
||||
|
||||
//? Update graphs for processes with above 0.0% cpu usage, delete if below 0.1% 10x times
|
||||
|
|
|
@ -354,7 +354,16 @@ namespace Input {
|
|||
const auto& current_selection = Config::getI("proc_selected");
|
||||
if (current_selection == line - y - 1) {
|
||||
redraw = true;
|
||||
goto proc_mouse_enter;
|
||||
if (Config::getB("proc_tree")) {
|
||||
const int x_pos = col - Proc::x;
|
||||
const int offset = Config::getI("selected_depth") * 3;
|
||||
if (x_pos > offset and x_pos < 4 + offset) {
|
||||
process("space");
|
||||
return;
|
||||
}
|
||||
}
|
||||
process("enter");
|
||||
return;
|
||||
}
|
||||
else if (current_selection == 0 or line - y - 1 == 0)
|
||||
redraw = true;
|
||||
|
@ -380,7 +389,6 @@ namespace Input {
|
|||
keep_going = true;
|
||||
}
|
||||
else if (key == "enter") {
|
||||
proc_mouse_enter:
|
||||
if (Config::getI("proc_selected") == 0 and not Config::getB("show_detailed")) {
|
||||
return;
|
||||
}
|
||||
|
|
174
src/btop_shared.cpp
Normal file
174
src/btop_shared.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <btop_shared.hpp>
|
||||
#include <btop_tools.hpp>
|
||||
|
||||
using std::string_literals::operator""s;
|
||||
namespace rng = std::ranges;
|
||||
using namespace Tools;
|
||||
|
||||
|
||||
namespace Proc {
|
||||
void proc_sorter(vector<proc_info>& proc_vec, string sorting, const bool reverse, const bool tree) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(proc_vec, rng::less{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(proc_vec, rng::less{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(proc_vec, rng::less{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(proc_vec, rng::less{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(proc_vec, rng::less{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
|
||||
//* When sorting with "cpu lazy" push processes over threshold cpu usage to the front regardless of cumulative usage
|
||||
if (not tree and not reverse and sorting == "cpu lazy") {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, x = 0, offset = 0; i < proc_vec.size(); i++) {
|
||||
if (i <= 5 and proc_vec.at(i).cpu_p > max)
|
||||
max = proc_vec.at(i).cpu_p;
|
||||
else if (i == 6)
|
||||
target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset and proc_vec.at(i).cpu_p > 30.0)
|
||||
offset++;
|
||||
else if (proc_vec.at(i).cpu_p > target) {
|
||||
rotate(proc_vec.begin() + offset, proc_vec.begin() + i, proc_vec.begin() + i + 1);
|
||||
if (++x > 10) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tree_sort(vector<tree_proc>& proc_vec, const string& sorting, const bool reverse, int& c_index, const int index_max, const bool collapsed) {
|
||||
if (proc_vec.size() > 1) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 3: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().threads < b.entry.get().threads; }); break;
|
||||
case 5: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().mem < b.entry.get().mem; }); break;
|
||||
case 6: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_p < b.entry.get().cpu_p; }); break;
|
||||
case 7: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_c < b.entry.get().cpu_c; }); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 3: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().threads > b.entry.get().threads; }); break;
|
||||
case 5: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().mem > b.entry.get().mem; }); break;
|
||||
case 6: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_p > b.entry.get().cpu_p; }); break;
|
||||
case 7: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_c > b.entry.get().cpu_c; }); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& r : proc_vec) {
|
||||
r.entry.get().tree_index = (collapsed or r.entry.get().filtered ? index_max : c_index++);
|
||||
if (not r.children.empty()) {
|
||||
tree_sort(r.children, sorting, reverse, c_index, (collapsed or r.entry.get().collapsed or r.entry.get().tree_index == (size_t)index_max));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs, int cur_depth, const bool collapsed, const string& filter, bool found, const bool no_update, const bool should_filter) {
|
||||
auto cur_pos = out_procs.size();
|
||||
bool filtering = false;
|
||||
|
||||
//? If filtering, include children of matching processes
|
||||
if (not found and (should_filter or not filter.empty())) {
|
||||
if (not s_contains(std::to_string(cur_proc.pid), filter)
|
||||
and not s_contains(cur_proc.name, filter)
|
||||
and not s_contains(cur_proc.cmd, filter)
|
||||
and not s_contains(cur_proc.user, filter)) {
|
||||
filtering = true;
|
||||
cur_proc.filtered = true;
|
||||
filter_found++;
|
||||
}
|
||||
else {
|
||||
found = true;
|
||||
cur_depth = 0;
|
||||
}
|
||||
}
|
||||
else if (cur_proc.filtered) cur_proc.filtered = false;
|
||||
|
||||
cur_proc.depth = cur_depth;
|
||||
|
||||
//? Set tree index position for process if not filtered out or currently in a collapsed sub-tree
|
||||
out_procs.push_back({ cur_proc, {} });
|
||||
if (not collapsed and not filtering) {
|
||||
cur_proc.tree_index = out_procs.size() - 1;
|
||||
|
||||
//? Try to find name of the binary file and append to program name if not the same
|
||||
if (cur_proc.short_cmd.empty() and not cur_proc.cmd.empty()) {
|
||||
std::string_view cmd_view = cur_proc.cmd;
|
||||
cmd_view = cmd_view.substr((size_t)0, std::min(cmd_view.find(' '), cmd_view.size()));
|
||||
cmd_view = cmd_view.substr(std::min(cmd_view.find_last_of('/') + 1, cmd_view.size()));
|
||||
cur_proc.short_cmd = (string)cmd_view;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cur_proc.tree_index = in_procs.size();
|
||||
}
|
||||
|
||||
//? Recursive iteration over all children
|
||||
int children = 0;
|
||||
for (auto& p : rng::equal_range(in_procs, cur_proc.pid, rng::less{}, &proc_info::ppid)) {
|
||||
if (collapsed and not filtering) {
|
||||
cur_proc.filtered = true;
|
||||
}
|
||||
children++;
|
||||
|
||||
_tree_gen(p, in_procs, out_procs.back().children, cur_depth + 1, (collapsed or cur_proc.collapsed), filter, found, no_update, should_filter);
|
||||
|
||||
if (not no_update and not filtering and (collapsed or cur_proc.collapsed)) {
|
||||
//auto& parent = cur_proc;
|
||||
cur_proc.cpu_p += p.cpu_p;
|
||||
cur_proc.cpu_c += p.cpu_c;
|
||||
cur_proc.mem += p.mem;
|
||||
cur_proc.threads += p.threads;
|
||||
filter_found++;
|
||||
p.filtered = true;
|
||||
}
|
||||
}
|
||||
if (collapsed or filtering) {
|
||||
return;
|
||||
}
|
||||
|
||||
//? Add tree terminator symbol if it's the last child in a sub-tree
|
||||
if (children > 0 and out_procs.back().children.back().entry.get().prefix.size() >= 8 and not out_procs.back().children.back().entry.get().prefix.ends_with("]─"))
|
||||
out_procs.back().children.back().entry.get().prefix.replace(out_procs.back().children.back().entry.get().prefix.size() - 8, 8, " └─ ");
|
||||
|
||||
//? Add collapse/expand symbols if process have any children
|
||||
out_procs.at(cur_pos).entry.get().prefix = " │ "s * cur_depth + (children > 0 ? (cur_proc.collapsed ? "[+]─" : "[-]─") : " ├─ ");
|
||||
}
|
||||
|
||||
}
|
|
@ -131,7 +131,7 @@ namespace Mem {
|
|||
struct disk_info {
|
||||
std::filesystem::path dev;
|
||||
string name;
|
||||
string fstype;
|
||||
string fstype = "";
|
||||
std::filesystem::path stat = "";
|
||||
int64_t total = 0, used = 0, free = 0;
|
||||
int used_percent = 0, free_percent = 0;
|
||||
|
@ -199,7 +199,7 @@ namespace Proc {
|
|||
extern bool shown, redraw;
|
||||
extern int select_max;
|
||||
extern atomic<int> detailed_pid;
|
||||
extern int selected_pid, start, selected, collapse, expand;
|
||||
extern int selected_pid, start, selected, collapse, expand, filter_found, selected_depth;
|
||||
extern string selected_name;
|
||||
|
||||
//? Contains the valid sorting options for processes
|
||||
|
@ -268,4 +268,18 @@ namespace Proc {
|
|||
|
||||
//* Draw contents of proc box using <plist> as data source
|
||||
string draw(const vector<proc_info>& plist, const bool force_redraw=false, const bool data_same=false);
|
||||
|
||||
struct tree_proc {
|
||||
std::reference_wrapper<proc_info> entry;
|
||||
vector<tree_proc> children;
|
||||
};
|
||||
|
||||
//* Sort vector of proc_info's
|
||||
void proc_sorter(vector<proc_info>& proc_vec, string sorting, const bool reverse, const bool tree = false);
|
||||
|
||||
//* Recursive sort of process tree
|
||||
void tree_sort(vector<tree_proc>& proc_vec, const string& sorting, const bool reverse, int& c_index, const int index_max, const bool collapsed = false);
|
||||
|
||||
//* Generate process tree list
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs, int cur_depth, const bool collapsed, const string& filter, bool found=false, const bool no_update=false, const bool should_filter=false);
|
||||
}
|
||||
|
|
|
@ -1007,65 +1007,6 @@ namespace Proc {
|
|||
|
||||
detail_container detailed;
|
||||
|
||||
//* Generate process tree list
|
||||
void _tree_gen(proc_info &cur_proc, vector<proc_info> &in_procs, vector<std::reference_wrapper<proc_info>> &out_procs, int cur_depth, const bool collapsed, const string &filter, bool found = false, const bool no_update = false, const bool should_filter = false) {
|
||||
auto cur_pos = out_procs.size();
|
||||
bool filtering = false;
|
||||
|
||||
//? If filtering, include children of matching processes
|
||||
if (not found and (should_filter or not filter.empty())) {
|
||||
if (not s_contains(std::to_string(cur_proc.pid), filter) and not s_contains(cur_proc.name, filter) and not s_contains(cur_proc.cmd, filter) and not s_contains(cur_proc.user, filter)) {
|
||||
filtering = true;
|
||||
cur_proc.filtered = true;
|
||||
filter_found++;
|
||||
} else {
|
||||
found = true;
|
||||
cur_depth = 0;
|
||||
}
|
||||
} else if (cur_proc.filtered)
|
||||
cur_proc.filtered = false;
|
||||
|
||||
//? Set tree index position for process if not filtered out or currently in a collapsed sub-tree
|
||||
if (not collapsed and not filtering) {
|
||||
out_procs.push_back(std::ref(cur_proc));
|
||||
cur_proc.tree_index = out_procs.size() - 1;
|
||||
//? Try to find name of the binary file and append to program name if not the same
|
||||
if (cur_proc.short_cmd.empty() and not cur_proc.cmd.empty()) {
|
||||
std::string_view cmd_view = cur_proc.cmd;
|
||||
cmd_view = cmd_view.substr((size_t)0, min(cmd_view.find(' '), cmd_view.size()));
|
||||
cmd_view = cmd_view.substr(min(cmd_view.find_last_of('/') + 1, cmd_view.size()));
|
||||
cur_proc.short_cmd = (string)cmd_view;
|
||||
}
|
||||
} else {
|
||||
cur_proc.tree_index = in_procs.size();
|
||||
}
|
||||
|
||||
//? Recursive iteration over all children
|
||||
int children = 0;
|
||||
for (auto &p : rng::equal_range(in_procs, cur_proc.pid, rng::less{}, &proc_info::ppid)) {
|
||||
if (not no_update and not filtering and (collapsed or cur_proc.collapsed)) {
|
||||
out_procs.back().get().cpu_p += p.cpu_p;
|
||||
out_procs.back().get().mem += p.mem;
|
||||
out_procs.back().get().threads += p.threads;
|
||||
filter_found++;
|
||||
}
|
||||
if (collapsed and not filtering) {
|
||||
cur_proc.filtered = true;
|
||||
} else
|
||||
children++;
|
||||
_tree_gen(p, in_procs, out_procs, cur_depth + 1, (collapsed ? true : cur_proc.collapsed), filter, found, no_update, should_filter);
|
||||
}
|
||||
if (collapsed or filtering)
|
||||
return;
|
||||
|
||||
//? Add tree terminator symbol if it's the last child in a sub-tree
|
||||
if (out_procs.size() > cur_pos + 1 and not out_procs.back().get().prefix.ends_with("]─"))
|
||||
out_procs.back().get().prefix.replace(out_procs.back().get().prefix.size() - 8, 8, " └─ ");
|
||||
|
||||
//? Add collapse/expand symbols if process have any children
|
||||
out_procs.at(cur_pos).get().prefix = " │ "s * cur_depth + (children > 0 ? (cur_proc.collapsed ? "[+]─" : "[-]─") : " ├─ ");
|
||||
}
|
||||
|
||||
string get_status(char s) {
|
||||
if (s & SRUN) return "Running";
|
||||
if (s & SSLEEP) return "Sleeping";
|
||||
|
@ -1156,6 +1097,8 @@ namespace Proc {
|
|||
const int cmult = (per_core) ? Shared::coreCount : 1;
|
||||
bool got_detailed = false;
|
||||
|
||||
static vector<size_t> found;
|
||||
|
||||
vector<array<long, CPUSTATES>> cpu_time(Shared::coreCount);
|
||||
size_t size = sizeof(long) * CPUSTATES * Shared::coreCount;
|
||||
if (sysctlbyname("kern.cp_times", &cpu_time[0], &size, NULL, 0) == -1) {
|
||||
|
@ -1175,7 +1118,7 @@ namespace Proc {
|
|||
//* ---------------------------------------------Collection start----------------------------------------------
|
||||
|
||||
should_filter = true;
|
||||
vector<size_t> found;
|
||||
found.clear();
|
||||
struct timeval currentTime;
|
||||
gettimeofday(¤tTime, NULL);
|
||||
const double timeNow = currentTime.tv_sec + (currentTime.tv_usec / 1'000'000);
|
||||
|
@ -1206,6 +1149,7 @@ namespace Proc {
|
|||
if (no_cache) {
|
||||
if (kproc->ki_comm == NULL or kproc->ki_comm == "idle"s) {
|
||||
current_procs.pop_back();
|
||||
found.pop_back();
|
||||
continue;
|
||||
}
|
||||
new_proc.name = kproc->ki_comm;
|
||||
|
@ -1249,116 +1193,111 @@ namespace Proc {
|
|||
if (show_detailed and not got_detailed and new_proc.pid == detailed_pid) {
|
||||
got_detailed = true;
|
||||
}
|
||||
|
||||
// //? Clear dead processes from current_procs
|
||||
auto eraser = rng::remove_if(current_procs, [&](const auto &element) { return not v_contains(found, element.pid); });
|
||||
current_procs.erase(eraser.begin(), eraser.end());
|
||||
|
||||
//? Update the details info box for process if active
|
||||
if (show_detailed and got_detailed) {
|
||||
_collect_details(detailed_pid, current_procs);
|
||||
} else if (show_detailed and not got_detailed and detailed.status != "Dead") {
|
||||
detailed.status = "Dead";
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
old_cputimes = cputimes;
|
||||
}
|
||||
|
||||
//? Clear dead processes from current_procs
|
||||
auto eraser = rng::remove_if(current_procs, [&](const auto &element) { return not v_contains(found, element.pid); });
|
||||
current_procs.erase(eraser.begin(), eraser.end());
|
||||
|
||||
//? Update the details info box for process if active
|
||||
if (show_detailed and got_detailed) {
|
||||
_collect_details(detailed_pid, current_procs);
|
||||
} else if (show_detailed and not got_detailed and detailed.status != "Dead") {
|
||||
detailed.status = "Dead";
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
old_cputimes = cputimes;
|
||||
|
||||
}
|
||||
|
||||
//* ---------------------------------------------Collection done-----------------------------------------------
|
||||
|
||||
//* Sort processes
|
||||
if (sorted_change or not no_update) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(current_procs, rng::less{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(current_procs, rng::less{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(current_procs, rng::less{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(current_procs, rng::less{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(current_procs, rng::less{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(current_procs, rng::less{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(current_procs, rng::less{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(current_procs, rng::less{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
} else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(current_procs, rng::greater{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(current_procs, rng::greater{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(current_procs, rng::greater{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(current_procs, rng::greater{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(current_procs, rng::greater{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
|
||||
//* When sorting with "cpu lazy" push processes over threshold cpu usage to the front regardless of cumulative usage
|
||||
if (not tree and not reverse and sorting == "cpu lazy") {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, x = 0, offset = 0; i < current_procs.size(); i++) {
|
||||
if (i <= 5 and current_procs.at(i).cpu_p > max)
|
||||
max = current_procs.at(i).cpu_p;
|
||||
else if (i == 6)
|
||||
target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset and current_procs.at(i).cpu_p > 30.0)
|
||||
offset++;
|
||||
else if (current_procs.at(i).cpu_p > target) {
|
||||
rotate(current_procs.begin() + offset, current_procs.begin() + i, current_procs.begin() + i + 1);
|
||||
if (++x > 10) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Match filter if defined
|
||||
if (should_filter) {
|
||||
filter_found = 0;
|
||||
for (auto &p : current_procs) {
|
||||
for (auto& p : current_procs) {
|
||||
if (not tree and not filter.empty()) {
|
||||
if (not s_contains_ic(to_string(p.pid), filter) and not s_contains_ic(p.name, filter) and not s_contains_ic(p.cmd, filter) and not s_contains_ic(p.user, filter)) {
|
||||
p.filtered = true;
|
||||
filter_found++;
|
||||
} else {
|
||||
p.filtered = false;
|
||||
if (not s_contains_ic(to_string(p.pid), filter)
|
||||
and not s_contains_ic(p.name, filter)
|
||||
and not s_contains_ic(p.cmd, filter)
|
||||
and not s_contains_ic(p.user, filter)) {
|
||||
p.filtered = true;
|
||||
filter_found++;
|
||||
}
|
||||
else {
|
||||
p.filtered = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
else {
|
||||
p.filtered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Sort processes
|
||||
if (sorted_change or not no_update) {
|
||||
proc_sorter(current_procs, sorting, reverse, tree);
|
||||
}
|
||||
|
||||
//* Generate tree view if enabled
|
||||
if (tree and (not no_update or should_filter or sorted_change)) {
|
||||
bool locate_selection = false;
|
||||
if (auto find_pid = (collapse != -1 ? collapse : expand); find_pid != -1) {
|
||||
auto collapser = rng::find(current_procs, find_pid, &proc_info::pid);
|
||||
if (collapser != current_procs.end()) {
|
||||
if (collapse == expand) {
|
||||
collapser->collapsed = not collapser->collapsed;
|
||||
} else if (collapse > -1) {
|
||||
}
|
||||
else if (collapse > -1) {
|
||||
collapser->collapsed = true;
|
||||
} else if (expand > -1) {
|
||||
}
|
||||
else if (expand > -1) {
|
||||
collapser->collapsed = false;
|
||||
}
|
||||
if (Config::ints.at("proc_selected") > 0) locate_selection = true;
|
||||
}
|
||||
collapse = expand = -1;
|
||||
}
|
||||
if (should_filter or not filter.empty()) filter_found = 0;
|
||||
|
||||
vector<std::reference_wrapper<proc_info>> tree_procs;
|
||||
vector<tree_proc> tree_procs;
|
||||
tree_procs.reserve(current_procs.size());
|
||||
|
||||
for (auto& p : current_procs) {
|
||||
if (not v_contains(found, p.ppid)) p.ppid = 0;
|
||||
}
|
||||
|
||||
//? Stable sort to retain selected sorting among processes with the same parent
|
||||
rng::stable_sort(current_procs, rng::less{}, &proc_info::ppid);
|
||||
rng::stable_sort(current_procs, rng::less{}, & proc_info::ppid);
|
||||
|
||||
//? Start recursive iteration over processes with the lowest shared parent pids
|
||||
for (auto &p : rng::equal_range(current_procs, current_procs.at(0).ppid, rng::less{}, &proc_info::ppid)) {
|
||||
for (auto& p : rng::equal_range(current_procs, current_procs.at(0).ppid, rng::less{}, &proc_info::ppid)) {
|
||||
_tree_gen(p, current_procs, tree_procs, 0, false, filter, false, no_update, should_filter);
|
||||
}
|
||||
|
||||
//? Recursive sort over tree structure to account for collapsed processes in the tree
|
||||
int index = 0;
|
||||
tree_sort(tree_procs, sorting, reverse, index, current_procs.size());
|
||||
|
||||
//? Add tree begin symbol to first item if childless
|
||||
if (tree_procs.front().children.empty())
|
||||
tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ ");
|
||||
|
||||
//? Add tree terminator symbol to last item if childless
|
||||
if (tree_procs.back().children.empty())
|
||||
tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ ");
|
||||
|
||||
//? Final sort based on tree index
|
||||
rng::stable_sort(current_procs, rng::less{}, &proc_info::tree_index);
|
||||
rng::sort(current_procs, rng::less{}, & proc_info::tree_index);
|
||||
|
||||
//? Move current selection/view to the selected process when collapsing/expanding in the tree
|
||||
if (locate_selection) {
|
||||
int loc = rng::find(current_procs, Proc::selected_pid, &proc_info::pid)->tree_index;
|
||||
if (Config::ints.at("proc_start") >= loc or Config::ints.at("proc_start") <= loc - Proc::select_max)
|
||||
Config::ints.at("proc_start") = max(0, loc - 1);
|
||||
Config::ints.at("proc_selected") = loc - Config::ints.at("proc_start") + 1;
|
||||
}
|
||||
}
|
||||
|
||||
numpids = (int)current_procs.size() - filter_found;
|
||||
|
|
|
@ -1307,69 +1307,6 @@ namespace Proc {
|
|||
constexpr size_t KTHREADD = 2;
|
||||
static robin_hood::unordered_set<size_t> kernels_procs = {KTHREADD};
|
||||
|
||||
//* Generate process tree list
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<std::reference_wrapper<proc_info>>& out_procs, int cur_depth, const bool collapsed, const string& filter, bool found=false, const bool no_update=false, const bool should_filter=false) {
|
||||
auto cur_pos = out_procs.size();
|
||||
bool filtering = false;
|
||||
|
||||
//? If filtering, include children of matching processes
|
||||
if (not found and (should_filter or not filter.empty())) {
|
||||
if (not s_contains(std::to_string(cur_proc.pid), filter)
|
||||
and not s_contains(cur_proc.name, filter)
|
||||
and not s_contains(cur_proc.cmd, filter)
|
||||
and not s_contains(cur_proc.user, filter)) {
|
||||
filtering = true;
|
||||
cur_proc.filtered = true;
|
||||
filter_found++;
|
||||
}
|
||||
else {
|
||||
found = true;
|
||||
cur_depth = 0;
|
||||
}
|
||||
}
|
||||
else if (cur_proc.filtered) cur_proc.filtered = false;
|
||||
|
||||
//? Set tree index position for process if not filtered out or currently in a collapsed sub-tree
|
||||
if (not collapsed and not filtering) {
|
||||
out_procs.push_back(std::ref(cur_proc));
|
||||
cur_proc.tree_index = out_procs.size() - 1;
|
||||
//? Try to find name of the binary file and append to program name if not the same
|
||||
if (cur_proc.short_cmd.empty() and not cur_proc.cmd.empty()) {
|
||||
std::string_view cmd_view = cur_proc.cmd;
|
||||
cmd_view = cmd_view.substr((size_t)0, min(cmd_view.find(' '), cmd_view.size()));
|
||||
cmd_view = cmd_view.substr(min(cmd_view.find_last_of('/') + 1, cmd_view.size()));
|
||||
cur_proc.short_cmd = (string)cmd_view;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cur_proc.tree_index = in_procs.size();
|
||||
}
|
||||
|
||||
//? Recursive iteration over all children
|
||||
int children = 0;
|
||||
for (auto& p : rng::equal_range(in_procs, cur_proc.pid, rng::less{}, &proc_info::ppid)) {
|
||||
if (not no_update and not filtering and (collapsed or cur_proc.collapsed)) {
|
||||
out_procs.back().get().cpu_p += p.cpu_p;
|
||||
out_procs.back().get().mem += p.mem;
|
||||
out_procs.back().get().threads += p.threads;
|
||||
filter_found++;
|
||||
}
|
||||
if (collapsed and not filtering) {
|
||||
cur_proc.filtered = true;
|
||||
}
|
||||
else children++;
|
||||
_tree_gen(p, in_procs, out_procs, cur_depth + 1, (collapsed ? true : cur_proc.collapsed), filter, found, no_update, should_filter);
|
||||
}
|
||||
if (collapsed or filtering) return;
|
||||
|
||||
//? Add tree terminator symbol if it's the last child in a sub-tree
|
||||
if (out_procs.size() > cur_pos + 1 and not out_procs.back().get().prefix.ends_with("]─"))
|
||||
out_procs.back().get().prefix.replace(out_procs.back().get().prefix.size() - 8, 8, " └─ ");
|
||||
|
||||
//? Add collapse/expand symbols if process have any children
|
||||
out_procs.at(cur_pos).get().prefix = " │ "s * cur_depth + (children > 0 ? (cur_proc.collapsed ? "[+]─" : "[-]─") : " ├─ ");
|
||||
}
|
||||
|
||||
//* Get detailed info for selected process
|
||||
void _collect_details(const size_t pid, const uint64_t uptime, vector<proc_info>& procs) {
|
||||
fs::path pid_path = Shared::procPath / std::to_string(pid);
|
||||
|
@ -1488,6 +1425,8 @@ namespace Proc {
|
|||
string long_string;
|
||||
string short_str;
|
||||
|
||||
static vector<size_t> found;
|
||||
|
||||
const double uptime = system_uptime();
|
||||
|
||||
const int cmult = (per_core) ? Shared::coreCount : 1;
|
||||
|
@ -1502,10 +1441,11 @@ namespace Proc {
|
|||
//* ---------------------------------------------Collection start----------------------------------------------
|
||||
else {
|
||||
should_filter = true;
|
||||
found.clear();
|
||||
|
||||
//? First make sure kernel proc cache is cleared.
|
||||
if (should_filter_kernel and ++proc_clear_count >= 256) {
|
||||
//? Clearing the cache is used in the event of a pid wrap around.
|
||||
//? Clearing the cache is used in the event of a pid wrap around.
|
||||
//? In that event processes that acquire old kernel pids would also be filtered out so we need to manually clean the cache every now and then.
|
||||
kernels_procs.clear();
|
||||
kernels_procs.emplace(KTHREADD);
|
||||
|
@ -1547,7 +1487,6 @@ namespace Proc {
|
|||
pread.close();
|
||||
|
||||
//? Iterate over all pids in /proc
|
||||
vector<size_t> found;
|
||||
for (const auto& d: fs::directory_iterator(Shared::procPath)) {
|
||||
if (Runner::stopping)
|
||||
return current_procs;
|
||||
|
@ -1557,7 +1496,7 @@ namespace Proc {
|
|||
if (not isdigit(pid_str[0])) continue;
|
||||
|
||||
const size_t pid = stoul(pid_str);
|
||||
|
||||
|
||||
if (should_filter_kernel and kernels_procs.contains(pid)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1694,7 +1633,7 @@ namespace Proc {
|
|||
catch (const std::out_of_range&) { continue; }
|
||||
|
||||
pread.close();
|
||||
|
||||
|
||||
if (should_filter_kernel and new_proc.ppid == KTHREADD) {
|
||||
kernels_procs.emplace(new_proc.pid);
|
||||
found.pop_back();
|
||||
|
@ -1743,50 +1682,6 @@ namespace Proc {
|
|||
}
|
||||
//* ---------------------------------------------Collection done-----------------------------------------------
|
||||
|
||||
//* Sort processes
|
||||
if (sorted_change or not no_update) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(current_procs, rng::less{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(current_procs, rng::less{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(current_procs, rng::less{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(current_procs, rng::less{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(current_procs, rng::less{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(current_procs, rng::less{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(current_procs, rng::less{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(current_procs, rng::less{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
} else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(current_procs, rng::greater{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(current_procs, rng::greater{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(current_procs, rng::greater{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(current_procs, rng::greater{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(current_procs, rng::greater{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
|
||||
//* When sorting with "cpu lazy" push processes over threshold cpu usage to the front regardless of cumulative usage
|
||||
if (not tree and not reverse and sorting == "cpu lazy") {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, x = 0, offset = 0; i < current_procs.size(); i++) {
|
||||
if (i <= 5 and current_procs.at(i).cpu_p > max)
|
||||
max = current_procs.at(i).cpu_p;
|
||||
else if (i == 6)
|
||||
target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset and current_procs.at(i).cpu_p > 30.0)
|
||||
offset++;
|
||||
else if (current_procs.at(i).cpu_p > target) {
|
||||
rotate(current_procs.begin() + offset, current_procs.begin() + i, current_procs.begin() + i + 1);
|
||||
if (++x > 10) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Match filter if defined
|
||||
if (should_filter) {
|
||||
filter_found = 0;
|
||||
|
@ -1809,8 +1704,14 @@ namespace Proc {
|
|||
}
|
||||
}
|
||||
|
||||
//* Sort processes
|
||||
if (sorted_change or not no_update) {
|
||||
proc_sorter(current_procs, sorting, reverse, tree);
|
||||
}
|
||||
|
||||
//* Generate tree view if enabled
|
||||
if (tree and (not no_update or should_filter or sorted_change)) {
|
||||
bool locate_selection = false;
|
||||
if (auto find_pid = (collapse != -1 ? collapse : expand); find_pid != -1) {
|
||||
auto collapser = rng::find(current_procs, find_pid, &proc_info::pid);
|
||||
if (collapser != current_procs.end()) {
|
||||
|
@ -1823,24 +1724,49 @@ namespace Proc {
|
|||
else if (expand > -1) {
|
||||
collapser->collapsed = false;
|
||||
}
|
||||
if (Config::ints.at("proc_selected") > 0) locate_selection = true;
|
||||
}
|
||||
collapse = expand = -1;
|
||||
}
|
||||
if (should_filter or not filter.empty()) filter_found = 0;
|
||||
|
||||
vector<std::reference_wrapper<proc_info>> tree_procs;
|
||||
vector<tree_proc> tree_procs;
|
||||
tree_procs.reserve(current_procs.size());
|
||||
|
||||
for (auto& p : current_procs) {
|
||||
if (not v_contains(found, p.ppid)) p.ppid = 0;
|
||||
}
|
||||
|
||||
//? Stable sort to retain selected sorting among processes with the same parent
|
||||
rng::stable_sort(current_procs, rng::less{}, &proc_info::ppid);
|
||||
rng::stable_sort(current_procs, rng::less{}, & proc_info::ppid);
|
||||
|
||||
//? Start recursive iteration over processes with the lowest shared parent pids
|
||||
for (auto& p : rng::equal_range(current_procs, current_procs.at(0).ppid, rng::less{}, &proc_info::ppid)) {
|
||||
_tree_gen(p, current_procs, tree_procs, 0, false, filter, false, no_update, should_filter);
|
||||
}
|
||||
|
||||
//? Recursive sort over tree structure to account for collapsed processes in the tree
|
||||
int index = 0;
|
||||
tree_sort(tree_procs, sorting, reverse, index, current_procs.size());
|
||||
|
||||
//? Add tree begin symbol to first item if childless
|
||||
if (tree_procs.front().children.empty())
|
||||
tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ ");
|
||||
|
||||
//? Add tree terminator symbol to last item if childless
|
||||
if (tree_procs.back().children.empty())
|
||||
tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ ");
|
||||
|
||||
//? Final sort based on tree index
|
||||
rng::stable_sort(current_procs, rng::less{}, &proc_info::tree_index);
|
||||
rng::sort(current_procs, rng::less{}, & proc_info::tree_index);
|
||||
|
||||
//? Move current selection/view to the selected process when collapsing/expanding in the tree
|
||||
if (locate_selection) {
|
||||
int loc = rng::find(current_procs, Proc::selected_pid, &proc_info::pid)->tree_index;
|
||||
if (Config::ints.at("proc_start") >= loc or Config::ints.at("proc_start") <= loc - Proc::select_max)
|
||||
Config::ints.at("proc_start") = max(0, loc - 1);
|
||||
Config::ints.at("proc_selected") = loc - Config::ints.at("proc_start") + 1;
|
||||
}
|
||||
}
|
||||
|
||||
numpids = (int)current_procs.size() - filter_found;
|
||||
|
|
|
@ -1046,65 +1046,6 @@ namespace Proc {
|
|||
|
||||
detail_container detailed;
|
||||
|
||||
//* Generate process tree list
|
||||
void _tree_gen(proc_info &cur_proc, vector<proc_info> &in_procs, vector<std::reference_wrapper<proc_info>> &out_procs, int cur_depth, const bool collapsed, const string &filter, bool found = false, const bool no_update = false, const bool should_filter = false) {
|
||||
auto cur_pos = out_procs.size();
|
||||
bool filtering = false;
|
||||
|
||||
//? If filtering, include children of matching processes
|
||||
if (not found and (should_filter or not filter.empty())) {
|
||||
if (not s_contains(std::to_string(cur_proc.pid), filter) and not s_contains(cur_proc.name, filter) and not s_contains(cur_proc.cmd, filter) and not s_contains(cur_proc.user, filter)) {
|
||||
filtering = true;
|
||||
cur_proc.filtered = true;
|
||||
filter_found++;
|
||||
} else {
|
||||
found = true;
|
||||
cur_depth = 0;
|
||||
}
|
||||
} else if (cur_proc.filtered)
|
||||
cur_proc.filtered = false;
|
||||
|
||||
//? Set tree index position for process if not filtered out or currently in a collapsed sub-tree
|
||||
if (not collapsed and not filtering) {
|
||||
out_procs.push_back(std::ref(cur_proc));
|
||||
cur_proc.tree_index = out_procs.size() - 1;
|
||||
//? Try to find name of the binary file and append to program name if not the same
|
||||
if (cur_proc.short_cmd.empty() and not cur_proc.cmd.empty()) {
|
||||
std::string_view cmd_view = cur_proc.cmd;
|
||||
cmd_view = cmd_view.substr((size_t)0, min(cmd_view.find(' '), cmd_view.size()));
|
||||
cmd_view = cmd_view.substr(min(cmd_view.find_last_of('/') + 1, cmd_view.size()));
|
||||
cur_proc.short_cmd = (string)cmd_view;
|
||||
}
|
||||
} else {
|
||||
cur_proc.tree_index = in_procs.size();
|
||||
}
|
||||
|
||||
//? Recursive iteration over all children
|
||||
int children = 0;
|
||||
for (auto &p : rng::equal_range(in_procs, cur_proc.pid, rng::less{}, &proc_info::ppid)) {
|
||||
if (not no_update and not filtering and (collapsed or cur_proc.collapsed)) {
|
||||
out_procs.back().get().cpu_p += p.cpu_p;
|
||||
out_procs.back().get().mem += p.mem;
|
||||
out_procs.back().get().threads += p.threads;
|
||||
filter_found++;
|
||||
}
|
||||
if (collapsed and not filtering) {
|
||||
cur_proc.filtered = true;
|
||||
} else
|
||||
children++;
|
||||
_tree_gen(p, in_procs, out_procs, cur_depth + 1, (collapsed ? true : cur_proc.collapsed), filter, found, no_update, should_filter);
|
||||
}
|
||||
if (collapsed or filtering)
|
||||
return;
|
||||
|
||||
//? Add tree terminator symbol if it's the last child in a sub-tree
|
||||
if (out_procs.size() > cur_pos + 1 and not out_procs.back().get().prefix.ends_with("]─"))
|
||||
out_procs.back().get().prefix.replace(out_procs.back().get().prefix.size() - 8, 8, " └─ ");
|
||||
|
||||
//? Add collapse/expand symbols if process have any children
|
||||
out_procs.at(cur_pos).get().prefix = " │ "s * cur_depth + (children > 0 ? (cur_proc.collapsed ? "[+]─" : "[-]─") : " ├─ ");
|
||||
}
|
||||
|
||||
string get_status(char s) {
|
||||
if (s & SRUN) return "Running";
|
||||
if (s & SSLEEP) return "Sleeping";
|
||||
|
@ -1184,6 +1125,8 @@ namespace Proc {
|
|||
const int cmult = (per_core) ? Shared::coreCount : 1;
|
||||
bool got_detailed = false;
|
||||
|
||||
static vector<size_t> found;
|
||||
|
||||
//* Use pids from last update if only changing filter, sorting or tree options
|
||||
if (no_update and not current_procs.empty()) {
|
||||
if (show_detailed and detailed_pid != detailed.last_pid) _collect_details(detailed_pid, current_procs);
|
||||
|
@ -1211,7 +1154,7 @@ namespace Proc {
|
|||
|
||||
should_filter = true;
|
||||
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
|
||||
vector<size_t> found;
|
||||
found.clear();
|
||||
size_t size = 0;
|
||||
const auto timeNow = time_micros();
|
||||
|
||||
|
@ -1323,50 +1266,6 @@ namespace Proc {
|
|||
|
||||
//* ---------------------------------------------Collection done-----------------------------------------------
|
||||
|
||||
//* Sort processes
|
||||
if (sorted_change or not no_update) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(current_procs, rng::less{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(current_procs, rng::less{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(current_procs, rng::less{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(current_procs, rng::less{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(current_procs, rng::less{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(current_procs, rng::less{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(current_procs, rng::less{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(current_procs, rng::less{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
} else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(current_procs, rng::greater{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(current_procs, rng::greater{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(current_procs, rng::greater{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(current_procs, rng::greater{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(current_procs, rng::greater{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(current_procs, rng::greater{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
|
||||
//* When sorting with "cpu lazy" push processes over threshold cpu usage to the front regardless of cumulative usage
|
||||
if (not tree and not reverse and sorting == "cpu lazy") {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, x = 0, offset = 0; i < current_procs.size(); i++) {
|
||||
if (i <= 5 and current_procs.at(i).cpu_p > max)
|
||||
max = current_procs.at(i).cpu_p;
|
||||
else if (i == 6)
|
||||
target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset and current_procs.at(i).cpu_p > 30.0)
|
||||
offset++;
|
||||
else if (current_procs.at(i).cpu_p > target) {
|
||||
rotate(current_procs.begin() + offset, current_procs.begin() + i, current_procs.begin() + i + 1);
|
||||
if (++x > 10) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Match filter if defined
|
||||
if (should_filter) {
|
||||
filter_found = 0;
|
||||
|
@ -1384,36 +1283,69 @@ namespace Proc {
|
|||
}
|
||||
}
|
||||
|
||||
//* Sort processes
|
||||
if (sorted_change or not no_update) {
|
||||
proc_sorter(current_procs, sorting, reverse, tree);
|
||||
}
|
||||
|
||||
//* Generate tree view if enabled
|
||||
if (tree and (not no_update or should_filter or sorted_change)) {
|
||||
bool locate_selection = false;
|
||||
if (auto find_pid = (collapse != -1 ? collapse : expand); find_pid != -1) {
|
||||
auto collapser = rng::find(current_procs, find_pid, &proc_info::pid);
|
||||
if (collapser != current_procs.end()) {
|
||||
if (collapse == expand) {
|
||||
collapser->collapsed = not collapser->collapsed;
|
||||
} else if (collapse > -1) {
|
||||
}
|
||||
else if (collapse > -1) {
|
||||
collapser->collapsed = true;
|
||||
} else if (expand > -1) {
|
||||
}
|
||||
else if (expand > -1) {
|
||||
collapser->collapsed = false;
|
||||
}
|
||||
if (Config::ints.at("proc_selected") > 0) locate_selection = true;
|
||||
}
|
||||
collapse = expand = -1;
|
||||
}
|
||||
if (should_filter or not filter.empty()) filter_found = 0;
|
||||
|
||||
vector<std::reference_wrapper<proc_info>> tree_procs;
|
||||
vector<tree_proc> tree_procs;
|
||||
tree_procs.reserve(current_procs.size());
|
||||
|
||||
for (auto& p : current_procs) {
|
||||
if (not v_contains(found, p.ppid)) p.ppid = 0;
|
||||
}
|
||||
|
||||
//? Stable sort to retain selected sorting among processes with the same parent
|
||||
rng::stable_sort(current_procs, rng::less{}, &proc_info::ppid);
|
||||
rng::stable_sort(current_procs, rng::less{}, & proc_info::ppid);
|
||||
|
||||
//? Start recursive iteration over processes with the lowest shared parent pids
|
||||
for (auto &p : rng::equal_range(current_procs, current_procs.at(0).ppid, rng::less{}, &proc_info::ppid)) {
|
||||
for (auto& p : rng::equal_range(current_procs, current_procs.at(0).ppid, rng::less{}, &proc_info::ppid)) {
|
||||
_tree_gen(p, current_procs, tree_procs, 0, false, filter, false, no_update, should_filter);
|
||||
}
|
||||
|
||||
//? Recursive sort over tree structure to account for collapsed processes in the tree
|
||||
int index = 0;
|
||||
tree_sort(tree_procs, sorting, reverse, index, current_procs.size());
|
||||
|
||||
//? Add tree begin symbol to first item if childless
|
||||
if (tree_procs.front().children.empty())
|
||||
tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ ");
|
||||
|
||||
//? Add tree terminator symbol to last item if childless
|
||||
if (tree_procs.back().children.empty())
|
||||
tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ ");
|
||||
|
||||
//? Final sort based on tree index
|
||||
rng::stable_sort(current_procs, rng::less{}, &proc_info::tree_index);
|
||||
rng::sort(current_procs, rng::less{}, & proc_info::tree_index);
|
||||
|
||||
//? Move current selection/view to the selected process when collapsing/expanding in the tree
|
||||
if (locate_selection) {
|
||||
int loc = rng::find(current_procs, Proc::selected_pid, &proc_info::pid)->tree_index;
|
||||
if (Config::ints.at("proc_start") >= loc or Config::ints.at("proc_start") <= loc - Proc::select_max)
|
||||
Config::ints.at("proc_start") = max(0, loc - 1);
|
||||
Config::ints.at("proc_selected") = loc - Config::ints.at("proc_start") + 1;
|
||||
}
|
||||
}
|
||||
|
||||
numpids = (int)current_procs.size() - filter_found;
|
||||
|
|
Loading…
Reference in a new issue