mirror of
https://github.com/aristocratos/btop.git
synced 2024-06-02 02:24:54 +12:00
Optimizations and fixes
This commit is contained in:
parent
ce34cbb8d0
commit
43e3c4fa87
52
btop.cpp
52
btop.cpp
|
@ -40,6 +40,7 @@ namespace Global {
|
||||||
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
|
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
|
||||||
};
|
};
|
||||||
const std::string Version = "0.0.20";
|
const std::string Version = "0.0.20";
|
||||||
|
int coreCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <btop_tools.h>
|
#include <btop_tools.h>
|
||||||
|
@ -127,14 +128,14 @@ void _exit_handler() { clean_quit(-1); }
|
||||||
|
|
||||||
//? Generate the btop++ banner
|
//? Generate the btop++ banner
|
||||||
void banner_gen() {
|
void banner_gen() {
|
||||||
size_t z = 0, w = 0;
|
size_t z = 0;
|
||||||
string b_color, bg, fg, oc, letter;
|
string b_color, bg, fg, oc, letter;
|
||||||
bool truecolor = Config::getB("truecolor");
|
bool truecolor = Config::getB("truecolor");
|
||||||
int bg_i;
|
int bg_i;
|
||||||
Global::banner.clear();
|
Global::banner.clear();
|
||||||
Global::banner_width = 0;
|
Global::banner_width = 0;
|
||||||
for (auto line: Global::Banner_src) {
|
for (auto line: Global::Banner_src) {
|
||||||
if ( (w = ulen(line[1])) > Global::banner_width) Global::banner_width = w;
|
if (auto w = ulen(line[1]); w > Global::banner_width) Global::banner_width = w;
|
||||||
fg = Theme::hex_to_color(line[0], !truecolor);
|
fg = Theme::hex_to_color(line[0], !truecolor);
|
||||||
bg_i = 120-z*12;
|
bg_i = 120-z*12;
|
||||||
bg = Theme::dec_to_color(bg_i, bg_i, bg_i, !truecolor);
|
bg = Theme::dec_to_color(bg_i, bg_i, bg_i, !truecolor);
|
||||||
|
@ -179,12 +180,8 @@ int main(int argc, char **argv){
|
||||||
std::atexit(_exit_handler);
|
std::atexit(_exit_handler);
|
||||||
|
|
||||||
#if defined(LINUX)
|
#if defined(LINUX)
|
||||||
//? Linux paths init
|
Global::coreCount = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
Global::proc_path = (fs::is_directory(fs::path("/proc")) && access("/proc", R_OK) != -1) ? "/proc" : "";
|
if (Global::coreCount < 1) Global::coreCount = 1;
|
||||||
if (Global::proc_path.empty()) {
|
|
||||||
cout << "ERROR: Proc filesystem not found or no permission to read from it!" << endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
Global::self_path = fs::read_symlink("/proc/self/exe", ec).remove_filename();
|
Global::self_path = fs::read_symlink("/proc/self/exe", ec).remove_filename();
|
||||||
|
@ -199,21 +196,18 @@ int main(int argc, char **argv){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Config::conf_dir.empty()) {
|
if (!Config::conf_dir.empty()) {
|
||||||
std::error_code ec;
|
if (std::error_code ec; !fs::is_directory(Config::conf_dir) && !fs::create_directories(Config::conf_dir, ec)) {
|
||||||
if (!fs::is_directory(Config::conf_dir) && !fs::create_directories(Config::conf_dir, ec)) {
|
|
||||||
cout << "WARNING: Could not create or access btop config directory. Logging and config saving disabled." << endl;
|
cout << "WARNING: Could not create or access btop config directory. Logging and config saving disabled." << endl;
|
||||||
cout << "Make sure your $HOME environment variable is correctly set to fix this." << endl;
|
cout << "Make sure your $HOME environment variable is correctly set to fix this." << endl;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::error_code ec;
|
|
||||||
Config::conf_file = Config::conf_dir / "btop.conf";
|
Config::conf_file = Config::conf_dir / "btop.conf";
|
||||||
Logger::logfile = Config::conf_dir / "btop.log";
|
Logger::logfile = Config::conf_dir / "btop.log";
|
||||||
Theme::user_theme_dir = Config::conf_dir / "themes";
|
Theme::user_theme_dir = Config::conf_dir / "themes";
|
||||||
if (!fs::exists(Theme::user_theme_dir) && !fs::create_directory(Theme::user_theme_dir, ec)) Theme::user_theme_dir.clear();
|
if (!fs::exists(Theme::user_theme_dir) && !fs::create_directory(Theme::user_theme_dir, ec)) Theme::user_theme_dir.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Global::self_path.empty()) {
|
if (std::error_code ec; !Global::self_path.empty()) {
|
||||||
std::error_code ec;
|
|
||||||
Theme::theme_dir = fs::canonical(Global::self_path / "../share/btop/themes", ec);
|
Theme::theme_dir = fs::canonical(Global::self_path / "../share/btop/themes", ec);
|
||||||
if (ec || access(Theme::theme_dir.c_str(), R_OK) == -1) Theme::theme_dir.clear();
|
if (ec || access(Theme::theme_dir.c_str(), R_OK) == -1) Theme::theme_dir.clear();
|
||||||
}
|
}
|
||||||
|
@ -245,6 +239,11 @@ int main(int argc, char **argv){
|
||||||
clean_quit(1);
|
clean_quit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LINUX)
|
||||||
|
//? Linux init
|
||||||
|
Proc::init();
|
||||||
|
#endif
|
||||||
|
|
||||||
//? Read config file if present
|
//? Read config file if present
|
||||||
Config::load();
|
Config::load();
|
||||||
// Config::setB("truecolor", false);
|
// Config::setB("truecolor", false);
|
||||||
|
@ -261,7 +260,7 @@ int main(int argc, char **argv){
|
||||||
//* ------------------------------------------------ TESTING ------------------------------------------------------
|
//* ------------------------------------------------ TESTING ------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
Global::debuginit = true;
|
Global::debuginit = false;
|
||||||
|
|
||||||
// cout << Theme("main_bg") << Term::clear << flush;
|
// cout << Theme("main_bg") << Term::clear << flush;
|
||||||
// bool thread_test = false;
|
// bool thread_test = false;
|
||||||
|
@ -436,7 +435,6 @@ int main(int argc, char **argv){
|
||||||
|
|
||||||
|
|
||||||
auto timestamp = time_ms();
|
auto timestamp = time_ms();
|
||||||
Proc::init();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -444,7 +442,7 @@ int main(int argc, char **argv){
|
||||||
string ostring;
|
string ostring;
|
||||||
uint64_t tsl, timestamp2, rcount = 0;
|
uint64_t tsl, timestamp2, rcount = 0;
|
||||||
list<uint64_t> avgtimes = {0};
|
list<uint64_t> avgtimes = {0};
|
||||||
uint timer = 1000;
|
uint timer = 2000;
|
||||||
bool filtering = false;
|
bool filtering = false;
|
||||||
bool reversing = false;
|
bool reversing = false;
|
||||||
int sortint = Proc::sort_map["cpu lazy"];
|
int sortint = Proc::sort_map["cpu lazy"];
|
||||||
|
@ -461,25 +459,28 @@ int main(int argc, char **argv){
|
||||||
|
|
||||||
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});
|
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" + Mv::save;
|
||||||
|
|
||||||
while (key != "q") {
|
while (key != "q") {
|
||||||
timestamp = time_micros();
|
timestamp = time_micros();
|
||||||
tsl = time_ms() + 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, Config::getB("proc_per_core"));
|
||||||
timestamp2 = time_micros();
|
timestamp2 = time_micros();
|
||||||
timestamp = timestamp2 - timestamp;
|
timestamp = timestamp2 - timestamp;
|
||||||
ostring.clear();
|
ostring.clear();
|
||||||
lc = 0;
|
lc = 0;
|
||||||
filter_cur = (filtering) ? Fx::bl + "█" + Fx::reset : "";
|
|
||||||
ostring = Mv::save + Mv::u(2) + Mv::r(20) + trans(rjust("Filter: " + filter + filter_cur + string(Term::width / 3, ' ') +
|
ostring = Mv::u(2) + Mv::l(Term::width) + Mv::r(12)
|
||||||
"Sorting: " + string(Proc::sort_array[sortint]), Term::width - 25, true, filtering)) + Mv::restore;
|
+ trans("Filter: " + filter + (filtering ? Fx::bl + "█" + Fx::reset : "")) + Mv::l(Term::width)
|
||||||
|
+ trans(rjust("Per core: " + (Config::getB("proc_per_core") ? "On "s : "Off"s) + " Sorting: "
|
||||||
|
+ string(Proc::sort_array[sortint]), Term::width - 3))
|
||||||
|
+ Mv::restore;
|
||||||
|
|
||||||
for (auto& p : plist){
|
for (auto& p : plist){
|
||||||
ostring += Mv::r(1) + greyscale[lc] + rjust(to_string(p.pid), 8) + " " + ljust(p.name, 16) + " " + ljust(p.cmd, Term::width - 66, true) + " " +
|
ostring += Mv::r(1) + greyscale[lc] + rjust(to_string(p.pid), 8) + " " + ljust(p.name, 16) + " " + ljust(p.cmd, Term::width - 66, true) + " "
|
||||||
rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ');
|
+ rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ')
|
||||||
ostring += (p.cpu_p > 100) ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4);
|
+ (p.cpu_p < 10 || p.cpu_p >= 100 ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4))
|
||||||
ostring += "\n";
|
+ "\n";
|
||||||
if (lc++ > Term::height - 21) break;
|
if (lc++ > Term::height - 21) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,6 +512,7 @@ int main(int argc, char **argv){
|
||||||
else if (key == "right") { if (++sortint > (int)Proc::sort_array.size() - 1) sortint = 0; }
|
else if (key == "right") { if (++sortint > (int)Proc::sort_array.size() - 1) sortint = 0; }
|
||||||
else if (key == "f") filtering = true;
|
else if (key == "f") filtering = true;
|
||||||
else if (key == "r") reversing = !reversing;
|
else if (key == "r") reversing = !reversing;
|
||||||
|
else if (key == "c") Config::flip("proc_per_core");
|
||||||
else if (key == "delete") filter.clear();
|
else if (key == "delete") filter.clear();
|
||||||
else continue;
|
else continue;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -112,23 +112,29 @@ namespace Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Set config value <name> to bool <value>
|
//* Set config value <name> to bool <value>
|
||||||
void setB(string name, bool value){
|
void set(string name, bool value){
|
||||||
bools.at(name) = value;
|
bools.at(name) = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Set config value <name> to int <value>
|
//* Set config value <name> to int <value>
|
||||||
void setI(string name, int value){
|
void set(string name, int value){
|
||||||
ints.at(name) = value;
|
ints.at(name) = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Set config value <name> to string <value>
|
//* Set config value <name> to string <value>
|
||||||
void setS(string name, string value){
|
void set(string name, string value){
|
||||||
strings.at(name) = value;
|
strings.at(name) = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//* Flip config bool value
|
||||||
|
void flip(string name){
|
||||||
|
bools.at(name) = !bools.at(name);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
void load(){
|
void load(){
|
||||||
if (conf_file.empty()) return;
|
if (conf_file.empty()) return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,21 +91,21 @@ namespace Draw {
|
||||||
|
|
||||||
//* Draw horizontal lines
|
//* Draw horizontal lines
|
||||||
for (uint hpos : {c.y, c.y + c.height - 1}){
|
for (uint hpos : {c.y, c.y + c.height - 1}){
|
||||||
out += Mv::to(hpos, c.x) + Symbols::h_line * (c.width - 1);
|
out += Mv::to(hpos, c.x) + Symbols::h_line * (c.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Draw vertical lines and fill if enabled
|
//* Draw vertical lines and fill if enabled
|
||||||
for (uint hpos : iota(c.y + 1, c.y + c.height - 1)){
|
for (uint hpos : iota(c.y + 1, c.y + c.height - 1)){
|
||||||
out += Mv::to(hpos, c.x) + Symbols::v_line +
|
out += Mv::to(hpos, c.x) + Symbols::v_line +
|
||||||
((c.fill) ? string(c.width - 2, ' ') : Mv::r(c.width - 2)) +
|
((c.fill) ? string(c.width - 1, ' ') : Mv::r(c.width - 1)) +
|
||||||
Symbols::v_line;
|
Symbols::v_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Draw corners
|
//* Draw corners
|
||||||
out += Mv::to(c.y, c.x) + Symbols::left_up +
|
out += Mv::to(c.y, c.x) + Symbols::left_up +
|
||||||
Mv::to(c.y, c.x + c.width - 1) + Symbols::right_up +
|
Mv::to(c.y, c.x + c.width) + Symbols::right_up +
|
||||||
Mv::to(c.y + c.height - 1, c.x) + Symbols::left_down +
|
Mv::to(c.y + c.height - 1, c.x) + Symbols::left_down +
|
||||||
Mv::to(c.y + c.height - 1, c.x + c.width - 1) + Symbols::right_down;
|
Mv::to(c.y + c.height - 1, c.x + c.width) + Symbols::right_down;
|
||||||
|
|
||||||
//* Draw titles if defined
|
//* Draw titles if defined
|
||||||
if (!c.title.empty()){
|
if (!c.title.empty()){
|
||||||
|
@ -117,7 +117,7 @@ namespace Draw {
|
||||||
Fx::ub + lcolor + Symbols::title_right;
|
Fx::ub + lcolor + Symbols::title_right;
|
||||||
}
|
}
|
||||||
|
|
||||||
return out + Fx::reset + Mv::to(c.y + 1, c.x + 1);
|
return out + Fx::reset + Mv::to(c.y + 1, c.x + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Class holding a percentage meter
|
//* Class holding a percentage meter
|
||||||
|
@ -203,7 +203,7 @@ namespace Draw {
|
||||||
ai++;
|
ai++;
|
||||||
}
|
}
|
||||||
//? Generate braille symbol from 5x5 2D vector
|
//? Generate braille symbol from 5x5 2D vector
|
||||||
graphs[current][horizon] += (height == 1 && result[0] + result[1] == 0) ? Mv::r(1) : graph_symbol[result[0] * 5 + result[1]];
|
graphs[current][horizon] += (height == 1 && result[0] + result[1] == 0) ? Mv::r(1) : graph_symbol[(result[0] * 5 + result[1])];
|
||||||
}
|
}
|
||||||
if (mult && i > data_offset) last = data_value;
|
if (mult && i > data_offset) last = data_value;
|
||||||
|
|
||||||
|
|
|
@ -81,10 +81,10 @@ namespace Input {
|
||||||
//* Poll keyboard & mouse input for <timeout> ms and return input availabilty as a bool
|
//* Poll keyboard & mouse input for <timeout> ms and return input availabilty as a bool
|
||||||
bool poll(int timeout=0){
|
bool poll(int timeout=0){
|
||||||
if (timeout < 1) return cin.rdbuf()->in_avail() > 0;
|
if (timeout < 1) return cin.rdbuf()->in_avail() > 0;
|
||||||
int timer = 0;
|
while (timeout > 0) {
|
||||||
while (timer++ * 10 <= timeout) {
|
|
||||||
if (cin.rdbuf()->in_avail() > 0) return true;
|
if (cin.rdbuf()->in_avail() > 0) return true;
|
||||||
sleep_ms( (timer * 10 <= timeout) ? 10 : timeout % 10);
|
sleep_ms(timeout < 10 ? timeout : 10);
|
||||||
|
timeout -= 10;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
148
src/btop_linux.h
148
src/btop_linux.h
|
@ -46,24 +46,18 @@ namespace fs = std::filesystem;
|
||||||
using namespace Tools;
|
using namespace Tools;
|
||||||
const auto SSmax = std::numeric_limits<streamsize>::max();
|
const auto SSmax = std::numeric_limits<streamsize>::max();
|
||||||
|
|
||||||
namespace Global {
|
|
||||||
|
|
||||||
fs::path proc_path;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||||
|
|
||||||
double system_uptime(){
|
namespace Tools {
|
||||||
string upstr;
|
double system_uptime(){
|
||||||
ifstream pread("/proc/uptime");
|
string upstr;
|
||||||
getline(pread, upstr, ' ');
|
ifstream pread("/proc/uptime");
|
||||||
pread.close();
|
getline(pread, upstr, ' ');
|
||||||
return stod(upstr);
|
pread.close();
|
||||||
|
return stod(upstr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
|
||||||
|
|
||||||
namespace Proc {
|
namespace Proc {
|
||||||
namespace {
|
namespace {
|
||||||
uint64_t tstamp;
|
uint64_t tstamp;
|
||||||
|
@ -81,6 +75,8 @@ namespace Proc {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs::path proc_path;
|
||||||
|
uint64_t old_cputimes = 0;
|
||||||
size_t numpids = 500;
|
size_t numpids = 500;
|
||||||
atomic<bool> stop (false);
|
atomic<bool> stop (false);
|
||||||
atomic<bool> running (false);
|
atomic<bool> running (false);
|
||||||
|
@ -99,36 +95,27 @@ namespace Proc {
|
||||||
//* 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 {
|
||||||
uint pid;
|
uint pid;
|
||||||
string name, cmd;
|
string name = "", cmd = "";
|
||||||
size_t threads;
|
size_t threads = 0;
|
||||||
string user;
|
string user = "";
|
||||||
uint64_t mem;
|
uint64_t mem = 0;
|
||||||
double cpu_p, cpu_c;
|
double cpu_p = 0.0, cpu_c = 0.0;
|
||||||
char state;
|
char state = '0';
|
||||||
int cpu_n, p_nice;
|
int cpu_n = 0, p_nice = 0;
|
||||||
uint ppid;
|
uint ppid = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//* Collects process information from /proc and returns a vector of proc_info structs
|
//* Collects process information from /proc and returns a vector of proc_info structs
|
||||||
auto collect(string sorting="pid", bool reverse=false, string filter=""){
|
auto collect(string sorting="pid", bool reverse=false, string filter="", bool per_core=true){
|
||||||
running.store(true);
|
running.store(true);
|
||||||
uint pid, ppid;
|
|
||||||
uint64_t cpu_t, rss_mem;
|
|
||||||
double cpu, cpu_s;
|
|
||||||
bool new_cache;
|
|
||||||
char state;
|
|
||||||
int cpu_n, p_nice;
|
|
||||||
size_t threads, s_pos, c_pos, s_count;
|
|
||||||
ifstream pread;
|
ifstream pread;
|
||||||
string pid_str, name, cmd, attr, user, instr, uid, status, tmpstr;
|
|
||||||
auto since_last = time_ms() - tstamp;
|
|
||||||
if (since_last < 1) since_last = 1;
|
|
||||||
auto uptime = system_uptime();
|
auto uptime = system_uptime();
|
||||||
auto sortint = (sort_map.contains(sorting)) ? sort_map[sorting] : 7;
|
auto sortint = (sort_map.contains(sorting)) ? sort_map[sorting] : 7;
|
||||||
vector<proc_info> procs;
|
vector<proc_info> procs;
|
||||||
procs.reserve((numpids + 10));
|
procs.reserve((numpids + 10));
|
||||||
numpids = 0;
|
numpids = 0;
|
||||||
|
int cmult = (per_core) ? Global::coreCount : 1;
|
||||||
|
|
||||||
//* Update uid_user map if /etc/passwd changed since last run
|
//* Update uid_user map if /etc/passwd changed since last run
|
||||||
if (!passwd_path.empty() && fs::last_write_time(passwd_path) != passwd_time) {
|
if (!passwd_path.empty() && fs::last_write_time(passwd_path) != passwd_time) {
|
||||||
|
@ -148,8 +135,18 @@ namespace Proc {
|
||||||
pread.close();
|
pread.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Iterate over all pids in /proc and get relevant values
|
//* Get cpu total times from /proc/stat
|
||||||
for (auto& d: fs::directory_iterator(Global::proc_path)){
|
uint64_t cputimes = 0;
|
||||||
|
pread.open(proc_path / "stat");
|
||||||
|
if (pread.good()) {
|
||||||
|
pread.ignore(SSmax, ' ');
|
||||||
|
for (uint64_t times; pread >> times; cputimes += times);
|
||||||
|
pread.close();
|
||||||
|
}
|
||||||
|
else return procs;
|
||||||
|
|
||||||
|
//* Iterate over all pids in /proc
|
||||||
|
for (auto& d: fs::directory_iterator(proc_path)){
|
||||||
if (pread.is_open()) pread.close();
|
if (pread.is_open()) pread.close();
|
||||||
if (stop.load()) {
|
if (stop.load()) {
|
||||||
procs.clear();
|
procs.clear();
|
||||||
|
@ -157,17 +154,16 @@ namespace Proc {
|
||||||
stop.store(false);
|
stop.store(false);
|
||||||
return procs;
|
return procs;
|
||||||
}
|
}
|
||||||
pid_str = d.path().filename();
|
|
||||||
cpu = 0.0; cpu_s = 0.0; cpu_t = 0; cpu_n = 0;
|
string pid_str = d.path().filename();
|
||||||
rss_mem = 0; threads = 0; state = '0'; ppid = 0; p_nice = 0;
|
bool new_cache = false;
|
||||||
new_cache = false;
|
|
||||||
if (d.is_directory() && isdigit(pid_str[0])) {
|
if (d.is_directory() && isdigit(pid_str[0])) {
|
||||||
numpids++;
|
numpids++;
|
||||||
pid = stoul(pid_str);
|
proc_info new_proc (stoul(pid_str));
|
||||||
|
|
||||||
//* Cache program name, command and username
|
//* Cache program name, command and username
|
||||||
if (!cache.contains(pid)) {
|
if (!cache.contains(new_proc.pid)) {
|
||||||
name.clear(); cmd.clear(); user.clear();
|
string name, cmd, user;
|
||||||
new_cache = true;
|
new_cache = true;
|
||||||
pread.open(d.path() / "comm");
|
pread.open(d.path() / "comm");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
|
@ -178,6 +174,7 @@ namespace Proc {
|
||||||
|
|
||||||
pread.open(d.path() / "cmdline");
|
pread.open(d.path() / "cmdline");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
|
string tmpstr = "";
|
||||||
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();
|
||||||
|
@ -186,10 +183,11 @@ namespace Proc {
|
||||||
|
|
||||||
pread.open(d.path() / "status");
|
pread.open(d.path() / "status");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
uid.clear();
|
string uid;
|
||||||
while (!pread.eof()){
|
while (!pread.eof()){
|
||||||
getline(pread, status, ':');
|
string line;
|
||||||
if (status == "Uid") {
|
getline(pread, line, ':');
|
||||||
|
if (line == "Uid") {
|
||||||
pread.ignore();
|
pread.ignore();
|
||||||
getline(pread, uid, '\t');
|
getline(pread, uid, '\t');
|
||||||
break;
|
break;
|
||||||
|
@ -201,25 +199,30 @@ namespace Proc {
|
||||||
user = (!uid.empty() && uid_user.contains(uid)) ? uid_user.at(uid) : uid;
|
user = (!uid.empty() && uid_user.contains(uid)) ? uid_user.at(uid) : uid;
|
||||||
}
|
}
|
||||||
else continue;
|
else continue;
|
||||||
cache[pid] = {name, cmd, user};
|
cache[new_proc.pid] = {name, cmd, user};
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Match filter if defined
|
//* Match filter if defined
|
||||||
if (!filter.empty()
|
if (!filter.empty()
|
||||||
&& pid_str.find(filter) == string::npos
|
&& pid_str.find(filter) == string::npos
|
||||||
&& cache[pid].name.find(filter) == string::npos
|
&& cache[new_proc.pid].name.find(filter) == string::npos
|
||||||
&& cache[pid].cmd.find(filter) == string::npos
|
&& cache[new_proc.pid].cmd.find(filter) == string::npos
|
||||||
&& cache[pid].user.find(filter) == string::npos) {
|
&& cache[new_proc.pid].user.find(filter) == string::npos) {
|
||||||
if (new_cache) cache.erase(pid);
|
if (new_cache) cache.erase(new_proc.pid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
new_proc.name = cache[new_proc.pid].name;
|
||||||
|
new_proc.cmd = cache[new_proc.pid].cmd;
|
||||||
|
new_proc.user = cache[new_proc.pid].user;
|
||||||
|
|
||||||
//* Parse /proc/[pid]/stat
|
//* Parse /proc/[pid]/stat
|
||||||
pread.open(d.path() / "stat");
|
pread.open(d.path() / "stat");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
|
string instr;
|
||||||
getline(pread, instr);
|
getline(pread, instr);
|
||||||
pread.close();
|
pread.close();
|
||||||
s_pos = 0; c_pos = 0; s_count = 0;
|
size_t s_pos = 0, c_pos = 0, s_count = 0;
|
||||||
|
uint64_t cpu_t = 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;
|
||||||
|
@ -231,11 +234,11 @@ namespace Proc {
|
||||||
|
|
||||||
switch (s_count) {
|
switch (s_count) {
|
||||||
case 0: { //? Process state
|
case 0: { //? Process state
|
||||||
state = instr[s_pos];
|
new_proc.state = instr[s_pos];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: { //? Process parent pid
|
case 1: { //? Process parent pid
|
||||||
ppid = stoul(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.ppid = stoul(instr.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 11: { //? Process utime
|
case 11: { //? Process utime
|
||||||
|
@ -247,22 +250,19 @@ namespace Proc {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 16: { //? Process nice value
|
case 16: { //? Process nice value
|
||||||
p_nice = stoi(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.p_nice = stoi(instr.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 17: { //? Process number of threads
|
case 17: { //? Process number of threads
|
||||||
threads = stoul(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.threads = stoul(instr.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 19: { //? Cache cpu times and cpu seconds
|
case 19: { //? Cache cpu seconds
|
||||||
if (new_cache) {
|
if (new_cache) cache[new_proc.pid].cpu_s = stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||||
cache[pid].cpu_t = cpu_t;
|
|
||||||
cache[pid].cpu_s = stoull(instr.substr(s_pos, c_pos - s_pos));
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 36: { //? CPU number last executed on
|
case 36: { //? CPU number last executed on
|
||||||
cpu_n = stoi(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.cpu_n = stoi(instr.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,14 +271,14 @@ namespace Proc {
|
||||||
|
|
||||||
if (s_count < 19) continue;
|
if (s_count < 19) continue;
|
||||||
|
|
||||||
//? Process cpu usage since last update, 100'000 because (100 percent * 1000 milliseconds) for correct conversion
|
//? Process cpu usage since last update
|
||||||
cpu = static_cast<double>(100000 * (cpu_t - cache[pid].cpu_t) / since_last) / clk_tck;
|
new_proc.cpu_p = round(cmult * 1000 * (cpu_t - cache[new_proc.pid].cpu_t) / (cputimes - old_cputimes)) / 10.0;
|
||||||
|
|
||||||
//? Process cumulative cpu usage since process start
|
//? Process cumulative cpu usage since process start
|
||||||
cpu_s = static_cast<double>((cpu_t / clk_tck) / (uptime - (cache[pid].cpu_s / clk_tck)));
|
new_proc.cpu_c = ((double)cpu_t / clk_tck) / (uptime - (cache[new_proc.pid].cpu_s / clk_tck));
|
||||||
|
|
||||||
//? Update cache with latest cpu times
|
//? Update cache with latest cpu times
|
||||||
cache[pid].cpu_t = cpu_t;
|
cache[new_proc.pid].cpu_t = cpu_t;
|
||||||
}
|
}
|
||||||
else continue;
|
else continue;
|
||||||
|
|
||||||
|
@ -286,13 +286,13 @@ namespace Proc {
|
||||||
pread.open(d.path() / "statm");
|
pread.open(d.path() / "statm");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
pread.ignore(SSmax, ' ');
|
pread.ignore(SSmax, ' ');
|
||||||
pread >> rss_mem;
|
pread >> new_proc.mem;
|
||||||
pread.close();
|
pread.close();
|
||||||
rss_mem *= page_size;
|
new_proc.mem *= page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Create proc_info
|
//* Create proc_info
|
||||||
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);
|
procs.push_back(new_proc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,12 +329,14 @@ namespace Proc {
|
||||||
unordered_flat_map<uint, p_cache> r_cache;
|
unordered_flat_map<uint, p_cache> r_cache;
|
||||||
r_cache.reserve(procs.size());
|
r_cache.reserve(procs.size());
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
Logger::debug("Cleared proc cache");
|
||||||
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.swap(r_cache);
|
cache.swap(r_cache);
|
||||||
}
|
}
|
||||||
else cache.clear();
|
else cache.clear();
|
||||||
}
|
}
|
||||||
|
old_cputimes = cputimes;
|
||||||
tstamp = time_ms();
|
tstamp = time_ms();
|
||||||
running.store(false);
|
running.store(false);
|
||||||
return procs;
|
return procs;
|
||||||
|
@ -343,6 +345,15 @@ namespace Proc {
|
||||||
//* Initialize needed variables for collect
|
//* Initialize needed variables for collect
|
||||||
void init(){
|
void init(){
|
||||||
tstamp = time_ms();
|
tstamp = time_ms();
|
||||||
|
|
||||||
|
proc_path = (fs::is_directory(fs::path("/proc")) && access("/proc", R_OK) != -1) ? "/proc" : "";
|
||||||
|
if (proc_path.empty()) {
|
||||||
|
string errmsg = "Proc filesystem not found or no permission to read from it!";
|
||||||
|
Logger::error(errmsg);
|
||||||
|
cout << "ERROR: " << errmsg << endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path;
|
passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path;
|
||||||
if (passwd_path.empty()) Logger::warning("Could not read /etc/passwd, will show UID instead of username.");
|
if (passwd_path.empty()) Logger::warning("Could not read /etc/passwd, will show UID instead of username.");
|
||||||
|
|
||||||
|
@ -352,7 +363,6 @@ namespace Proc {
|
||||||
Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect.");
|
Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
clk_tck = sysconf(_SC_CLK_TCK);
|
clk_tck = sysconf(_SC_CLK_TCK);
|
||||||
if (clk_tck <= 0) {
|
if (clk_tck <= 0) {
|
||||||
clk_tck = 100;
|
clk_tck = 100;
|
||||||
|
|
|
@ -85,7 +85,7 @@ namespace Theme {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
//* Convert 24-bit colors to 256 colors using 6x6x6 color cube
|
//* Convert 24-bit colors to 256 colors using 6x6x6 color cube
|
||||||
int truecolor_to_256(uint r, uint g, uint b){
|
int truecolor_to_256(int r, int g, int b){
|
||||||
if (round((double)r / 11) == round((double)g / 11) && round((double)g / 11) == round((double)b / 11)) {
|
if (round((double)r / 11) == round((double)g / 11) && round((double)g / 11) == round((double)b / 11)) {
|
||||||
return 232 + round((double)r / 11);
|
return 232 + round((double)r / 11);
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,12 +105,10 @@ namespace Theme {
|
||||||
Logger::error("Invalid hex value: " + hexa);
|
Logger::error("Invalid hex value: " + hexa);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
depth = (depth == "fg") ? "38" : "48";
|
string pre = Fx::e + (depth == "fg" ? "38" : "48") + ";" + (t_to_256 ? "5;" : "2;");
|
||||||
string pre = Fx::e + depth + ";";
|
|
||||||
pre += (t_to_256) ? "5;" : "2;";
|
|
||||||
|
|
||||||
if (hexa.size() == 2){
|
if (hexa.size() == 2){
|
||||||
uint h_int = stoi(hexa, 0, 16);
|
int h_int = stoi(hexa, 0, 16);
|
||||||
if (t_to_256){
|
if (t_to_256){
|
||||||
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
|
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
|
||||||
} else {
|
} else {
|
||||||
|
@ -133,7 +131,7 @@ namespace Theme {
|
||||||
}
|
}
|
||||||
else Logger::error("Invalid size of hex value: " + hexa);
|
else Logger::error("Invalid size of hex value: " + hexa);
|
||||||
}
|
}
|
||||||
else Logger::error("Hex value missing." + hexa);
|
else Logger::error("Hex value missing: " + hexa);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,13 +139,11 @@ namespace Theme {
|
||||||
//* Args r: [0-255], g: [0-255], b: [0-255]
|
//* Args r: [0-255], g: [0-255], b: [0-255]
|
||||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||||
string dec_to_color(uint r, uint g, uint b, bool t_to_256=false, string depth="fg"){
|
string dec_to_color(int r, int g, int b, bool t_to_256=false, string depth="fg"){
|
||||||
depth = (depth == "fg") ? "38" : "48";
|
string pre = Fx::e + (depth == "fg" ? "38" : "48") + ";" + (t_to_256 ? "5;" : "2;");
|
||||||
string pre = Fx::e + depth + ";";
|
r = std::clamp(r, 0, 255);
|
||||||
pre += (t_to_256) ? "5;" : "2;";
|
g = std::clamp(g, 0, 255);
|
||||||
r = min(r, 255u);
|
b = std::clamp(b, 0, 255);
|
||||||
g = min(g, 255u);
|
|
||||||
b = min(b, 255u);
|
|
||||||
if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m";
|
if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m";
|
||||||
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
||||||
}
|
}
|
||||||
|
@ -229,15 +225,13 @@ namespace Theme {
|
||||||
void generateGradients(){
|
void generateGradients(){
|
||||||
gradients.clear();
|
gradients.clear();
|
||||||
array<string, 101> c_gradient;
|
array<string, 101> c_gradient;
|
||||||
string wname;
|
|
||||||
bool t_to_256 = !Config::getB("truecolor");
|
bool t_to_256 = !Config::getB("truecolor");
|
||||||
array<array<int, 3>, 3> rgb_arr;
|
|
||||||
array<array<int, 3>, 101> dec_arr;
|
|
||||||
for (auto& [name, source_arr] : rgbs) {
|
for (auto& [name, source_arr] : rgbs) {
|
||||||
if (!name.ends_with("_start")) continue;
|
if (!name.ends_with("_start")) continue;
|
||||||
|
array<array<int, 3>, 101> dec_arr;
|
||||||
dec_arr[0][0] = -1;
|
dec_arr[0][0] = -1;
|
||||||
wname = rtrim(name, "_start");
|
string wname = rtrim(name, "_start");
|
||||||
rgb_arr = {source_arr, rgbs[wname + "_mid"], rgbs[wname + "_end"]};
|
array<array<int, 3>, 3> rgb_arr = {source_arr, rgbs[wname + "_mid"], rgbs[wname + "_end"]};
|
||||||
|
|
||||||
//? Only start iteration if gradient has a _end color value defined
|
//? Only start iteration if gradient has a _end color value defined
|
||||||
if (rgb_arr[2][0] >= 0) {
|
if (rgb_arr[2][0] >= 0) {
|
||||||
|
|
|
@ -93,19 +93,19 @@ namespace Fx {
|
||||||
//* Collection of escape codes and functions for cursor manipulation
|
//* Collection of escape codes and functions for cursor manipulation
|
||||||
namespace Mv {
|
namespace Mv {
|
||||||
//* Move cursor to <line>, <column>
|
//* Move cursor to <line>, <column>
|
||||||
const string to(int line, int col){ return Fx::e + to_string(line) + ";" + to_string(col) + "f";}
|
string to(int line, int col){ return Fx::e + to_string(line) + ";" + to_string(col) + "f";}
|
||||||
|
|
||||||
//* Move cursor right <x> columns
|
//* Move cursor right <x> columns
|
||||||
const string r(int x){ return Fx::e + to_string(x) + "C";}
|
string r(int x){ return Fx::e + to_string(x) + "C";}
|
||||||
|
|
||||||
//* Move cursor left <x> columns
|
//* Move cursor left <x> columns
|
||||||
const string l(int x){ return Fx::e + to_string(x) + "D";}
|
string l(int x){ return Fx::e + to_string(x) + "D";}
|
||||||
|
|
||||||
//* Move cursor up x lines
|
//* Move cursor up x lines
|
||||||
const string u(int x){ return Fx::e + to_string(x) + "A";}
|
string u(int x){ return Fx::e + to_string(x) + "A";}
|
||||||
|
|
||||||
//* Move cursor down x lines
|
//* Move cursor down x lines
|
||||||
const string d(int x) { return Fx::e + to_string(x) + "B";}
|
string d(int x) { return Fx::e + to_string(x) + "B";}
|
||||||
|
|
||||||
//* Save cursor position
|
//* Save cursor position
|
||||||
const string save = Fx::e + "s";
|
const string save = Fx::e + "s";
|
||||||
|
@ -135,18 +135,19 @@ namespace Term {
|
||||||
return 0 == tcsetattr(STDIN_FILENO, TCSANOW, &settings);
|
return 0 == tcsetattr(STDIN_FILENO, TCSANOW, &settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Refresh variables holding current terminal width and height and return true if resized
|
//* Toggle need for return key when reading input
|
||||||
bool refresh(){
|
bool linebuffered(bool on=true){
|
||||||
struct winsize w;
|
struct termios settings;
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
if (tcgetattr(STDIN_FILENO, &settings)) return false;
|
||||||
resized = (width != w.ws_col || height != w.ws_row) ? true : false;
|
if (on) settings.c_lflag |= ICANON;
|
||||||
width = w.ws_col;
|
else settings.c_lflag &= ~(ICANON);
|
||||||
height = w.ws_row;
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false;
|
||||||
return resized;
|
if (on) setlinebuf(stdin);
|
||||||
|
else setbuf(stdin, NULL);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//* Hide terminal cursor
|
//* Hide terminal cursor
|
||||||
const string hide_cursor = Fx::e + "?25l";
|
const string hide_cursor = Fx::e + "?25l";
|
||||||
|
|
||||||
|
@ -180,20 +181,18 @@ namespace Term {
|
||||||
//* Disable direct mouse reporting
|
//* Disable direct mouse reporting
|
||||||
const string mouse_direct_off = Fx::e + "?1003l";
|
const string mouse_direct_off = Fx::e + "?1003l";
|
||||||
|
|
||||||
//* Toggle need for return key when reading input
|
//* Refresh variables holding current terminal width and height and return true if resized
|
||||||
bool linebuffered(bool on=true){
|
bool refresh(){
|
||||||
struct termios settings;
|
struct winsize w;
|
||||||
if (tcgetattr(STDIN_FILENO, &settings)) return false;
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
if (on) settings.c_lflag |= ICANON;
|
if (width != w.ws_col || height != w.ws_row) {
|
||||||
else settings.c_lflag &= ~(ICANON);
|
width = w.ws_col;
|
||||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false;
|
height = w.ws_row;
|
||||||
if (on) setlinebuf(stdin);
|
resized = true;
|
||||||
else setbuf(stdin, NULL);
|
}
|
||||||
return true;
|
return resized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//* Check for a valid tty, save terminal options and set new options
|
//* Check for a valid tty, save terminal options and set new options
|
||||||
bool init(){
|
bool init(){
|
||||||
if (!initialized){
|
if (!initialized){
|
||||||
|
@ -408,34 +407,16 @@ namespace Tools {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Repeat string <str> <n> number of times
|
//* Add std::string operator "*" : Repeat string <str> <n> number of times
|
||||||
string repeat(string str, const size_t n){
|
|
||||||
if (n == 0){
|
|
||||||
str.clear();
|
|
||||||
str.shrink_to_fit();
|
|
||||||
return str;
|
|
||||||
} else if (n == 1 || str.empty()){
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
const auto period = str.size();
|
|
||||||
if (period == 1){
|
|
||||||
str.append(n - 1, str.front());
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
str.reserve(period * n);
|
|
||||||
size_t m = 2;
|
|
||||||
for (; m < n; m *= 2) str += str;
|
|
||||||
str.append(str.c_str(), (n - (m / 2)) * period);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
//* String gets passed to repeat function
|
|
||||||
std::string operator*(string str, size_t n){
|
std::string operator*(string str, size_t n){
|
||||||
return repeat(std::move(str), n);
|
string out;
|
||||||
|
out.reserve(str.size() * n);
|
||||||
|
while (n-- > 0) out += str;
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Return current time in <strf> format
|
//* Return current time in <strf> format
|
||||||
std::string strf_time(std::string strf){
|
string strf_time(string strf){
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||||
std::tm bt {};
|
std::tm bt {};
|
||||||
|
@ -468,11 +449,11 @@ namespace Logger {
|
||||||
if (loglevel < level || logfile.empty()) return;
|
if (loglevel < level || logfile.empty()) return;
|
||||||
busy.wait(true); busy.store(true);
|
busy.wait(true); busy.store(true);
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
if (fs::file_size(logfile, ec) > 1024 << 10) {
|
if (fs::file_size(logfile, ec) > 1024 << 10 && !ec) {
|
||||||
auto old_log = logfile;
|
auto old_log = logfile;
|
||||||
old_log += ".1";
|
old_log += ".1";
|
||||||
if (fs::exists(old_log)) fs::remove(old_log, ec);
|
if (fs::exists(old_log)) fs::remove(old_log, ec);
|
||||||
fs::rename(logfile, old_log, ec);
|
if (!ec) fs::rename(logfile, old_log, ec);
|
||||||
}
|
}
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
std::ofstream lwrite(logfile, std::ios::app);
|
std::ofstream lwrite(logfile, std::ios::app);
|
||||||
|
@ -480,6 +461,7 @@ namespace Logger {
|
||||||
lwrite << Tools::strf_time(tdf) << log_levels[level] << ": " << msg << "\n";
|
lwrite << Tools::strf_time(tdf) << log_levels[level] << ": " << msg << "\n";
|
||||||
lwrite.close();
|
lwrite.close();
|
||||||
}
|
}
|
||||||
|
else logfile.clear();
|
||||||
busy.store(false);
|
busy.store(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue