mirror of https://github.com/aristocratos/btop.git
Added Meter class
This commit is contained in:
parent
e7cbc28960
commit
ecd4ef9985
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
32
btop.cpp
32
btop.cpp
|
@ -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) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue