mirror of https://github.com/aristocratos/btop.git
Added threads, memory to processes
This commit is contained in:
parent
621534f5d4
commit
05eb21dfbb
41
btop.cpp
41
btop.cpp
|
@ -25,6 +25,7 @@ tab-size = 4
|
|||
#include <thread>
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
#include <filesystem>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -35,26 +36,20 @@ tab-size = 4
|
|||
#include <btop_theme.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#define SYSTEM "linux"
|
||||
#include <btop_linux.h>
|
||||
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
|
||||
#include <sys/param.h>
|
||||
#if defined(BSD)
|
||||
#define SYSTEM "bsd"
|
||||
#else
|
||||
#define SYSTEM "unknown"
|
||||
// #include <btop_bsd.h>
|
||||
#endif
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_MAC == 1
|
||||
#define SYSTEM "osx"
|
||||
#else
|
||||
#define SYSTEM "unknown"
|
||||
// #include <btop_osx.h>
|
||||
#endif
|
||||
#else
|
||||
#define SYSTEM "unknown"
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
@ -99,7 +94,7 @@ class C_Banner {
|
|||
string banner_str;
|
||||
|
||||
public:
|
||||
int width;
|
||||
int width = 0;
|
||||
|
||||
C_Banner(){
|
||||
size_t z = 0;
|
||||
|
@ -112,7 +107,7 @@ public:
|
|||
fg = hex_to_color(line[0]);
|
||||
bg_i = 120-z*12;
|
||||
bg = dec_to_color(bg_i, bg_i, bg_i);
|
||||
for (unsigned i = 0; i < line[1].size(); i += 3) {
|
||||
for (uint i = 0; i < line[1].size(); i += 3) {
|
||||
if (line[1][i] == ' '){
|
||||
letter = ' ';
|
||||
i -= 2;
|
||||
|
@ -125,7 +120,7 @@ public:
|
|||
oc = b_color;
|
||||
}
|
||||
z++;
|
||||
if (z < Global::Banner_src.size()) out += Mv::l(ulen(line[1])) + Mv::d(1);
|
||||
if (z < Global::Banner_src.size()) out += Mv::l(new_len) + Mv::d(1);
|
||||
}
|
||||
banner_str = out + Mv::r(18 - Global::Version.size()) + Fx::i + dec_to_color(0,0,0, State::truecolor, "bg") + dec_to_color(150, 150, 150) + "v" + Global::Version;
|
||||
}
|
||||
|
@ -154,6 +149,15 @@ int main(int argc, char **argv){
|
|||
cout.setf(std::ios::boolalpha);
|
||||
if (argc > 1) argumentParser(argc, argv);
|
||||
|
||||
//? Init for Linux
|
||||
if (Global::SYSTEM == "linux") {
|
||||
Global::proc_path = (fs::is_directory(fs::path("/proc"))) ? fs::path("/proc") : Global::proc_path;
|
||||
if (Global::proc_path.empty()) {
|
||||
cout << "ERROR: Proc filesystem not detected!" << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
//? Initialize terminal and set options
|
||||
C_Term Term;
|
||||
if (!Term.initialized) {
|
||||
|
@ -174,7 +178,6 @@ int main(int argc, char **argv){
|
|||
//? Initialize the Input class
|
||||
C_Input Input;
|
||||
|
||||
|
||||
//* ------------------------------------------------ TESTING ------------------------------------------------------
|
||||
|
||||
int debug = 2;
|
||||
|
@ -192,6 +195,7 @@ int main(int argc, char **argv){
|
|||
|
||||
|
||||
|
||||
|
||||
//* Test MENUS
|
||||
// for (auto& outer : Global::Menus){
|
||||
// for (auto& inner : outer.second){
|
||||
|
@ -264,10 +268,10 @@ int main(int argc, char **argv){
|
|||
// insert Processes call here
|
||||
|
||||
|
||||
|
||||
unsigned lc;
|
||||
uint lc;
|
||||
string ostring;
|
||||
cout << rjustify("Pid:", 8) << " " << ljustify("Program:", 16) << " " << ljustify("Command:", Term.width - 48) << " " << rjustify("User:", 10) << " " << rjustify("Cpu%", 4) << "\n" << Mv::save << flush;
|
||||
cout << rjustify("Pid:", 8) << " " << ljustify("Program:", 16) << " " << ljustify("Command:", Term.width - 69) << " Threads: " <<
|
||||
ljustify("User:", 10) << " " << rjustify("MemB", 5) << " " << rjustify("Cpu%", 14) << "\n" << Mv::save << flush;
|
||||
|
||||
while (Input() != "q") {
|
||||
timestamp = time_ms();
|
||||
|
@ -275,9 +279,10 @@ int main(int argc, char **argv){
|
|||
timestamp = time_ms() - timestamp;
|
||||
ostring.clear();
|
||||
lc = 0;
|
||||
for (auto& [lpid, lname, lcmd, luser, lcpu, lcpu_s] : plist){
|
||||
for (auto& [lpid, lname, lcmd, lthread, luser, lmem, lcpu, lcpu_s] : plist){
|
||||
(void) lcpu_s;
|
||||
ostring += rjustify(to_string(lpid), 8) + " " + ljustify(lname, 16) + " " + ljustify(lcmd, Term.width - 48, true) + " " + rjustify(luser, 10) + " ";
|
||||
ostring += rjustify(to_string(lpid), 8) + " " + ljustify(lname, 16) + " " + ljustify(lcmd, Term.width - 66, true) + " " +
|
||||
rjustify(to_string(lthread), 5) + " " + ljustify(luser, 10) + " " + rjustify(floating_humanizer(lmem, true, 1), 5) + string(11, ' ');
|
||||
ostring += (lcpu > 100) ? rjustify(to_string(lcpu), 3) + " " : rjustify(to_string(lcpu), 4);
|
||||
ostring += "\n";
|
||||
if (lc++ > Term.height - 20) break;
|
||||
|
|
|
@ -39,7 +39,7 @@ using namespace std;
|
|||
namespace State {
|
||||
bool truecolor = true;
|
||||
string fg, bg;
|
||||
unsigned width, height;
|
||||
uint width, height;
|
||||
}
|
||||
|
||||
class C_Config {
|
||||
|
|
|
@ -113,6 +113,11 @@ namespace Global {
|
|||
} }
|
||||
} }
|
||||
};
|
||||
|
||||
//? Units for floating_humanizer function
|
||||
const vector<string> Units_bit = {"bit", "Kib", "Mib", "Gib", "Tib", "Pib", "Eib", "Zib", "Yib", "Bib", "GEb"};
|
||||
const vector<string> Units_byte = {"Byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "BiB", "GEB"};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
165
src/btop_linux.h
165
src/btop_linux.h
|
@ -37,23 +37,34 @@ tab-size = 4
|
|||
namespace fs = std::filesystem;
|
||||
using namespace std;
|
||||
|
||||
namespace Global {
|
||||
|
||||
const string SYSTEM = "linux";
|
||||
filesystem::path proc_path;
|
||||
|
||||
}
|
||||
|
||||
class Processes {
|
||||
uint64_t tstamp;
|
||||
long int clk_tck;
|
||||
map<int, tuple<string, string, string>> cache;
|
||||
map<string, unsigned> sorts = {
|
||||
map<string, uint> sorts = {
|
||||
{"pid", 0},
|
||||
{"name", 1},
|
||||
{"command", 2},
|
||||
{"user", 3},
|
||||
{"cpu direct", 4},
|
||||
{"cpu lazy", 5}
|
||||
{"threads", 3},
|
||||
{"user", 4},
|
||||
{"memory", 5},
|
||||
{"cpu direct", 6},
|
||||
{"cpu lazy", 7}
|
||||
};
|
||||
map<string, string> uid_user;
|
||||
fs::path passwd_path;
|
||||
fs::file_time_type passwd_time;
|
||||
map<int, uint64_t> cpu_times;
|
||||
map<int, uint64_t> cpu_second;
|
||||
unsigned counter = 0;
|
||||
uint counter = 0;
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
public:
|
||||
atomic<bool> stop;
|
||||
atomic<bool> running;
|
||||
|
@ -62,40 +73,42 @@ public:
|
|||
auto collect(string sorting="pid", bool reverse=false, string filter=""){
|
||||
running.store(true);
|
||||
int pid;
|
||||
uint64_t cpu_t;
|
||||
uint64_t cpu_t, rss_mem;
|
||||
double cpu, cpu_s;
|
||||
size_t threads;
|
||||
ifstream pread;
|
||||
string pid_str, name, cmd, attr, user, instr, uid, status, tmpstr;
|
||||
string pid_str, name, cmd, attr, user, instr, uid, status, tmpstr, smap;
|
||||
auto since_last = time_ms() - tstamp;
|
||||
if (since_last < 1) since_last = 1;
|
||||
auto uptime = system_uptime();
|
||||
auto sortint = (sorts.contains(sorting)) ? sorts[sorting] : 5;
|
||||
vector<string> pstat;
|
||||
|
||||
//? Return type! Values in tuple: pid, program, command, username, cpu%, cpu cumulative
|
||||
vector<tuple<int, string, string, string, double, double>> procs;
|
||||
//? Return type! Values in tuple: pid, program, command, threads, username, mem KiB, cpu%, cpu cumulative
|
||||
vector<tuple<int, string, string, size_t, string, uint64_t, double, double>> procs;
|
||||
|
||||
//* Update uid_user map if /etc/passwd changed since last run
|
||||
if (fs::last_write_time(fs::path("/etc/passwd")) != passwd_time) {
|
||||
if (!passwd_path.empty() && fs::last_write_time(passwd_path) != passwd_time) {
|
||||
string r_uid, r_user;
|
||||
passwd_time = fs::last_write_time(fs::path("/etc/passwd"));
|
||||
passwd_time = fs::last_write_time(passwd_path);
|
||||
uid_user.clear();
|
||||
pread.clear();
|
||||
ifstream pread("/etc/passwd");
|
||||
while (true){
|
||||
getline(pread, r_user, ':');
|
||||
pread.ignore(numeric_limits<streamsize>::max(), ':');
|
||||
getline(pread, r_uid, ':');
|
||||
uid_user[r_uid] = r_user;
|
||||
pread.ignore(numeric_limits<streamsize>::max(), '\n');
|
||||
if (pread.eof()) break;
|
||||
ifstream pread(passwd_path);
|
||||
if (pread.good()) {
|
||||
while (true){
|
||||
getline(pread, r_user, ':');
|
||||
pread.ignore(numeric_limits<streamsize>::max(), ':');
|
||||
getline(pread, r_uid, ':');
|
||||
uid_user[r_uid] = r_user;
|
||||
pread.ignore(numeric_limits<streamsize>::max(), '\n');
|
||||
if (pread.eof()) break;
|
||||
}
|
||||
}
|
||||
pread.close();
|
||||
}
|
||||
|
||||
|
||||
//* Iterate over all pid directories in /proc and get relevant values
|
||||
for (auto& d: fs::directory_iterator("/proc")){
|
||||
for (auto& d: fs::directory_iterator(Global::proc_path)){
|
||||
if (stop.load()) {
|
||||
procs.clear();
|
||||
running.store(false);
|
||||
|
@ -104,16 +117,22 @@ public:
|
|||
}
|
||||
pid_str = fs::path(d.path()).filename();
|
||||
cpu = 0.0;
|
||||
rss_mem = 0;
|
||||
if (d.is_directory() && isdigit(pid_str[0])) {
|
||||
pid = stoi(pid_str);
|
||||
|
||||
//* Get cpu usage
|
||||
if (fs::is_regular_file((string)d.path() + "/stat")) {
|
||||
pstat.clear();
|
||||
//* Get cpu usage, threads and rss mem from [pid]/stat
|
||||
if (fs::exists((string)d.path() + "/stat")) {
|
||||
pread.clear(); pstat.clear();
|
||||
ifstream pread((string)d.path() + "/stat");
|
||||
while (getline(pread, instr, ' ')) pstat.push_back(instr);
|
||||
if (pread.good()) while (getline(pread, instr, ' ')) pstat.push_back(instr);
|
||||
pread.close();
|
||||
|
||||
if (pstat.size() < 37) continue;
|
||||
|
||||
//? Process number of threads
|
||||
threads = stoul(pstat[19]);
|
||||
|
||||
//? Process utime + stime
|
||||
cpu_t = stoull(pstat[13]) + stoull(pstat[14]);
|
||||
if (!cpu_times.contains(pid)) cpu_times[pid] = cpu_t;
|
||||
|
@ -121,6 +140,9 @@ public:
|
|||
//? Cache process start time
|
||||
if (!cpu_second.contains(pid)) cpu_second[pid] = stoull(pstat[21]);
|
||||
|
||||
//? Get RSS memory in KiB (will be overriden by /status if available)
|
||||
rss_mem = (stoull(pstat[23]) * page_size) >> 10;
|
||||
|
||||
//? Process cpu usage since last update, 100'000 because (100 percent * 1000 milliseconds) for correct conversion
|
||||
cpu = static_cast<double>(100000 * (cpu_t - cpu_times[pid]) / since_last) / clk_tck;
|
||||
|
||||
|
@ -129,86 +151,106 @@ public:
|
|||
cpu_times[pid] = cpu_t;
|
||||
}
|
||||
|
||||
//* Get RSS memory in KiB
|
||||
if (fs::exists((string)d.path() + "/status")) {
|
||||
pread.clear(); status.clear(); tmpstr.clear();
|
||||
ifstream pread((string)d.path() + "/status");
|
||||
if (pread.good()) {
|
||||
while (getline(pread, status, ':')){
|
||||
if (status == "VmRSS") {
|
||||
pread.ignore();
|
||||
pread >> ws;
|
||||
getline(pread, tmpstr, 'k');
|
||||
tmpstr.pop_back();
|
||||
break;
|
||||
} else pread.ignore(numeric_limits<streamsize>::max(), '\n');
|
||||
}
|
||||
}
|
||||
pread.close();
|
||||
if (!tmpstr.empty()) rss_mem = stoull(tmpstr);
|
||||
}
|
||||
|
||||
//* Cache program name, command and username
|
||||
if (!cache.contains(pid)) {
|
||||
if (fs::is_regular_file((string)d.path() + "/comm")) {
|
||||
if (fs::exists((string)d.path() + "/comm")) {
|
||||
pread.clear(); name.clear();
|
||||
ifstream pread((string)d.path() + "/comm");
|
||||
getline(pread, name);
|
||||
if (pread.good()) getline(pread, name);
|
||||
pread.close();
|
||||
}
|
||||
if (fs::is_regular_file((string)d.path() + "/cmdline")) {
|
||||
cmd.clear();
|
||||
if (fs::exists((string)d.path() + "/cmdline")) {
|
||||
pread.clear(); cmd.clear(); tmpstr.clear();
|
||||
ifstream pread((string)d.path() + "/cmdline");
|
||||
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + " ";
|
||||
if (pread.good()) while(getline(pread, tmpstr, '\0')) cmd += tmpstr + " ";
|
||||
pread.close();
|
||||
if (!cmd.empty()) cmd.pop_back();
|
||||
}
|
||||
if (fs::exists((string)d.path() + "/status")) {
|
||||
pread.clear(); status.clear(); uid.clear();
|
||||
ifstream pread((string)d.path() + "/status");
|
||||
status.clear();
|
||||
while (!pread.eof()){
|
||||
getline(pread, status, ':');
|
||||
if (status == "Uid") {
|
||||
pread.ignore();
|
||||
getline(pread, uid, '\t');
|
||||
break;
|
||||
} else {
|
||||
pread.ignore(numeric_limits<streamsize>::max(), '\n');
|
||||
if (pread.good()) {
|
||||
while (!pread.eof()){
|
||||
getline(pread, status, ':');
|
||||
if (status == "Uid") {
|
||||
pread.ignore();
|
||||
getline(pread, uid, '\t');
|
||||
break;
|
||||
} else {
|
||||
pread.ignore(numeric_limits<streamsize>::max(), '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
pread.close();
|
||||
user = (uid_user.contains(uid)) ? uid_user.at(uid) : "";
|
||||
user = (!uid.empty() && uid_user.contains(uid)) ? uid_user.at(uid) : uid;
|
||||
}
|
||||
cache[pid] = make_tuple(name, cmd, user);
|
||||
}
|
||||
|
||||
// //* Match filter if applicable
|
||||
if (!filter.empty() &&
|
||||
pid_str.find(filter) == string::npos &&
|
||||
get<0>(cache[pid]).find(filter) == string::npos &&
|
||||
get<1>(cache[pid]).find(filter) == string::npos &&
|
||||
get<2>(cache[pid]).find(filter) == string::npos
|
||||
pid_str.find(filter) == string::npos && //? Pid
|
||||
get<0>(cache[pid]).find(filter) == string::npos && //? Program
|
||||
get<1>(cache[pid]).find(filter) == string::npos && //? Command
|
||||
get<2>(cache[pid]).find(filter) == string::npos //? User
|
||||
) continue;
|
||||
|
||||
//* Create tuple
|
||||
procs.push_back(make_tuple(pid, get<0>(cache[pid]), get<1>(cache[pid]), get<2>(cache[pid]), cpu, cpu_s));
|
||||
procs.push_back(make_tuple(pid, get<0>(cache[pid]), get<1>(cache[pid]), threads, get<2>(cache[pid]), rss_mem, cpu, cpu_s));
|
||||
}
|
||||
}
|
||||
|
||||
// auto st = time_ms();
|
||||
|
||||
//* Sort processes vector
|
||||
ranges::sort(procs, [&sortint, &reverse](tuple<int, string, string, string, double, double>& a, tuple<int, string, string, string, double, double>& b) {
|
||||
ranges::sort(procs, [&sortint, &reverse]( tuple<int, string, string, size_t, string, uint64_t, double, double>& a,
|
||||
tuple<int, string, string, size_t, string, uint64_t, double, double>& b)
|
||||
{
|
||||
switch (sortint) {
|
||||
case 0: return (reverse) ? get<0>(a) < get<0>(b) : get<0>(a) > get<0>(b); //? Pid
|
||||
case 1: return (reverse) ? get<1>(a) < get<1>(b) : get<1>(a) > get<1>(b); //? Program
|
||||
case 2: return (reverse) ? get<2>(a) < get<2>(b) : get<2>(a) > get<2>(b); //? Command
|
||||
case 3: return (reverse) ? get<3>(a) < get<3>(b) : get<3>(a) > get<3>(b); //? User
|
||||
case 4: return (reverse) ? get<4>(a) < get<4>(b) : get<4>(a) > get<4>(b); //? Cpu direct
|
||||
case 5: return (reverse) ? get<5>(a) < get<5>(b) : get<5>(a) > get<5>(b); //? Cpu lazy
|
||||
case 3: return (reverse) ? get<3>(a) < get<3>(b) : get<3>(a) > get<3>(b); //? Threads
|
||||
case 4: return (reverse) ? get<4>(a) < get<4>(b) : get<4>(a) > get<4>(b); //? User
|
||||
case 5: return (reverse) ? get<5>(a) < get<5>(b) : get<5>(a) > get<5>(b); //? Memory
|
||||
case 6: return (reverse) ? get<6>(a) < get<6>(b) : get<6>(a) > get<6>(b); //? Cpu direct
|
||||
case 7: return (reverse) ? get<7>(a) < get<7>(b) : get<7>(a) > get<7>(b); //? Cpu lazy
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
//* When using "cpu lazy" sorting, push processes with high cpu usage to the front regardless of cumulative usage
|
||||
if (sortint == 5 && !reverse) {
|
||||
//* When using "cpu lazy" sorting push processes with high cpu usage to the front regardless of cumulative usage
|
||||
if (sortint == 6 && !reverse) {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, offset = 0; i < procs.size(); i++) {
|
||||
if (i <= 5 && get<4>(procs[i]) > max) max = get<4>(procs[i]);
|
||||
if (i <= 5 && get<6>(procs[i]) > max) max = get<6>(procs[i]);
|
||||
else if (i == 6) target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset && get<4>(procs[i]) > 30.0) offset++;
|
||||
else if (get<4>(procs[i]) > target) rotate(procs.begin() + offset, procs.begin() + i, procs.begin() + i + 1);
|
||||
if (i == offset && get<6>(procs[i]) > 30.0) offset++;
|
||||
else if (get<6>(procs[i]) > target) rotate(procs.begin() + offset, procs.begin() + i, procs.begin() + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cout << "Sort took: " << time_ms() - st << "ms " << flush;
|
||||
|
||||
|
||||
|
||||
//* Clear all cached values at a regular interval
|
||||
//* Clear all cached values at a regular interval to get rid of dead processes
|
||||
if (++counter >= 10000 || (filter.empty() && cache.size() > procs.size() + 100)) {
|
||||
counter = 0;
|
||||
cache.clear();
|
||||
|
@ -225,6 +267,7 @@ public:
|
|||
clk_tck = sysconf(_SC_CLK_TCK);
|
||||
tstamp = time_ms();
|
||||
stop.store(false);
|
||||
passwd_path = (fs::exists(fs::path("/etc/passwd"))) ? fs::path("/etc/passwd") : passwd_path;
|
||||
collect();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ using namespace std;
|
|||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
//* Convert 24-bit colors to 256 colors using 6x6x6 color cube
|
||||
int truecolor_to_256(unsigned r, unsigned g, unsigned b){
|
||||
int truecolor_to_256(uint r, uint g, uint b){
|
||||
if (r / 11 == g / 11 && g / 11 == b / 11) {
|
||||
return 232 + r / 11;
|
||||
} else {
|
||||
|
@ -54,7 +54,7 @@ string hex_to_color(string hexa, bool t_to_256=false, string depth="fg"){
|
|||
pre += (t_to_256) ? "5;" : "2;";
|
||||
|
||||
if (hexa.size() == 2){
|
||||
unsigned h_int = stoi(hexa, 0, 16);
|
||||
uint h_int = stoi(hexa, 0, 16);
|
||||
if (t_to_256){
|
||||
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
|
||||
} else {
|
||||
|
@ -83,7 +83,7 @@ string hex_to_color(string hexa, bool t_to_256=false, string depth="fg"){
|
|||
//* Args r: [0-255], g: [0-255], b: [0-255]
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string dec_to_color(unsigned r, unsigned g, unsigned b, bool t_to_256=false, string depth="fg"){
|
||||
string dec_to_color(uint r, uint g, uint b, bool t_to_256=false, string depth="fg"){
|
||||
depth = (depth == "fg") ? "38" : "48";
|
||||
string pre = Fx::e + depth + ";";
|
||||
pre += (t_to_256) ? "5;" : "2;";
|
||||
|
|
|
@ -42,7 +42,7 @@ using namespace std;
|
|||
//* Collection of escape codes for text style and formatting
|
||||
namespace Fx {
|
||||
//* Escape sequence start
|
||||
const string e = "\x1b[";
|
||||
const string e = "\033[";
|
||||
|
||||
//* Bold on
|
||||
const string b = e + "1m";
|
||||
|
@ -96,9 +96,9 @@ namespace Mv {
|
|||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
//* Return number of UTF8 characters in a string
|
||||
size_t ulen(string s){
|
||||
inline size_t ulen(string s){
|
||||
return std::count_if(s.begin(), s.end(),
|
||||
[](char c) { return (static_cast<unsigned char>(c) & 0xC0) != 0x80; } );
|
||||
[](char& c) { return (c & 0xC0) != 0x80; } );
|
||||
}
|
||||
|
||||
//* Return current time since epoch in milliseconds
|
||||
|
@ -152,7 +152,7 @@ vector<string> ssplit(string str, string delim = " ", int times = 0){
|
|||
}
|
||||
|
||||
//* Put current thread to sleep for <ms> milliseconds
|
||||
void sleep_ms(unsigned ms) {
|
||||
void sleep_ms(uint ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
|
@ -207,9 +207,9 @@ string trans(string str){
|
|||
return (newstr.empty()) ? str : newstr;
|
||||
}
|
||||
|
||||
string sec_to_dhms(unsigned sec){
|
||||
string sec_to_dhms(uint sec){
|
||||
string out;
|
||||
unsigned d, h, m;
|
||||
uint d, h, m;
|
||||
d = sec / (3600 * 24);
|
||||
sec %= 3600 * 24;
|
||||
h = sec / 3600;
|
||||
|
@ -231,6 +231,41 @@ double system_uptime(){
|
|||
return stod(upstr);
|
||||
}
|
||||
|
||||
//* Scales up in steps of 1024 to highest possible unit and returns string with unit suffixed
|
||||
//* bit=True or defaults to bytes
|
||||
//* start=int to set 1024 multiplier starting unit
|
||||
//* short=True always returns 0 decimals and shortens unit to 1 character
|
||||
string floating_humanizer(uint64_t value, bool shorten=false, uint start=0, bool bit=false, bool per_second=false){
|
||||
string out;
|
||||
uint mult = (bit) ? 8 : 1;
|
||||
auto& units = (bit) ? Global::Units_bit : Global::Units_byte;
|
||||
|
||||
value *= 100 * mult;
|
||||
|
||||
while (value >= 102400){
|
||||
value >>= 10;
|
||||
if (value < 100){
|
||||
out = to_string(value);
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = to_string(value);
|
||||
if (out.size() == 4 && start > 0) { out.pop_back(); out.insert(2, ".");}
|
||||
else if (out.size() == 3 && start > 0) out.insert(1, ".");
|
||||
else if (out.size() >= 2) out.resize(out.size() - 2);
|
||||
}
|
||||
if (shorten){
|
||||
if (out.find('.') != string::npos) out = to_string((int)round(stof(out)));
|
||||
if (out.size() > 3) { out = to_string((int)(out[0] - '0') + 1); start++;}
|
||||
out.push_back(units[start][0]);
|
||||
}
|
||||
else out += " " + units[start];
|
||||
|
||||
if (per_second) out += (bit) ? "ps" : "/s";
|
||||
return out;
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- CLASSES -----------------------------------------------------
|
||||
|
||||
|
@ -240,8 +275,8 @@ class C_Term {
|
|||
public:
|
||||
bool initialized = false;
|
||||
bool resized = false;
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
|
||||
//* Hide terminal cursor
|
||||
const string hide_cursor = Fx::e + "?25l";
|
||||
|
|
Loading…
Reference in New Issue