Added Meter class

This commit is contained in:
aristocratos 2021-05-27 22:29:36 +02:00
parent e7cbc28960
commit ecd4ef9985
7 changed files with 2627 additions and 39 deletions

View file

@ -4,7 +4,7 @@ CPP = g++
CPPFLAGS = -std=c++20 -pthread
OPTFLAG = -O3
INFOFLAGS += -Wall -Wextra -Wno-stringop-overread -pedantic
INCLUDES = -I./src
INCLUDES = -I./src -I./include
btop: btop.cpp
@mkdir -p bin

View file

@ -238,7 +238,7 @@ int main(int argc, char **argv){
int ill = 0;
for (int i : iota(0, (int)blen)){
ill = (i <= (int)blen / 2) ? i : ill - 1;
cout << Theme::g("used")[ill] << "-";
cout << Theme::g("used")[ill] << Symbols::h_line;
}
cout << Fx::reset << endl;
@ -274,6 +274,18 @@ int main(int argc, char **argv){
}
if (true) {
Draw::Meter kmeter;
kmeter(Term::width - 2, "cpu", false);
cout << kmeter(25) << endl;
cout << kmeter(0) << endl;
cout << kmeter(50) << endl;
cout << kmeter(100) << endl;
cout << kmeter(50) << endl;
exit(0);
}
if (thread_test){
map<int, future<string>> runners;
@ -329,15 +341,15 @@ int main(int argc, char **argv){
greyscale.push_back(Theme::dec_to_color(xc, xc, xc));
}
string pbox = Draw::createBox({.x = 0, .y = 10, .width = Term::width, .height = Term::height - 16, .line_color = Theme::c("proc_box"), .title = "testbox", .title2 = "below", .num = 7});
string pbox = Draw::createBox({.x = 0, .y = 10, .width = Term::width, .height = Term::height - 16, .line_color = Theme::c("proc_box"), .title = "testbox", .title2 = "below", .fill = false, .num = 7});
pbox += rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + ljust("Command:", Term::width - 69) + " Threads: " +
ljust("User:", 10) + " " + rjust("MemB", 5) + " " + rjust("Cpu%", 14) + "\n";
while (key != "q") {
timestamp = time_ms();
tsl = timestamp + timer;
timestamp = time_micros();
tsl = time_ms() + timer;
auto plist = Proc::collect(Proc::sort_array[sortint], reversing, filter);
timestamp2 = time_ms();
timestamp2 = time_micros();
timestamp = timestamp2 - timestamp;
ostring.clear();
lc = 0;
@ -353,12 +365,16 @@ int main(int argc, char **argv){
if (lc++ > Term::height - 21) break;
}
while (lc++ < Term::height - 19) ostring += Mv::r(1) + string(Term::width - 2, ' ') + "\n";
avgtimes.push_front(timestamp);
if (avgtimes.size() > 100) avgtimes.pop_back();
cout << pbox << ostring << Fx::reset << "\n" << endl;
cout << Mv::to(Term::height - 4, 1) << "Processes call took: " << rjust(to_string(timestamp), 4) << "ms. Average: " <<
rjust(to_string(accumulate(avgtimes.begin(), avgtimes.end(), 0) / avgtimes.size()), 3) << "ms of " << avgtimes.size() <<
" samples. Drawing took: " << time_ms() - timestamp2 << "ms.\nNumber of processes: " << Proc::numpids << ". Run count: " <<
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() <<
" samples. Drawing took: " << time_micros() - timestamp2 << " μs.\nNumber of processes: " << Proc::numpids << ". Run count: " <<
++rcount << ". Time: " << strf_time("%X ") << endl;
while (time_ms() < tsl) {

2530
include/robin_hood.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,8 @@ tab-size = 4
#include <vector>
#include <map>
#include <ranges>
#include <algorithm>
#include <cmath>
#include <btop_config.h>
#include <btop_tools.h>
@ -29,7 +31,7 @@ tab-size = 4
#ifndef _btop_draw_included_
#define _btop_draw_included_ 1
using std::string, std::vector, std::map, std::round, std::views::iota;
using std::string, std::vector, std::map, std::round, std::views::iota, std::string_literals::operator""s;
namespace Draw {
@ -80,8 +82,42 @@ namespace Draw {
}
class Meter {
string out, color_gradient, color_inactive;
string out, color_gradient;
int width = 10;
bool invert = false;
vector<string> cache;
public:
void operator()(int width, string color_gradient, bool invert = false) {
if (width < 0) width = 1;
this->width = width;
this->color_gradient = color_gradient;
this->invert = invert;
cache.clear();
cache.insert(cache.begin(), 101, "");
}
string operator()(int value) {
if (value > 100) value = 100;
else if (value < 0) value = 0;
if (!cache.at(value).empty()) return out = cache.at(value);
out.clear();
int y;
for (int i : iota(1, width + 1)) {
y = round((double)i * 100.0 / width);
if (value >= y)
out += Theme::g(color_gradient)[invert ? 100 - y : y] + Symbols::meter;
else {
out += Theme::c("meter_bg") + Symbols::meter * (width + 1 - i);
break;
}
}
out += Fx::reset;
return cache.at(value) = out;
}
string operator()() {
return out;
}
};

View file

@ -23,8 +23,6 @@ tab-size = 4
#include <vector>
#include <deque>
#include <array>
#include <map>
#include <unordered_map>
#include <atomic>
#include <future>
#include <thread>
@ -39,9 +37,10 @@ tab-size = 4
#include <btop_config.h>
#include <btop_globs.h>
#include <btop_tools.h>
#include <robin_hood.h>
using std::string, std::vector, std::array, std::ifstream, std::atomic, std::numeric_limits, std::streamsize, std::map, std::unordered_map, std::deque, std::list;
using std::string, std::vector, std::array, std::ifstream, std::atomic, std::numeric_limits, std::streamsize, robin_hood::unordered_flat_map;
using std::cout, std::flush, std::endl;
namespace fs = std::filesystem;
using namespace Tools;
@ -72,8 +71,8 @@ namespace Proc {
string name, cmd, user;
uint64_t cpu_t = 0, cpu_s = 0;
};
unordered_map<uint, p_cache> cache;
unordered_map<string, string> uid_user;
unordered_flat_map<uint, p_cache> cache;
unordered_flat_map<string, string> uid_user;
fs::path passwd_path;
fs::file_time_type passwd_time;
uint counter = 0;
@ -95,7 +94,7 @@ namespace Proc {
"cpu direct",
"cpu lazy",
};
unordered_map<string, uint> sort_map;
unordered_flat_map<string, uint> sort_map;
//* proc_info: pid, name, cmd, threads, user, mem, cpu_p, cpu_c, state, cpu_n, p_nice, ppid
struct proc_info {
@ -138,13 +137,12 @@ namespace Proc {
uid_user.clear();
pread.open(passwd_path);
if (pread.good()) {
while (true){
while (!pread.eof()){
getline(pread, r_user, ':');
pread.ignore(SSmax, ':');
getline(pread, r_uid, ':');
uid_user[r_uid] = r_user;
pread.ignore(SSmax, '\n');
if (pread.eof()) break;
}
}
pread.close();
@ -180,7 +178,6 @@ namespace Proc {
pread.open(d.path() / "cmdline");
if (pread.good()) {
tmpstr.clear();
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + " ";
pread.close();
if (!cmd.empty()) cmd.pop_back();
@ -189,7 +186,7 @@ namespace Proc {
pread.open(d.path() / "status");
if (pread.good()) {
status.clear(); uid.clear();
uid.clear();
while (!pread.eof()){
getline(pread, status, ':');
if (status == "Uid") {
@ -208,10 +205,11 @@ namespace Proc {
}
//* Match filter if defined
if (!filter.empty() && pid_str.find(filter) == string::npos &&
cache[pid].name.find(filter) == string::npos &&
cache[pid].cmd.find(filter) == string::npos &&
cache[pid].user.find(filter) == string::npos) {
if (!filter.empty()
&& pid_str.find(filter) == string::npos
&& cache[pid].name.find(filter) == string::npos
&& cache[pid].cmd.find(filter) == string::npos
&& cache[pid].user.find(filter) == string::npos) {
if (new_cache) cache.erase(pid);
continue;
}
@ -219,9 +217,9 @@ namespace Proc {
//* Parse /proc/[pid]/stat
pread.open(d.path() / "stat");
if (pread.good()) {
instr.clear(); s_pos = 0; c_pos = 0; s_count = 0;
getline(pread, instr);
pread.close();
s_pos = 0; c_pos = 0; s_count = 0;
//? Skip pid and comm field and find comm fields closing ')'
s_pos = instr.find_last_of(')') + 2;
@ -289,12 +287,12 @@ namespace Proc {
if (pread.good()) {
pread.ignore(SSmax, ' ');
pread >> rss_mem;
rss_mem *= page_size;
pread.close();
rss_mem *= page_size;
}
//* Create proc_info
procs.push_back({pid, cache[pid].name, cache[pid].cmd, threads, cache[pid].user, rss_mem, cpu, cpu_s, state, cpu_n, p_nice, ppid});
procs.emplace_back(pid, cache[pid].name, cache[pid].cmd, threads, cache[pid].user, rss_mem, cpu, cpu_s, state, cpu_n, p_nice, ppid);
}
}
@ -302,14 +300,14 @@ namespace Proc {
//* Sort processes vector
std::ranges::sort(procs, [&sortint, &reverse](proc_info& a, proc_info& b) {
switch (sortint) {
case 0: return (reverse) ? a.pid < b.pid : a.pid > b.pid;
case 1: return (reverse) ? a.name < b.name : a.name > b.name;
case 2: return (reverse) ? a.cmd < b.cmd : a.cmd > b.cmd;
case 3: return (reverse) ? a.threads < b.threads : a.threads > b.threads;
case 4: return (reverse) ? a.user < b.user : a.user > b.user;
case 5: return (reverse) ? a.mem < b.mem : a.mem > b.mem;
case 6: return (reverse) ? a.cpu_p < b.cpu_p : a.cpu_p > b.cpu_p;
case 7: return (reverse) ? a.cpu_c < b.cpu_c : a.cpu_c > b.cpu_c;
case 0: return (reverse) ? a.pid < b.pid : a.pid > b.pid;
case 1: return (reverse) ? a.name < b.name : a.name > b.name;
case 2: return (reverse) ? a.cmd < b.cmd : a.cmd > b.cmd;
case 3: return (reverse) ? a.threads < b.threads : a.threads > b.threads;
case 4: return (reverse) ? a.user < b.user : a.user > b.user;
case 5: return (reverse) ? a.mem < b.mem : a.mem > b.mem;
case 6: return (reverse) ? a.cpu_p < b.cpu_p : a.cpu_p > b.cpu_p;
case 7: return (reverse) ? a.cpu_c < b.cpu_c : a.cpu_c > b.cpu_c;
}
return false;
}
@ -328,11 +326,12 @@ namespace Proc {
//* Clear dead processes from cache at a regular interval
if (++counter >= 10000 || (filter.empty() && cache.size() > procs.size() + 100)) {
unordered_map<uint, p_cache> r_cache;
unordered_flat_map<uint, p_cache> r_cache;
r_cache.reserve(procs.size());
counter = 0;
if (filter.empty()) {
for (auto& p : procs) r_cache[p.pid] = cache[p.pid];
cache = move(r_cache);
cache.swap(r_cache);
}
else cache.clear();
}

View file

@ -192,7 +192,7 @@ namespace Theme {
string depth;
colors.clear(); rgbs.clear();
for (auto& [name, color] : Default_theme) {
depth = (name.ends_with("bg")) ? "bg" : "fg";
depth = (name.ends_with("bg") && name != "meter_bg") ? "bg" : "fg";
if (source.contains(name)) {
if (source.at(name)[0] == '#') {
colors[name] = hex_to_color(source.at(name), !Config::getB("truecolor"), depth);

View file

@ -56,6 +56,8 @@ namespace Symbols {
const string div_up = "";
const string div_down = "";
const string meter = "";
const array<string, 10> superscript = { "", "¹", "²", "³", "", "", "", "", "", "" };
}
@ -254,6 +256,11 @@ namespace Tools {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
//* Return current time since epoch in milliseconds
inline uint64_t time_micros(){
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
//* Check if a string is a valid bool value
inline bool isbool(string& str){
return (str == "true") || (str == "false") || (str == "True") || (str == "False");