Proc changes

This commit is contained in:
aristocratos 2021-05-19 23:21:56 +02:00
parent 806045c0a6
commit 098a914f4b
2 changed files with 84 additions and 36 deletions

View file

@ -19,10 +19,12 @@ tab-size = 4
#include <string> #include <string>
#include <array> #include <array>
#include <list>
#include <vector> #include <vector>
#include <thread> #include <thread>
#include <future> #include <future>
#include <atomic> #include <atomic>
#include <numeric>
#include <ranges> #include <ranges>
#include <btop_globs.h> #include <btop_globs.h>
@ -33,20 +35,27 @@ tab-size = 4
#include <btop_draw.h> #include <btop_draw.h>
#if defined(__linux__) #if defined(__linux__)
#define LINUX 1
#include <btop_linux.h> #include <btop_linux.h>
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__) #elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h> #include <sys/param.h>
#if defined(BSD) #if defined(BSD)
// #include <btop_bsd.h> // #include <btop_bsd.h>
#error BSD support not yet implemented!
#endif #endif
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h> #include <TargetConditionals.h>
#if TARGET_OS_MAC == 1 #if TARGET_OS_MAC == 1
#define OSX 1
// #include <btop_osx.h> // #include <btop_osx.h>
#error OSX support not yet implemented!
#endif #endif
#else
#error Platform not supported or could not determine platform!
#endif #endif
using std::string, std::vector, std::array, std::map, std::atomic, std::endl, std::cout, std::views::iota; using std::string, std::vector, std::array, std::map, std::atomic, std::endl, std::cout, std::views::iota, std::list, std::accumulate;
using std::flush, std::endl, std::future, std::string_literals::operator""s, std::future_status;
using namespace Tools; using namespace Tools;
@ -133,21 +142,21 @@ string my_worker(int x){
//? --------------------------------------------- Main starts here! --------------------------------------------------- //? --------------------------------------------- Main starts here! ---------------------------------------------------
int main(int argc, char **argv){ int main(int argc, char **argv){
using namespace std; // using namespace std;
//? Init //? Init
cout.setf(std::ios::boolalpha); cout.setf(std::ios::boolalpha);
if (argc > 1) argumentParser(argc, argv); if (argc > 1) argumentParser(argc, argv);
//? Init for Linux #if defined(LINUX)
if (Global::System == "linux") { //? Linux init
Global::proc_path = (fs::is_directory(fs::path("/proc"))) ? fs::path("/proc") : Global::proc_path; Global::proc_path = (fs::is_directory(fs::path("/proc"))) ? fs::path("/proc") : Global::proc_path;
if (Global::proc_path.empty()) { if (Global::proc_path.empty()) {
cout << "ERROR: Proc filesystem not detected!" << endl; cout << "ERROR: Proc filesystem not detected!" << endl;
exit(1); exit(1);
} }
} #endif
//? Initialize terminal and set options //? Initialize terminal and set options
if (!Term::init()) { if (!Term::init()) {
@ -172,19 +181,22 @@ int main(int argc, char **argv){
int debug = 0; int debug = 0;
int tests = 0; int tests = 0;
bool debuginit = false;
// cout << Theme("main_bg") << Term::clear << flush; // cout << Theme("main_bg") << Term::clear << flush;
bool thread_test = false; bool thread_test = false;
if (debug < 2) cout << Term::alt_screen << Term::hide_cursor << flush; if (!debuginit) cout << Term::alt_screen << Term::hide_cursor << flush;
cout << Theme::c("main_fg") << Theme::c("main_bg") << Term::clear << endl; cout << Theme::c("main_fg") << Theme::c("main_bg") << Term::clear << endl;
cout << Mv::r(Term::width / 2 - Global::banner_width / 2) << Global::banner << endl; cout << Mv::r(Term::width / 2 - Global::banner_width / 2) << Global::banner << endl;
// cout << string(Term::width - 1, '-') << endl; // cout << string(Term::width - 1, '-') << endl;
size_t blen = (Term::width > 200) ? 200 : Term::width;
if (Term::width > 203) cout << Mv::r(Term::width / 2 - blen / 2) << flush;
int ill = 0; int ill = 0;
for (int i : iota(0, (int)Term::width)){ for (int i : iota(0, (int)blen)){
ill = (i <= (int)Term::width / 2) ? i : ill - 1; ill = (i <= (int)blen / 2) ? i : ill - 1;
cout << Theme::g("used")[ill] << "-"; cout << Theme::g("used")[ill] << "-";
} }
cout << Fx::reset << endl; cout << Fx::reset << endl;
@ -234,7 +246,7 @@ int main(int argc, char **argv){
while (outputs.size() < 10){ while (outputs.size() < 10){
for (int i : iota(0, 10)){ for (int i : iota(0, 10)){
if (runners[i].valid() && runners[i].wait_for(chrono::milliseconds(10)) == future_status::ready) { if (runners[i].valid() && runners[i].wait_for(std::chrono::milliseconds(10)) == future_status::ready) {
outputs[i] = runners[i].get(); outputs[i] = runners[i].get();
cout << "Thread " << i << " : " << outputs[i] << endl; cout << "Thread " << i << " : " << outputs[i] << endl;
} }
@ -271,7 +283,8 @@ int main(int argc, char **argv){
uint lc; uint lc;
string ostring; string ostring;
uint64_t tsl, timestamp2; uint64_t tsl, timestamp2;
uint timer = 2000; list<uint64_t> avgtimes;
uint timer = 1000;
bool filtering = false; bool filtering = false;
bool reversing = false; bool reversing = false;
int sortint = Proc::sort_map["cpu lazy"]; int sortint = Proc::sort_map["cpu lazy"];
@ -300,7 +313,7 @@ int main(int argc, char **argv){
lc = 0; lc = 0;
filter_cur = (filtering) ? Fx::bl + "" + Fx::reset : ""; filter_cur = (filtering) ? Fx::bl + "" + Fx::reset : "";
ostring = Mv::save + Mv::u(2) + Mv::r(20) + trans(rjust("Filter: " + filter + filter_cur + string(Term::width / 3, ' ') + ostring = Mv::save + Mv::u(2) + Mv::r(20) + trans(rjust("Filter: " + filter + filter_cur + string(Term::width / 3, ' ') +
"Sorting: " + string(Proc::sort_array[sortint]), Term::width - 25, true, filtering)) + Mv::restore; "Sorting: " + string(Proc::sort_array[sortint]), Term::width - 25, true, filtering)) + Mv::restore;
for (auto& p : plist){ for (auto& p : plist){
ostring += Mv::r(1) + greyscale[lc] + rjust(to_string(p.pid), 8) + " " + ljust(p.name, 16) + " " + ljust(p.cmd, Term::width - 66, true) + " " + ostring += Mv::r(1) + greyscale[lc] + rjust(to_string(p.pid), 8) + " " + ljust(p.name, 16) + " " + ljust(p.cmd, Term::width - 66, true) + " " +
@ -310,8 +323,11 @@ int main(int argc, char **argv){
if (lc++ > Term::height - 21) break; if (lc++ > Term::height - 21) break;
} }
avgtimes.push_front(timestamp);
if (avgtimes.size() > 100) avgtimes.pop_back();
cout << pbox << ostring << Fx::reset << "\n" << endl; cout << pbox << ostring << Fx::reset << "\n" << endl;
cout << "Processes call took: " << timestamp << "ms. Drawing took: " << time_ms() - timestamp2 << "ms." << endl; cout << Mv::to(Term::height - 4, 1) << "Processes call took: " << timestamp << "ms. Average: " << accumulate(avgtimes.begin(), avgtimes.end(), 0) / avgtimes.size() <<
"ms of " << avgtimes.size() << " samples. Drawing took: " << time_ms() - timestamp2 << "ms. " << endl;
while (time_ms() < tsl) { while (time_ms() < tsl) {
if (Input::poll(tsl - time_ms())) key = Input::get(); if (Input::poll(tsl - time_ms())) key = Input::get();
@ -413,6 +429,6 @@ int main(int argc, char **argv){
if (debug == 1) Input::wait(); if (debug == 1) Input::wait();
Term::restore(); Term::restore();
if (debug < 2) cout << Term::normal_screen << Term::show_cursor << flush; if (!debuginit) cout << Term::normal_screen << Term::show_cursor << flush;
return 0; return 0;
} }

View file

@ -21,12 +21,15 @@ tab-size = 4
#include <string> #include <string>
#include <vector> #include <vector>
#include <deque>
#include <array> #include <array>
#include <unordered_map> #include <unordered_map>
#include <atomic> #include <atomic>
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include <ranges> #include <ranges>
#include <list>
#include <unistd.h> #include <unistd.h>
@ -35,7 +38,7 @@ tab-size = 4
#include <btop_tools.h> #include <btop_tools.h>
using std::string, std::vector, std::array, std::ifstream, std::atomic, std::numeric_limits, std::streamsize, std::unordered_map; using std::string, std::vector, std::array, std::ifstream, std::atomic, std::numeric_limits, std::streamsize, std::unordered_map, std::deque, std::list;
namespace fs = std::filesystem; namespace fs = std::filesystem;
using namespace Tools; using namespace Tools;
@ -61,6 +64,7 @@ double system_uptime(){
namespace Proc { namespace Proc {
namespace { namespace {
uint64_t tstamp; uint64_t tstamp;
size_t numpids = 500;
long int clk_tck; long int clk_tck;
struct p_cache { struct p_cache {
string name, cmd, user; string name, cmd, user;
@ -89,7 +93,7 @@ namespace Proc {
}; };
unordered_map<string, uint> sort_map; unordered_map<string, uint> sort_map;
//* proc_info: pid, name, cmd, threads, user, mem, cpu_p, cpu_c //* proc_info: pid, name, cmd, threads, user, mem, cpu_p, cpu_c, state, tty, cpu_n, p_nice, ppid
struct proc_info { struct proc_info {
uint pid; uint pid;
string name, cmd; string name, cmd;
@ -97,16 +101,21 @@ namespace Proc {
string user; string user;
uint64_t mem; uint64_t mem;
double cpu_p, cpu_c; double cpu_p, cpu_c;
char state;
int cpu_n, p_nice;
uint ppid;
}; };
//* Collects process information from /proc and returns a vector of proc_info structs //* Collects process information from /proc and returns a vector of proc_info structs
auto collect(string sorting="pid", bool reverse=false, string filter=""){ auto collect(string sorting="pid", bool reverse=false, string filter=""){
running.store(true); running.store(true);
uint pid; uint pid, ppid;
uint64_t cpu_t, rss_mem; uint64_t cpu_t, rss_mem;
double cpu, cpu_s; double cpu, cpu_s;
bool new_cache; bool new_cache;
char state;
int cpu_n, p_nice;
size_t threads; size_t threads;
ifstream pread; ifstream pread;
string pid_str, name, cmd, attr, user, instr, uid, status, tmpstr; string pid_str, name, cmd, attr, user, instr, uid, status, tmpstr;
@ -115,8 +124,13 @@ namespace Proc {
auto uptime = system_uptime(); auto uptime = system_uptime();
auto sortint = (sort_map.contains(sorting)) ? sort_map[sorting] : 7; auto sortint = (sort_map.contains(sorting)) ? sort_map[sorting] : 7;
vector<string> pstat; vector<string> pstat;
pstat.reserve(40);
vector<proc_info> procs; vector<proc_info> procs;
procs.reserve((numpids + 10));
vector<uint> c_pids; vector<uint> c_pids;
c_pids.reserve((numpids + 10));
numpids = 0;
uint parenthesis = 0;
//* Update uid_user map if /etc/passwd changed since last run //* Update uid_user map if /etc/passwd changed since last run
if (!passwd_path.empty() && fs::last_write_time(passwd_path) != passwd_time) { if (!passwd_path.empty() && fs::last_write_time(passwd_path) != passwd_time) {
@ -146,9 +160,10 @@ namespace Proc {
stop.store(false); stop.store(false);
return procs; return procs;
} }
numpids++;
pid_str = fs::path(d.path()).filename(); pid_str = fs::path(d.path()).filename();
cpu = 0.0; cpu_s = 0.0; cpu_t = 0; cpu = 0.0; cpu_s = 0.0; cpu_t = 0; cpu_n = 0;
rss_mem = 0; threads = 0; rss_mem = 0; threads = 0; state = '0'; ppid = 0; p_nice = 0;
new_cache = false; new_cache = false;
if (d.is_directory() && isdigit(pid_str[0])) { if (d.is_directory() && isdigit(pid_str[0])) {
pid = stoul(pid_str); pid = stoul(pid_str);
@ -194,27 +209,47 @@ namespace Proc {
//* Get cpu usage, cpu cumulative and threads from /proc/[pid]/stat //* Get cpu usage, cpu cumulative and threads from /proc/[pid]/stat
if (fs::exists((string)d.path() + "/stat")) { if (fs::exists((string)d.path() + "/stat")) {
pread.clear(); pstat.clear(); pread.clear(); instr.clear(); pstat.clear(); pstat.reserve(40); pstat.resize(3, "");
ifstream pread((string)d.path() + "/stat"); ifstream pread((string)d.path() + "/stat");
if (pread.good()) while (getline(pread, instr, ' ')) pstat.push_back(instr); if (pread.good()) {
parenthesis = 1;
pread.ignore(numeric_limits<streamsize>::max(), '(');
while (parenthesis > 0 && !pread.eof()) {
instr = pread.get();
if (instr == "(") ++parenthesis;
else if (instr == ")") --parenthesis;
}
pread.ignore(1);
while (getline(pread, instr, ' ') && pstat.size() < 40) pstat.push_back(instr);
}
pread.close(); pread.close();
if (pstat.size() < 37) continue; if (pstat.size() < 22) continue;
//? Process state
state = pstat[3][0];
//? Process parent pid
ppid = stoul(pstat[4]);
//? Process nice value
p_nice = stoi(pstat[19]);
//? Process number of threads //? Process number of threads
threads = stoul(pstat[19]); threads = stoul(pstat[20]);
//? Process utime + stime //? Process utime + stime
cpu_t = stoull(pstat[13]) + stoull(pstat[14]); cpu_t = stoull(pstat[14]) + stoull(pstat[15]);
//? Cache cpu times and cpu seconds //? Cache cpu times and cpu seconds
if (new_cache) { if (new_cache) {
cache[pid].cpu_t = cpu_t; cache[pid].cpu_t = cpu_t;
cache[pid].cpu_s = stoull(pstat[21]); cache[pid].cpu_s = stoull(pstat[22]);
} }
//? Cache process start time //? CPU number last executed on
// if (!cpu_second.contains(pid)) cpu_second[pid] = stoull(pstat[21]); if (pstat.size() > 39) cpu_n = stoi(pstat[39]);
//? Process cpu usage since last update, 100'000 because (100 percent * 1000 milliseconds) for correct conversion //? Process cpu usage since last update, 100'000 because (100 percent * 1000 milliseconds) for correct conversion
cpu = static_cast<double>(100000 * (cpu_t - cache[pid].cpu_t) / since_last) / clk_tck; cpu = static_cast<double>(100000 * (cpu_t - cache[pid].cpu_t) / since_last) / clk_tck;
@ -228,7 +263,7 @@ namespace Proc {
//* Get RSS memory in bytes from /proc/[pid]/statm //* Get RSS memory in bytes from /proc/[pid]/statm
if (fs::exists((string)d.path() + "/statm")) { if (fs::exists((string)d.path() + "/statm")) {
pread.clear(); tmpstr.clear(); pread.clear();
ifstream pread((string)d.path() + "/statm"); ifstream pread((string)d.path() + "/statm");
if (pread.good()) { if (pread.good()) {
pread.ignore(numeric_limits<streamsize>::max(), ' '); pread.ignore(numeric_limits<streamsize>::max(), ' ');
@ -238,22 +273,19 @@ namespace Proc {
pread.close(); pread.close();
} }
//* Match filter if defined
// //* Match filter if applicable
if (!filter.empty() && if (!filter.empty() &&
pid_str.find(filter) == string::npos && //? Pid pid_str.find(filter) == string::npos &&
cache[pid].name.find(filter) == string::npos && //? Program cache[pid].name.find(filter) == string::npos &&
cache[pid].cmd.find(filter) == string::npos && //? Command cache[pid].cmd.find(filter) == string::npos &&
cache[pid].user.find(filter) == string::npos //? User cache[pid].user.find(filter) == string::npos
) continue; ) continue;
//* Create proc_info //* Create proc_info
procs.push_back(proc_info(pid, cache[pid].name, cache[pid].cmd, threads, cache[pid].user, rss_mem, cpu, cpu_s)); procs.push_back(proc_info(pid, cache[pid].name, cache[pid].cmd, threads, cache[pid].user, rss_mem, cpu, cpu_s, state, cpu_n, p_nice, ppid));
} }
} }
// auto st = time_ms();
//* Sort processes vector //* Sort processes vector
std::ranges::sort(procs, [&sortint, &reverse](proc_info& a, proc_info& b) std::ranges::sort(procs, [&sortint, &reverse](proc_info& a, proc_info& b)