btop/src/btop.cpp

647 lines
19 KiB
C++
Raw Normal View History

2021-05-07 06:32:03 +12:00
/* 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 <string>
#include <array>
2021-05-20 09:21:56 +12:00
#include <list>
2021-05-07 06:32:03 +12:00
#include <vector>
2021-06-10 05:47:49 +12:00
#include <csignal>
2021-05-07 06:32:03 +12:00
#include <thread>
#include <future>
#include <atomic>
2021-05-20 09:21:56 +12:00
#include <numeric>
#include <ranges>
2021-05-22 12:13:56 +12:00
#include <filesystem>
#include <unistd.h>
2021-05-29 12:32:36 +12:00
#include <robin_hood.h>
#include <cmath>
2021-06-20 08:48:31 +12:00
#include <iostream>
#include <exception>
2021-05-24 08:25:07 +12:00
2021-06-20 10:49:13 +12:00
#include <btop_shared.hpp>
2021-06-20 08:48:31 +12:00
#include <btop_tools.hpp>
#include <btop_config.hpp>
#include <btop_input.hpp>
#include <btop_theme.hpp>
#include <btop_draw.hpp>
#include <btop_menu.hpp>
2021-05-09 00:56:48 +12:00
#if defined(__linux__)
2021-06-10 05:47:49 +12:00
#define LINUX
2021-06-22 08:52:55 +12:00
#elif defined(__unix__) or not defined(__APPLE__) and defined(__MACH__)
2021-05-09 00:56:48 +12:00
#include <sys/param.h>
#if defined(BSD)
2021-05-20 09:21:56 +12:00
#error BSD support not yet implemented!
2021-05-09 00:56:48 +12:00
#endif
2021-06-22 08:52:55 +12:00
#elif defined(__APPLE__) and defined(__MACH__)
2021-05-09 00:56:48 +12:00
#include <TargetConditionals.h>
#if TARGET_OS_MAC == 1
2021-06-10 05:47:49 +12:00
#define OSX
2021-05-20 09:21:56 +12:00
#error OSX support not yet implemented!
2021-05-09 00:56:48 +12:00
#endif
2021-05-20 09:21:56 +12:00
#else
2021-05-24 08:25:07 +12:00
#error Platform not supported!
2021-05-09 00:56:48 +12:00
#endif
2021-05-07 06:32:03 +12:00
namespace Global {
const std::vector<std::array<std::string, 2>> Banner_src = {
{"#E62525", "██████╗ ████████╗ ██████╗ ██████╗"},
{"#CD2121", "██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ██╗ ██╗"},
{"#B31D1D", "██████╔╝ ██║ ██║ ██║██████╔╝ ██████╗██████╗"},
{"#9A1919", "██╔══██╗ ██║ ██║ ██║██╔═══╝ ╚═██╔═╝╚═██╔═╝"},
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
};
2021-06-26 09:58:19 +12:00
const std::string Version = "0.0.30";
int coreCount;
}
2021-05-29 12:32:36 +12:00
using std::string, std::vector, std::array, robin_hood::unordered_flat_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, std::to_string, std::round;
2021-05-22 12:13:56 +12:00
namespace fs = std::filesystem;
namespace rng = std::ranges;
using namespace Tools;
2021-05-07 06:32:03 +12:00
2021-05-09 00:56:48 +12:00
namespace Global {
2021-05-15 04:54:37 +12:00
string banner;
2021-06-03 07:33:26 +12:00
size_t banner_width = 0;
2021-05-29 12:32:36 +12:00
fs::path self_path;
bool debuginit = false;
bool debug = false;
uint64_t start_time;
atomic<bool> resized (false);
atomic<bool> quitting (false);
bool arg_tty = false;
2021-06-22 08:52:55 +12:00
bool arg_low_color = false;
2021-05-09 00:56:48 +12:00
}
2021-05-07 06:32:03 +12:00
2021-05-09 00:56:48 +12:00
//* A simple argument parser
2021-05-08 12:38:51 +12:00
void argumentParser(int argc, char **argv){
string argument;
for(int i = 1; i < argc; i++) {
argument = argv[i];
2021-06-22 08:52:55 +12:00
if (argument == "-v" or argument == "--version") {
2021-05-09 00:56:48 +12:00
cout << "btop version: " << Global::Version << endl;
2021-05-08 12:38:51 +12:00
exit(0);
2021-05-29 12:32:36 +12:00
}
2021-06-22 08:52:55 +12:00
else if (argument == "-h" or argument == "--help") {
cout << "usage: btop [-h] [-v] [-/+t] [--debug]\n\n"
<< "optional arguments:\n"
2021-06-22 08:52:55 +12:00
<< " -h, --help show this help message and exit\n"
<< " -v, --version show version info and exit\n"
<< " -lc, --low-color disable truecolor, converts 24-bit colors to 256-color\n"
<< " -t, --tty_on force (ON) tty mode, max 16 colors and tty friendly graph symbols\n"
<< " +t, --tty_off force (OFF) tty mode\n"
<< " --debug start with loglevel set to DEBUG, overriding value set in config\n"
<< endl;
2021-05-08 12:38:51 +12:00
exit(0);
2021-05-29 12:32:36 +12:00
}
else if (argument == "--debug")
Global::debug = true;
2021-06-22 08:52:55 +12:00
else if (argument == "-t" or argument == "--tty_on") {
Config::set("tty_mode", true);
Global::arg_tty = true;
}
2021-06-22 08:52:55 +12:00
else if (argument == "+t" or argument == "--tty_off") {
Config::set("tty_mode", false);
Global::arg_tty = true;
}
2021-06-22 08:52:55 +12:00
else if (argument == "-lc" or argument == "--low-color") {
Global::arg_low_color = true;
}
2021-05-29 12:32:36 +12:00
else {
2021-05-08 12:38:51 +12:00
cout << " Unknown argument: " << argument << "\n" <<
" Use -h or --help for help." << endl;
exit(1);
}
}
}
//* Handler for SIGWINCH and general resizing events
void _resize(bool force=false){
if (Term::refresh(false) or force) {
Global::resized = true;
if (Runner::active) {
Runner::stop = true;
atomic_wait(Runner::active);
}
Term::refresh();
}
else return;
while (true) {
sleep_ms(100);
if (not Term::refresh()) break;
}
Input::interrupt = true;
Draw::calcSizes();
}
//* Exit handler; stops threads, restores terminal and saves config changes
void clean_quit(int sig=-1){
2021-06-03 07:33:26 +12:00
if (Global::quitting) return;
Global::quitting = true;
if (Runner::active) {
Runner::stop = true;
atomic_wait(Runner::active);
}
2021-06-03 07:33:26 +12:00
if (Term::initialized) {
Term::restore();
2021-06-22 08:52:55 +12:00
if (not Global::debuginit) cout << Term::normal_screen << Term::show_cursor << flush;
2021-06-03 07:33:26 +12:00
}
2021-06-10 05:47:49 +12:00
Config::write();
2021-06-14 09:12:11 +12:00
Logger::info("Quitting! Runtime: " + sec_to_dhms(time_s() - Global::start_time));
2021-06-10 05:47:49 +12:00
if (sig != -1) exit(sig);
}
//* Handler for SIGTSTP; stops threads, restores terminal and sends SIGSTOP
void _sleep(){
if (Runner::active) {
Runner::stop = true;
atomic_wait(Runner::active);
}
2021-06-10 05:47:49 +12:00
if (Term::initialized) {
Term::restore();
2021-06-22 08:52:55 +12:00
if (not Global::debuginit) cout << Term::normal_screen << Term::show_cursor << flush;
2021-06-10 05:47:49 +12:00
}
std::raise(SIGSTOP);
}
//* Handler for SIGCONT; re-initialize terminal and force a resize event
void _resume(){
2021-06-10 05:47:49 +12:00
Term::init();
2021-06-22 08:52:55 +12:00
if (not Global::debuginit) cout << Term::alt_screen << Term::hide_cursor << flush;
_resize(true);
2021-06-03 07:33:26 +12:00
}
void _exit_handler() {
clean_quit(-1);
}
2021-06-03 07:33:26 +12:00
2021-06-10 05:47:49 +12:00
void _signal_handler(int sig) {
switch (sig) {
case SIGINT:
clean_quit(0);
break;
case SIGTSTP:
_sleep();
2021-06-10 05:47:49 +12:00
break;
case SIGCONT:
_resume();
break;
case SIGWINCH:
_resize();
2021-06-10 05:47:49 +12:00
break;
}
}
2021-06-03 07:33:26 +12:00
//? Generate the btop++ banner
void banner_gen() {
2021-06-05 11:41:24 +12:00
size_t z = 0;
2021-06-03 07:33:26 +12:00
string b_color, bg, fg, oc, letter;
2021-06-22 08:52:55 +12:00
auto& lowcolor = Config::getB("lowcolor");
2021-05-15 04:54:37 +12:00
int bg_i;
2021-06-03 07:33:26 +12:00
Global::banner.clear();
Global::banner_width = 0;
auto tty_mode = (Config::getB("tty_mode"));
2021-05-15 04:54:37 +12:00
for (auto line: Global::Banner_src) {
2021-06-05 11:41:24 +12:00
if (auto w = ulen(line[1]); w > Global::banner_width) Global::banner_width = w;
2021-06-22 08:52:55 +12:00
if (tty_mode) {
fg = (z > 2) ? "\x1b[31m" : "\x1b[91m";
bg = (z > 2) ? "\x1b[90m" : "\x1b[37m";
}
else {
fg = Theme::hex_to_color(line[0], lowcolor);
bg_i = 120 - z * 12;
bg = Theme::dec_to_color(bg_i, bg_i, bg_i, lowcolor);
}
for (size_t i = 0; i < line[1].size(); i += 3) {
if (line[1][i] == ' ') {
2021-05-15 04:54:37 +12:00
letter = ' ';
i -= 2;
2021-05-07 06:32:03 +12:00
}
else
letter = line[1].substr(i, 3);
2021-06-22 08:52:55 +12:00
// if (tty_mode and letter != "█" and letter != " ") letter = "░";
2021-05-15 04:54:37 +12:00
b_color = (letter == "") ? fg : bg;
2021-06-03 07:33:26 +12:00
if (b_color != oc) Global::banner += b_color;
Global::banner += letter;
2021-05-15 04:54:37 +12:00
oc = b_color;
2021-05-07 06:32:03 +12:00
}
2021-06-03 07:33:26 +12:00
if (++z < Global::Banner_src.size()) Global::banner += Mv::l(ulen(line[1])) + Mv::d(1);
2021-05-07 06:32:03 +12:00
}
2021-06-22 08:52:55 +12:00
Global::banner += Mv::r(18 - Global::Version.size())
+ (tty_mode ? "\x1b[0;40;37m" : Theme::dec_to_color(0,0,0, lowcolor, "bg") + Theme::dec_to_color(150, 150, 150, lowcolor))
+ Fx::i + "v" + Global::Version + Fx::ui;
2021-05-15 04:54:37 +12:00
}
2021-05-07 06:32:03 +12:00
namespace Runner {
atomic<bool> active (false);
atomic<bool> stop (false);
}
2021-05-10 08:25:41 +12:00
2021-05-09 00:56:48 +12:00
2021-05-07 06:32:03 +12:00
//? --------------------------------------------- Main starts here! ---------------------------------------------------
int main(int argc, char **argv){
//? Init
2021-05-29 12:32:36 +12:00
Global::start_time = time_s();
2021-05-08 12:38:51 +12:00
cout.setf(std::ios::boolalpha);
2021-05-07 06:32:03 +12:00
if (argc > 1) argumentParser(argc, argv);
2021-05-29 12:32:36 +12:00
std::atexit(_exit_handler);
2021-06-10 05:47:49 +12:00
std::at_quick_exit(_exit_handler);
std::signal(SIGINT, _signal_handler);
std::signal(SIGTSTP, _signal_handler);
std::signal(SIGCONT, _signal_handler);
std::signal(SIGWINCH, _signal_handler);
2021-05-29 12:32:36 +12:00
2021-06-06 11:41:36 +12:00
//? Linux init
2021-05-20 09:21:56 +12:00
#if defined(LINUX)
2021-06-05 11:41:24 +12:00
Global::coreCount = sysconf(_SC_NPROCESSORS_ONLN);
if (Global::coreCount < 1) Global::coreCount = 1;
2021-05-29 12:32:36 +12:00
{
std::error_code ec;
Global::self_path = fs::read_symlink("/proc/self/exe", ec).remove_filename();
}
2021-05-20 09:21:56 +12:00
#endif
2021-05-14 07:11:10 +12:00
//? Setup paths for config, log and themes
for (auto env : {"XDG_CONFIG_HOME", "HOME"}) {
2021-06-22 08:52:55 +12:00
if (getenv(env) != NULL and access(getenv(env), W_OK) != -1) {
2021-05-29 12:32:36 +12:00
Config::conf_dir = fs::path(getenv(env)) / (((string)env == "HOME") ? ".config/btop" : "btop");
break;
}
}
2021-06-22 08:52:55 +12:00
if (not Config::conf_dir.empty()) {
if (std::error_code ec; not fs::is_directory(Config::conf_dir) and not fs::create_directories(Config::conf_dir, ec)) {
cout << "WARNING: Could not create or access btop config directory. Logging and config saving disabled." << endl;
2021-05-29 12:32:36 +12:00
cout << "Make sure your $HOME environment variable is correctly set to fix this." << endl;
}
else {
2021-05-29 12:32:36 +12:00
Config::conf_file = Config::conf_dir / "btop.conf";
Logger::logfile = Config::conf_dir / "btop.log";
Theme::user_theme_dir = Config::conf_dir / "themes";
2021-06-22 08:52:55 +12:00
if (not fs::exists(Theme::user_theme_dir) and not fs::create_directory(Theme::user_theme_dir, ec)) Theme::user_theme_dir.clear();
}
}
2021-06-22 08:52:55 +12:00
if (std::error_code ec; not Global::self_path.empty()) {
2021-05-29 12:32:36 +12:00
Theme::theme_dir = fs::canonical(Global::self_path / "../share/btop/themes", ec);
if (ec or not fs::is_directory(Theme::theme_dir) or access(Theme::theme_dir.c_str(), R_OK) == -1) Theme::theme_dir.clear();
2021-05-29 12:32:36 +12:00
}
if (Theme::theme_dir.empty()) {
for (auto theme_path : {"/usr/local/share/btop/themes", "/usr/share/btop/themes"}) {
if (fs::is_directory(fs::path(theme_path)) and access(theme_path, R_OK) != -1) {
2021-05-29 12:32:36 +12:00
Theme::theme_dir = fs::path(theme_path);
break;
}
}
}
2021-06-14 09:12:11 +12:00
//? Config init
2021-06-13 04:49:27 +12:00
{ vector<string> load_errors;
Config::load(Config::conf_file, load_errors);
2021-06-22 08:52:55 +12:00
Config::set("lowcolor", (Global::arg_low_color ? true : not Config::getB("truecolor")));
if (Global::debug) Logger::set("DEBUG");
else Logger::set(Config::getS("log_level"));
2021-06-13 04:49:27 +12:00
2021-06-22 08:52:55 +12:00
Logger::info("Logger set to " + Config::getS("log_level"));
2021-06-13 04:49:27 +12:00
2021-06-14 09:12:11 +12:00
for (auto& err_str : load_errors) Logger::warning(err_str);
2021-06-13 04:49:27 +12:00
}
2021-05-24 08:25:07 +12:00
2021-06-22 08:52:55 +12:00
if (not string(getenv("LANG")).ends_with("UTF-8") and not string(getenv("LANG")).ends_with("utf-8")) {
string err_msg = "No UTF-8 locale was detected! Symbols might not look as intended.\n"
"Make sure your $LANG evironment variable is set and with a UTF-8 locale.";
2021-05-24 08:25:07 +12:00
Logger::warning(err_msg);
cout << "WARNING: " << err_msg << endl;
}
2021-05-09 10:18:51 +12:00
//? Initialize terminal and set options
2021-06-22 08:52:55 +12:00
if (not Term::init()) {
2021-06-06 11:41:36 +12:00
string err_msg = "No tty detected!\nbtop++ needs an interactive shell to run.";
Logger::error(err_msg);
2021-05-24 08:25:07 +12:00
cout << "ERROR: " << err_msg << endl;
2021-05-29 12:32:36 +12:00
clean_quit(1);
2021-05-07 06:32:03 +12:00
}
2021-06-22 08:52:55 +12:00
Logger::info("Running on " + Term::current_tty);
if (not Global::arg_tty and Config::getB("force_tty")) {
Config::set("tty_mode", true);
Logger::info("Forcing tty mode: setting 16 color mode and using tty friendly graph symbols");
}
2021-06-22 08:52:55 +12:00
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");
}
2021-06-26 09:58:19 +12:00
//? Platform init and error check
Shared::init();
2021-06-05 11:41:24 +12:00
2021-06-13 04:49:27 +12:00
2021-06-06 11:41:36 +12:00
// Config::set("truecolor", false);
2021-05-09 10:18:51 +12:00
2021-06-26 09:58:19 +12:00
auto thts = time_micros();
2021-06-26 09:58:19 +12:00
//? Update theme list and generate the theme
Theme::updateThemes();
Theme::setTheme();
2021-05-09 10:18:51 +12:00
//? Create the btop++ banner
2021-06-03 07:33:26 +12:00
banner_gen();
2021-05-09 10:18:51 +12:00
2021-05-08 12:38:51 +12:00
2021-05-09 10:18:51 +12:00
//* ------------------------------------------------ TESTING ------------------------------------------------------
Global::debuginit = false;
2021-05-24 08:25:07 +12:00
Draw::calcSizes();
2021-05-07 06:32:03 +12:00
if (not Global::debuginit) cout << Term::alt_screen << Term::hide_cursor << Term::clear << endl;
2021-05-10 08:25:41 +12:00
cout << Cpu::box << Mem::box << Net::box << Proc::box << flush;
2021-05-07 06:32:03 +12:00
if (false) {
Draw::calcSizes();
cout << Cpu::box << Mem::box << Net::box << Proc::box << flush;
Input::wait();
exit(0);
}
2021-05-08 12:38:51 +12:00
// if (true) {
// cout << Term::clear << flush;
// unordered_flat_map<string, string(*)(string)> korvs = {
// {"korv1", korv1},
// {"korv2", korv2},
// };
// // auto hej = korv1;
// cout << korvs["korv1"]("hejsan") << endl;
// cout << korvs["korv2"]("hejsan igen") << endl;
// exit(0);
// }
2021-06-26 09:58:19 +12:00
//* Test theme
if (false) {
2021-06-26 09:58:19 +12:00
string key;
bool no_redraw = false;
auto theme_index = v_index(Theme::themes, Config::getS("color_theme"));
while (key != "q") {
key.clear();
if (not no_redraw) {
cout << "\nTheme generation of " << fs::path(Config::getS("color_theme")).filename().replace_extension("") << " took " << time_micros() - thts << "μs" << endl;
cout << "Colors:" << endl;
size_t i = 0;
2021-06-26 09:58:19 +12:00
for(auto& item : Theme::test_colors()) {
cout << rjust(item.first, 15) << ":" << item.second << ""s * 10 << Fx::reset << " ";
if (++i == 4) {
i = 0;
cout << endl;
}
}
cout << Fx::reset << endl;
cout << "Gradients:";
for (auto& [name, cvec] : Theme::test_gradients()) {
cout << endl << rjust(name + ":", 10);
for (auto& color : cvec) {
cout << color << "";
}
cout << Fx::reset << endl;
}
}
no_redraw = true;
key = Input::wait();
if (key.empty()) continue;
thts = time_micros();
if (key == "right") {
if (theme_index == Theme::themes.size() - 1) theme_index = 0;
else theme_index++;
}
else if (key == "left") {
if (theme_index == 0) theme_index = Theme::themes.size() - 1;
else theme_index--;
}
2021-06-26 09:58:19 +12:00
else continue;
no_redraw = false;
Config::set("color_theme", Theme::themes.at(theme_index));
Theme::setTheme();
}
exit(0);
2021-05-08 12:38:51 +12:00
}
2021-05-29 12:32:36 +12:00
2021-06-23 05:19:14 +12:00
if (false) {
2021-05-30 12:15:09 +12:00
deque<long long> mydata;
2021-05-30 12:15:09 +12:00
for (long long i = 0; i <= 100; i++) mydata.push_back(i);
for (long long i = 100; i >= 0; i--) mydata.push_back(i);
2021-06-03 07:33:26 +12:00
mydata.push_back(50);
2021-05-30 12:15:09 +12:00
2021-05-31 03:01:57 +12:00
Draw::Graph kgraph {};
Draw::Graph kgraph2 {};
Draw::Graph kgraph3 {};
cout << Draw::createBox(5, 10, Term::width - 10, 12, Theme::c("proc_box"), false, "braille", "", 1) << Mv::save;
cout << Draw::createBox(5, 23, Term::width - 10, 12, Theme::c("proc_box"), false, "block", "", 2);
cout << Draw::createBox(5, 36, Term::width - 10, 12, Theme::c("proc_box"), false, "tty", "", 3) << flush;
2021-05-31 03:01:57 +12:00
auto kts = time_micros();
kgraph(Term::width - 13, 10, "cpu", mydata, "braille", false, false);
kgraph2(Term::width - 13, 10, "cpu", mydata, "block", false, false);
kgraph3(Term::width - 13, 10, "cpu", mydata, "tty", false, false);
2021-06-01 07:47:41 +12:00
2021-05-31 03:01:57 +12:00
cout << Mv::restore << kgraph(mydata, true)
<< Mv::restore << Mv::d(13) << kgraph2(mydata, true)
<< Mv::restore << Mv::d(26) << kgraph3(mydata, true) << '\n'
<< Mv::d(1) << "Init took " << time_micros() - kts << " μs. " << endl;
2021-05-30 12:15:09 +12:00
list<uint64_t> ktavg;
2021-05-31 03:01:57 +12:00
while (true) {
2021-06-03 07:33:26 +12:00
mydata.back() = std::rand() % 101;
2021-05-30 12:15:09 +12:00
kts = time_micros();
cout << Term::sync_start << Mv::restore << kgraph(mydata)
<< Mv::restore << Mv::d(13) << kgraph2(mydata)
<< Mv::restore << Mv::d(26) << kgraph3(mydata)
<< Term::sync_end << endl;
2021-05-30 12:15:09 +12:00
ktavg.push_front(time_micros() - kts);
if (ktavg.size() > 100) ktavg.pop_back();
2021-06-03 07:33:26 +12:00
cout << Mv::d(1) << "Time: " << ktavg.front() << " μs. Avg: " << accumulate(ktavg.begin(), ktavg.end(), 0) / ktavg.size() << " μs. " << flush;
2021-05-31 03:01:57 +12:00
if (Input::poll()) {
2021-06-26 09:58:19 +12:00
if (Input::get() == "space") Input::wait();
2021-05-31 03:01:57 +12:00
else break;
}
2021-06-22 08:52:55 +12:00
sleep_ms(50);
2021-05-30 12:15:09 +12:00
}
Input::get();
exit(0);
}
2021-05-28 08:29:36 +12:00
2021-06-13 04:49:27 +12:00
if (false) {
cout << Config::getS("log_level") << endl;
vector<string> vv = {"hej", "vad", "du"};
vector<int> vy;
cout << v_contains(vv, "vad"s) << endl;
cout << v_index(vv, "hej"s) << endl;
cout << v_index(vv, "du"s) << endl;
cout << v_index(vv, "kodkod"s) << endl;
cout << v_index(vy, 4) << endl;
exit(0);
}
2021-05-22 12:13:56 +12:00
//*------>>>>>> Proc testing
2021-05-11 09:46:41 +12:00
2021-05-10 08:25:41 +12:00
auto timestamp = time_ms();
2021-05-11 09:46:41 +12:00
2021-05-10 08:25:41 +12:00
string ostring;
2021-05-22 12:13:56 +12:00
uint64_t tsl, timestamp2, rcount = 0;
list<uint64_t> avgtimes;
size_t timer = 2000;
vector<string> greyscale;
2021-05-15 04:54:37 +12:00
string filter;
string filter_cur;
string key;
vector<Proc::proc_info> plist;
int xc;
for (size_t i : iota(0, (int)Term::height - 19)){
xc = 230 - i * 150 / (Term::height - 20);
greyscale.push_back(Theme::dec_to_color(xc, xc, xc));
}
2021-05-15 04:54:37 +12:00
while (key != "q") {
2021-05-28 08:29:36 +12:00
timestamp = time_micros();
tsl = time_ms() + timer;
Config::lock();
try {
plist = Proc::collect();
}
catch (std::exception const& e) {
Logger::error("Caught exception in Proc::collect() : "s + e.what());
exit(1);
}
2021-05-28 08:29:36 +12:00
timestamp2 = time_micros();
2021-05-15 04:54:37 +12:00
timestamp = timestamp2 - timestamp;
ostring.clear();
2021-05-28 08:29:36 +12:00
ostring = Proc::draw(plist);
Config::unlock();
2021-05-28 08:29:36 +12:00
avgtimes.push_front(timestamp);
if (avgtimes.size() > 30) avgtimes.pop_back();
cout << Term::sync_start << ostring << Fx::reset << Mv::to(2, 2) << '\n';
cout << " Details for " << Proc::detailed.entry.name << " (" << Proc::detailed.entry.pid << ") Status: " << Proc::detailed.status << " Elapsed: " << Proc::detailed.elapsed
<< " Mem: " << floating_humanizer(Proc::detailed.entry.mem) << " "
<< "\n Parent: " << Proc::detailed.parent << " IO in/out: " << Proc::detailed.io_read << "/" << Proc::detailed.io_write << " ";
cout << Mv::to(4, 2) << "Processes call took: " << rjust(to_string(timestamp), 5) << " μs. Average: " <<
2021-05-28 08:29:36 +12:00
rjust(to_string(accumulate(avgtimes.begin(), avgtimes.end(), 0) / avgtimes.size()), 5) << " μs of " << avgtimes.size() <<
" samples. Drawing took: " << time_micros() - timestamp2 << " μs.\nNumber of processes: " << Proc::numpids << ". Number in vector: " << plist.size() << ". Run count: " << ++rcount << ". Time: " << strf_time("%X ") << Term::sync_end << flush;
2021-05-15 04:54:37 +12:00
while (time_ms() < tsl and not Global::resized) {
2021-05-15 04:54:37 +12:00
if (Input::poll(tsl - time_ms())) key = Input::get();
else { key.clear() ; continue; }
if (Config::getB("proc_filtering")) {
if (key == "enter") Config::set("proc_filtering", false);
2021-06-22 08:52:55 +12:00
else if (key == "backspace" and not filter.empty()) filter = uresize(filter, ulen(filter) - 1);
2021-05-15 04:54:37 +12:00
else if (key == "space") filter.push_back(' ');
else if (ulen(key) == 1 ) filter.append(key);
else { key.clear(); continue; }
2021-06-14 09:12:11 +12:00
if (filter != Config::getS("proc_filter")) Config::set("proc_filter", filter);
key.clear();
Proc::redraw = true;
2021-05-15 04:54:37 +12:00
break;
}
else if (key == "q") break;
2021-06-14 09:12:11 +12:00
else if (key == "left") {
int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting"));
if (--cur_i < 0) cur_i = Proc::sort_vector.size() - 1;
Config::set("proc_sorting", Proc::sort_vector.at(cur_i));
}
else if (key == "right") {
int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting"));
if (++cur_i > (int)Proc::sort_vector.size() - 1) cur_i = 0;
Config::set("proc_sorting", Proc::sort_vector.at(cur_i));
}
else if (key == "f") Config::flip("proc_filtering");
2021-06-14 09:12:11 +12:00
else if (key == "t") Config::flip("proc_tree");
else if (key == "r") Config::flip("proc_reversed");
2021-06-05 11:41:24 +12:00
else if (key == "c") Config::flip("proc_per_core");
2021-06-14 09:12:11 +12:00
else if (key == "delete") { filter.clear(); Config::set("proc_filter", filter); }
else if (is_in(key, "up", "down", "page_up", "page_down", "home", "end")) {
Proc::selection(key);
cout << Proc::draw(plist) << flush;
continue;
}
2021-05-15 04:54:37 +12:00
else continue;
Proc::redraw = true;
2021-05-15 04:54:37 +12:00
break;
}
if (Global::resized) {
cout << Cpu::box << Mem::box << Net::box << Proc::box << flush;
Global::resized = false;
}
cout << Mv::to(Term::height - 3, 1) << flush;
}
2021-05-11 09:46:41 +12:00
2021-05-10 08:25:41 +12:00
2021-05-22 12:13:56 +12:00
//*-----<<<<<
2021-05-10 08:25:41 +12:00
2021-05-07 06:32:03 +12:00
return 0;
}