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
|
CPPFLAGS = -std=c++20 -pthread
|
||||||
OPTFLAG = -O3
|
OPTFLAG = -O3
|
||||||
INFOFLAGS += -Wall -Wextra -Wno-stringop-overread -pedantic
|
INFOFLAGS += -Wall -Wextra -Wno-stringop-overread -pedantic
|
||||||
INCLUDES = -I./src
|
INCLUDES = -I./src -I./include
|
||||||
|
|
||||||
btop: btop.cpp
|
btop: btop.cpp
|
||||||
@mkdir -p bin
|
@mkdir -p bin
|
||||||
|
|
32
btop.cpp
32
btop.cpp
|
@ -238,7 +238,7 @@ int main(int argc, char **argv){
|
||||||
int ill = 0;
|
int ill = 0;
|
||||||
for (int i : iota(0, (int)blen)){
|
for (int i : iota(0, (int)blen)){
|
||||||
ill = (i <= (int)blen / 2) ? i : ill - 1;
|
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;
|
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){
|
if (thread_test){
|
||||||
|
|
||||||
map<int, future<string>> runners;
|
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));
|
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: " +
|
pbox += rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + ljust("Command:", Term::width - 69) + " Threads: " +
|
||||||
ljust("User:", 10) + " " + rjust("MemB", 5) + " " + rjust("Cpu%", 14) + "\n";
|
ljust("User:", 10) + " " + rjust("MemB", 5) + " " + rjust("Cpu%", 14) + "\n";
|
||||||
|
|
||||||
while (key != "q") {
|
while (key != "q") {
|
||||||
timestamp = time_ms();
|
timestamp = time_micros();
|
||||||
tsl = timestamp + timer;
|
tsl = time_ms() + timer;
|
||||||
auto plist = Proc::collect(Proc::sort_array[sortint], reversing, filter);
|
auto plist = Proc::collect(Proc::sort_array[sortint], reversing, filter);
|
||||||
timestamp2 = time_ms();
|
timestamp2 = time_micros();
|
||||||
timestamp = timestamp2 - timestamp;
|
timestamp = timestamp2 - timestamp;
|
||||||
ostring.clear();
|
ostring.clear();
|
||||||
lc = 0;
|
lc = 0;
|
||||||
|
@ -353,12 +365,16 @@ int main(int argc, char **argv){
|
||||||
if (lc++ > Term::height - 21) break;
|
if (lc++ > Term::height - 21) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (lc++ < Term::height - 19) ostring += Mv::r(1) + string(Term::width - 2, ' ') + "\n";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
avgtimes.push_front(timestamp);
|
avgtimes.push_front(timestamp);
|
||||||
if (avgtimes.size() > 100) avgtimes.pop_back();
|
if (avgtimes.size() > 100) avgtimes.pop_back();
|
||||||
cout << pbox << ostring << Fx::reset << "\n" << endl;
|
cout << pbox << ostring << Fx::reset << "\n" << endl;
|
||||||
cout << Mv::to(Term::height - 4, 1) << "Processes call took: " << rjust(to_string(timestamp), 4) << "ms. Average: " <<
|
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()), 3) << "ms of " << avgtimes.size() <<
|
rjust(to_string(accumulate(avgtimes.begin(), avgtimes.end(), 0) / avgtimes.size()), 5) << " μs of " << avgtimes.size() <<
|
||||||
" samples. Drawing took: " << time_ms() - timestamp2 << "ms.\nNumber of processes: " << Proc::numpids << ". Run count: " <<
|
" samples. Drawing took: " << time_micros() - timestamp2 << " μs.\nNumber of processes: " << Proc::numpids << ". Run count: " <<
|
||||||
++rcount << ". Time: " << strf_time("%X ") << endl;
|
++rcount << ". Time: " << strf_time("%X ") << endl;
|
||||||
|
|
||||||
while (time_ms() < tsl) {
|
while (time_ms() < tsl) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,8 @@ tab-size = 4
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include <btop_config.h>
|
#include <btop_config.h>
|
||||||
#include <btop_tools.h>
|
#include <btop_tools.h>
|
||||||
|
@ -29,7 +31,7 @@ tab-size = 4
|
||||||
#ifndef _btop_draw_included_
|
#ifndef _btop_draw_included_
|
||||||
#define _btop_draw_included_ 1
|
#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 {
|
namespace Draw {
|
||||||
|
|
||||||
|
@ -80,8 +82,42 @@ namespace Draw {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meter {
|
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 <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -39,9 +37,10 @@ tab-size = 4
|
||||||
#include <btop_config.h>
|
#include <btop_config.h>
|
||||||
#include <btop_globs.h>
|
#include <btop_globs.h>
|
||||||
#include <btop_tools.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;
|
using std::cout, std::flush, std::endl;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
using namespace Tools;
|
using namespace Tools;
|
||||||
|
@ -72,8 +71,8 @@ namespace Proc {
|
||||||
string name, cmd, user;
|
string name, cmd, user;
|
||||||
uint64_t cpu_t = 0, cpu_s = 0;
|
uint64_t cpu_t = 0, cpu_s = 0;
|
||||||
};
|
};
|
||||||
unordered_map<uint, p_cache> cache;
|
unordered_flat_map<uint, p_cache> cache;
|
||||||
unordered_map<string, string> uid_user;
|
unordered_flat_map<string, string> uid_user;
|
||||||
fs::path passwd_path;
|
fs::path passwd_path;
|
||||||
fs::file_time_type passwd_time;
|
fs::file_time_type passwd_time;
|
||||||
uint counter = 0;
|
uint counter = 0;
|
||||||
|
@ -95,7 +94,7 @@ namespace Proc {
|
||||||
"cpu direct",
|
"cpu direct",
|
||||||
"cpu lazy",
|
"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
|
//* proc_info: pid, name, cmd, threads, user, mem, cpu_p, cpu_c, state, cpu_n, p_nice, ppid
|
||||||
struct proc_info {
|
struct proc_info {
|
||||||
|
@ -138,13 +137,12 @@ namespace Proc {
|
||||||
uid_user.clear();
|
uid_user.clear();
|
||||||
pread.open(passwd_path);
|
pread.open(passwd_path);
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
while (true){
|
while (!pread.eof()){
|
||||||
getline(pread, r_user, ':');
|
getline(pread, r_user, ':');
|
||||||
pread.ignore(SSmax, ':');
|
pread.ignore(SSmax, ':');
|
||||||
getline(pread, r_uid, ':');
|
getline(pread, r_uid, ':');
|
||||||
uid_user[r_uid] = r_user;
|
uid_user[r_uid] = r_user;
|
||||||
pread.ignore(SSmax, '\n');
|
pread.ignore(SSmax, '\n');
|
||||||
if (pread.eof()) break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pread.close();
|
pread.close();
|
||||||
|
@ -180,7 +178,6 @@ namespace Proc {
|
||||||
|
|
||||||
pread.open(d.path() / "cmdline");
|
pread.open(d.path() / "cmdline");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
tmpstr.clear();
|
|
||||||
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + " ";
|
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + " ";
|
||||||
pread.close();
|
pread.close();
|
||||||
if (!cmd.empty()) cmd.pop_back();
|
if (!cmd.empty()) cmd.pop_back();
|
||||||
|
@ -189,7 +186,7 @@ namespace Proc {
|
||||||
|
|
||||||
pread.open(d.path() / "status");
|
pread.open(d.path() / "status");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
status.clear(); uid.clear();
|
uid.clear();
|
||||||
while (!pread.eof()){
|
while (!pread.eof()){
|
||||||
getline(pread, status, ':');
|
getline(pread, status, ':');
|
||||||
if (status == "Uid") {
|
if (status == "Uid") {
|
||||||
|
@ -208,10 +205,11 @@ namespace Proc {
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Match filter if defined
|
//* Match filter if defined
|
||||||
if (!filter.empty() && pid_str.find(filter) == string::npos &&
|
if (!filter.empty()
|
||||||
cache[pid].name.find(filter) == string::npos &&
|
&& pid_str.find(filter) == string::npos
|
||||||
cache[pid].cmd.find(filter) == string::npos &&
|
&& cache[pid].name.find(filter) == string::npos
|
||||||
cache[pid].user.find(filter) == string::npos) {
|
&& cache[pid].cmd.find(filter) == string::npos
|
||||||
|
&& cache[pid].user.find(filter) == string::npos) {
|
||||||
if (new_cache) cache.erase(pid);
|
if (new_cache) cache.erase(pid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -219,9 +217,9 @@ namespace Proc {
|
||||||
//* Parse /proc/[pid]/stat
|
//* Parse /proc/[pid]/stat
|
||||||
pread.open(d.path() / "stat");
|
pread.open(d.path() / "stat");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
instr.clear(); s_pos = 0; c_pos = 0; s_count = 0;
|
|
||||||
getline(pread, instr);
|
getline(pread, instr);
|
||||||
pread.close();
|
pread.close();
|
||||||
|
s_pos = 0; c_pos = 0; s_count = 0;
|
||||||
|
|
||||||
//? Skip pid and comm field and find comm fields closing ')'
|
//? Skip pid and comm field and find comm fields closing ')'
|
||||||
s_pos = instr.find_last_of(')') + 2;
|
s_pos = instr.find_last_of(')') + 2;
|
||||||
|
@ -289,12 +287,12 @@ namespace Proc {
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
pread.ignore(SSmax, ' ');
|
pread.ignore(SSmax, ' ');
|
||||||
pread >> rss_mem;
|
pread >> rss_mem;
|
||||||
rss_mem *= page_size;
|
|
||||||
pread.close();
|
pread.close();
|
||||||
|
rss_mem *= page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Create proc_info
|
//* 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
|
//* 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) {
|
||||||
switch (sortint) {
|
switch (sortint) {
|
||||||
case 0: return (reverse) ? a.pid < b.pid : a.pid > b.pid;
|
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 1: return (reverse) ? a.name < b.name : a.name > b.name;
|
||||||
case 2: return (reverse) ? a.cmd < b.cmd : a.cmd > b.cmd;
|
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 3: return (reverse) ? a.threads < b.threads : a.threads > b.threads;
|
||||||
case 4: return (reverse) ? a.user < b.user : a.user > b.user;
|
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 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 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 7: return (reverse) ? a.cpu_c < b.cpu_c : a.cpu_c > b.cpu_c;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -328,11 +326,12 @@ namespace Proc {
|
||||||
|
|
||||||
//* Clear dead processes from cache at a regular interval
|
//* Clear dead processes from cache at a regular interval
|
||||||
if (++counter >= 10000 || (filter.empty() && cache.size() > procs.size() + 100)) {
|
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;
|
counter = 0;
|
||||||
if (filter.empty()) {
|
if (filter.empty()) {
|
||||||
for (auto& p : procs) r_cache[p.pid] = cache[p.pid];
|
for (auto& p : procs) r_cache[p.pid] = cache[p.pid];
|
||||||
cache = move(r_cache);
|
cache.swap(r_cache);
|
||||||
}
|
}
|
||||||
else cache.clear();
|
else cache.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ namespace Theme {
|
||||||
string depth;
|
string depth;
|
||||||
colors.clear(); rgbs.clear();
|
colors.clear(); rgbs.clear();
|
||||||
for (auto& [name, color] : Default_theme) {
|
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.contains(name)) {
|
||||||
if (source.at(name)[0] == '#') {
|
if (source.at(name)[0] == '#') {
|
||||||
colors[name] = hex_to_color(source.at(name), !Config::getB("truecolor"), depth);
|
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_up = "┬";
|
||||||
const string div_down = "┴";
|
const string div_down = "┴";
|
||||||
|
|
||||||
|
const string meter = "■";
|
||||||
|
|
||||||
const array<string, 10> superscript = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" };
|
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 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
|
//* Check if a string is a valid bool value
|
||||||
inline bool isbool(string& str){
|
inline bool isbool(string& str){
|
||||||
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
||||||
|
|
Loading…
Reference in New Issue