From 86c1b2add5389c09089840ac677ad72a7ebcb827 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Sat, 13 Jul 2024 20:45:06 -0700 Subject: [PATCH] revise psutil.cc for correct stats --- lib/bridge.cc | 23 ++-- lib/fork.cc | 128 +++++++++---------- lib/include/bridge.h | 2 +- lib/include/fork.h | 10 +- lib/include/process.h | 2 +- lib/include/psutil.h | 2 +- lib/process.cc | 53 ++++---- lib/psutil.cc | 144 ++++++++++++---------- src/cli/internal.rs | 8 +- src/daemon/api/routes.rs | 14 +-- src/daemon/mod.rs | 2 +- src/webui/src/components/react/status.tsx | 4 +- 12 files changed, 201 insertions(+), 191 deletions(-) diff --git a/lib/bridge.cc b/lib/bridge.cc index f53737a..9b8ca52 100644 --- a/lib/bridge.cc +++ b/lib/bridge.cc @@ -1,5 +1,6 @@ -#include -#include +#include "include/bridge.h" +#include "include/process.h" + #include #include #include @@ -9,29 +10,27 @@ #include #ifdef __linux__ -#include -#include #include +#include #include +#include #include #elif __APPLE__ +#include +#include #include #include -#include -#include -#include -#include #endif using namespace std; -void set_program_name(String name) { - #ifdef __linux__ +extern "C++" void set_program_name(String name) { +#ifdef __linux__ prctl(PR_SET_NAME, name.c_str()); - #elif __APPLE__ +#elif __APPLE__ setprogname(name.c_str()); - #endif +#endif } int64_t get_child_pid(int64_t parentPID) { diff --git a/lib/fork.cc b/lib/fork.cc index 91a0ca4..85fe6d5 100644 --- a/lib/fork.cc +++ b/lib/fork.cc @@ -1,9 +1,10 @@ -#include -#include +#include "include/fork.h" + #include +#include #include +#include #include -#include #ifdef _WIN32 #include @@ -15,79 +16,78 @@ using namespace std; std::string home() { - #ifdef _WIN32 - const char* userProfile = std::getenv("USERPROFILE"); - if (userProfile) { - return std::string(userProfile); - } else { - return ""; - } - #else - struct passwd* pw = getpwuid(getuid()); - if (pw && pw->pw_dir) { - return std::string(pw->pw_dir); - } else { - return ""; - } - #endif +#ifdef _WIN32 + const char *userProfile = std::getenv("USERPROFILE"); + if (userProfile) { + return std::string(userProfile); + } else { + return ""; + } +#else + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_dir) { + return std::string(pw->pw_dir); + } else { + return ""; + } +#endif } - Fork fork_process() { - pid_t res = ::fork(); - if (res == -1) { - perror("fork_process"); - throw std::runtime_error("fork() failed"); - } else if (res == 0) { - return Fork::Child; - } else { - return Fork::Parent; - } + pid_t res = ::fork(); + if (res == -1) { + perror("fork_process"); + throw std::runtime_error("fork() failed"); + } else if (res == 0) { + return Fork::Child; + } else { + return Fork::Parent; + } } pid_t set_sid() { - pid_t res = ::setsid(); - if (res == -1) { - perror("set_sid"); - throw std::runtime_error("setsid() failed"); - } - return res; + pid_t res = ::setsid(); + if (res == -1) { + perror("set_sid"); + throw std::runtime_error("setsid() failed"); + } + return res; } void close_fd() { - bool res = false; - for (int i = 0; i <= 2; ++i) { - res |= (::close(i) == -1); - } + bool res = false; + for (int i = 0; i <= 2; ++i) { + res |= (::close(i) == -1); + } - if (res) { - perror("close_fd"); - throw std::runtime_error("close_fd() failed"); - } + if (res) { + perror("close_fd"); + throw std::runtime_error("close_fd() failed"); + } } int32_t try_fork(bool nochdir, bool noclose, Callback callback) { - try { - Fork forkResult = fork_process(); - if (forkResult == Fork::Parent) { - exit(0); - } else if (forkResult == Fork::Child) { - set_sid(); - if (!nochdir) { - std::string home_dir = home() + ".pmc"; - chdir(home_dir.c_str()); - } - if (!noclose) { - close_fd(); - } - forkResult = fork_process(); - } - return static_cast(forkResult); - } catch (const std::exception& e) { - std::cerr << "[PMC] (cc) Error setting up daemon handler\n"; - perror("try_fork"); + try { + Fork forkResult = fork_process(); + if (forkResult == Fork::Parent) { + exit(0); + } else if (forkResult == Fork::Child) { + set_sid(); + if (!nochdir) { + std::string home_dir = home() + ".pmc"; + chdir(home_dir.c_str()); + } + if (!noclose) { + close_fd(); + } + forkResult = fork_process(); } - - callback(); - return -1; + return static_cast(forkResult); + } catch (const std::exception &e) { + std::cerr << "[PMC] (cc) Error setting up daemon handler\n"; + perror("try_fork"); + } + + callback(); + return -1; } \ No newline at end of file diff --git a/lib/include/bridge.h b/lib/include/bridge.h index 57fefb5..ed33639 100644 --- a/lib/include/bridge.h +++ b/lib/include/bridge.h @@ -1,7 +1,7 @@ #ifndef BRIDGE_H #define BRIDGE_H -#include +#include "rust.h" using namespace rust; #ifndef CXXBRIDGE1_STRUCT_ProcessMetadata diff --git a/lib/include/fork.h b/lib/include/fork.h index 7ce089a..fe1550e 100644 --- a/lib/include/fork.h +++ b/lib/include/fork.h @@ -1,18 +1,18 @@ #ifndef FORK_H #define FORK_H -#include #include +#include #ifndef CXXBRIDGE1_ENUM_Fork #define CXXBRIDGE1_ENUM_Fork -enum class Fork: std::uint8_t { - Parent, - Child +enum class Fork: std::uint8_t { + Parent, + Child }; #endif -using Callback = void(*)(); +using Callback = void (*)(); pid_t set_sid(); void close_fd(); Fork fork_process(); diff --git a/lib/include/process.h b/lib/include/process.h index fe721c7..81c0c2b 100644 --- a/lib/include/process.h +++ b/lib/include/process.h @@ -1,7 +1,7 @@ #ifndef PROCESS_H #define PROCESS_H -#include +#include "rust.h" using namespace rust; namespace process { diff --git a/lib/include/psutil.h b/lib/include/psutil.h index abefd9e..f98c476 100644 --- a/lib/include/psutil.h +++ b/lib/include/psutil.h @@ -1,7 +1,7 @@ #ifndef PSUTIL_H #define PSUTIL_H -#include +#include "rust.h" using namespace rust; extern "C++" double get_process_cpu_usage_percentage(int64_t pid); diff --git a/lib/process.cc b/lib/process.cc index 679844b..00deb88 100644 --- a/lib/process.cc +++ b/lib/process.cc @@ -1,18 +1,19 @@ -#include -#include -#include -#include -#include -#include -#include -#include +#include "include/process.h" + #include +#include +#include #include +#include +#include #include +#include +#include +#include #ifdef __APPLE__ -#include #include +#include #endif using namespace std; @@ -21,18 +22,18 @@ namespace process { volatile sig_atomic_t childExitStatus = 0; std::string format(std::string text) { - std::replace(text.begin(), text.end(), ' ', '_'); - return text; + std::replace(text.begin(), text.end(), ' ', '_'); + return text; } -pair split(const std::string& str) { - size_t length = str.length(); - size_t midpoint = length / 2; +pair split(const std::string &str) { + size_t length = str.length(); + size_t midpoint = length / 2; - std::string firstHalf = str.substr(0, midpoint); - std::string secondHalf = str.substr(midpoint); + std::string firstHalf = str.substr(0, midpoint); + std::string secondHalf = str.substr(midpoint); - return make_pair(firstHalf, secondHalf); + return make_pair(firstHalf, secondHalf); } void sigchld_handler(int signo) { @@ -47,7 +48,7 @@ void Runner::New(const std::string &name, const std::string &logPath) { std::string formattedName = format(name); std::string stdoutFileName = logPath + "/" + formattedName + "-out.log"; std::string stderrFileName = logPath + "/" + formattedName + "-error.log"; - + stdout_fd = open(stdoutFileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644); stderr_fd = open(stderrFileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644); @@ -87,9 +88,9 @@ int64_t Runner::Run(const std::string &command, const std::string &shell, Vec argsArray; - std::vector envArray; + + std::vector argsArray; + std::vector envArray; argsArray.push_back(shell.c_str()); transform(args.begin(), args.end(), std::back_inserter(argsArray), @@ -99,8 +100,8 @@ int64_t Runner::Run(const std::string &command, const std::string &shell, Vec(argsArray.data()), const_cast(envArray.data())) == -1) { std::cerr << "[PMC] (cc) Unable to execute the command\n"; @@ -110,7 +111,7 @@ int64_t Runner::Run(const std::string &command, const std::string &shell, Vec #include -#include #ifdef __APPLE__ #include #include #include #else +#include +#include #include #include -#include -#include #include +#include +#include #endif int get_num_cores() { #ifdef __APPLE__ - int nm[2]; - size_t len = 4; - uint32_t count; - - nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - - if(count < 1) { - nm[1] = HW_NCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - } - return count > 0 ? static_cast(count) : 1; + int nm[2]; + size_t len = 4; + uint32_t count; + + nm[0] = CTL_HW; + nm[1] = HW_AVAILCPU; + sysctl(nm, 2, &count, &len, NULL, 0); + + if (count < 1) { + nm[1] = HW_NCPU; + sysctl(nm, 2, &count, &len, NULL, 0); + } + + return count > 0 ? static_cast(count) : 1; #else - return static_cast(sysconf(_SC_NPROCESSORS_ONLN)); + return static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #endif } double get_cpu_time(int64_t pid) { #ifdef __APPLE__ - struct proc_taskinfo pti; - int ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); - if (ret <= 0) { - return 0.0; - } - return (pti.pti_total_user + pti.pti_total_system) / 1e9; + struct proc_taskinfo pti; + int ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); + + if (ret <= 0) { + return 0.0; + } + + return (pti.pti_total_user + pti.pti_total_system) / 1e9; #else - std::string stat_path = "/proc/" + std::to_string(pid) + "/stat"; - std::ifstream stat_file(stat_path); - - if (!stat_file.is_open()) { - return 0.0; - } - - std::string line; - std::getline(stat_file, line); - - std::istringstream iss(line); - std::string token; - std::vector tokens; - - while (std::getline(iss, token, ' ')) { - tokens.push_back(token); - } - - if (tokens.size() < 15) { - return 0.0; - } - - unsigned long long utime = std::stoull(tokens[13]); - unsigned long long stime = std::stoull(tokens[14]); - - return (utime + stime) / sysconf(_SC_CLK_TCK); + std::string stat_path = "/proc/" + std::to_string(pid) + "/stat"; + std::ifstream stat_file(stat_path); + + if (!stat_file.is_open()) { + std::cerr << "Failed to open " << stat_path << std::endl; + return -1.0; + } + + std::string line; + std::getline(stat_file, line); + + std::istringstream iss(line); + std::string token; + std::vector tokens; + + while (std::getline(iss, token, ' ')) { + tokens.push_back(token); + } + + if (tokens.size() < 15) { + std::cerr << "Unexpected format in " << stat_path << std::endl; + return -1.0; + } + + unsigned long long utime = std::stoull(tokens[13]); + unsigned long long stime = std::stoull(tokens[14]); + double ticks_per_second = static_cast(sysconf(_SC_CLK_TCK)); + + return (utime + stime) / ticks_per_second; #endif } -extern "C++" double get_process_cpu_usage_percentage(int64_t pid) { - const std::chrono::milliseconds measurement_interval(300); +double get_process_cpu_usage_percentage(int64_t pid) { + const std::chrono::milliseconds measurement_interval(100); + double cpu_time_start = get_cpu_time(pid); - double cpu_time_start = get_cpu_time(pid); - if (cpu_time_start < 0) { - return 0.0; - } + if (cpu_time_start < 0) { + return 0.0; + } - auto start_time = std::chrono::steady_clock::now(); - std::this_thread::sleep_for(measurement_interval); - auto end_time = std::chrono::steady_clock::now(); + auto start_time = std::chrono::steady_clock::now(); + std::this_thread::sleep_for(measurement_interval); + auto end_time = std::chrono::steady_clock::now(); - double cpu_time_end = get_cpu_time(pid); - if (cpu_time_end < 0) { - return 0.0; - } + double cpu_time_end = get_cpu_time(pid); + if (cpu_time_end < 0) { + return 0.0; + } - double cpu_time_diff = cpu_time_end - cpu_time_start; - std::chrono::duration elapsed = end_time - start_time; - double elapsed_seconds = elapsed.count(); - double cpu_usage_percentage = (cpu_time_diff / elapsed_seconds) * 100.0; + long num_cores = get_num_cores(); + double cpu_time_diff = cpu_time_end - cpu_time_start; + std::chrono::duration elapsed = end_time - start_time; - long num_cores = get_num_cores(); + double elapsed_seconds = elapsed.count(); + double cpu_usage_percentage = (cpu_time_diff / elapsed_seconds) * (100.0 * num_cores); - return std::min(cpu_usage_percentage, 100.0 * num_cores); + return std::min(cpu_usage_percentage, 100.0 * num_cores); } \ No newline at end of file diff --git a/src/cli/internal.rs b/src/cli/internal.rs index 70718a3..cd428f7 100644 --- a/src/cli/internal.rs +++ b/src/cli/internal.rs @@ -283,7 +283,7 @@ impl<'i> Internal<'i> { let cpu_percent = match cpu_percent { Some(percent) => format!("{:.2}%", percent), - None => string!("0%"), + None => string!("0.00%"), }; let memory_usage = match memory_usage { @@ -361,7 +361,7 @@ impl<'i> Internal<'i> { let cpu_percent = match stats.cpu_percent { Some(percent) => format!("{percent:.2}%"), - None => string!("0%"), + None => string!("0.00%"), }; let memory_usage = match stats.memory_usage { @@ -544,7 +544,7 @@ impl<'i> Internal<'i> { cpu_percent = match usage_internals.0 { Some(percent) => format!("{:.2}%", percent), - None => string!("0%"), + None => string!("0.00%"), }; memory_usage = match usage_internals.1 { @@ -559,7 +559,7 @@ impl<'i> Internal<'i> { cpu_percent = match stats.cpu_percent { Some(percent) => format!("{:.2}%", percent), - None => string!("0%"), + None => string!("0.00%"), }; memory_usage = match stats.memory_usage { diff --git a/src/daemon/api/routes.rs b/src/daemon/api/routes.rs index b284a44..e3258c3 100644 --- a/src/daemon/api/routes.rs +++ b/src/daemon/api/routes.rs @@ -4,7 +4,7 @@ use chrono::{DateTime, Utc}; use global_placeholders::global; use macros_rs::{fmtstr, string, ternary, then}; use prometheus::{Encoder, TextEncoder}; -use psutil::process::{MemoryInfo, Process}; +use psutil::process::Process; use reqwest::header::HeaderValue; use tera::Context; use utoipa::ToSchema; @@ -116,7 +116,7 @@ pub struct MetricsRoot { #[derive(Serialize, Deserialize, ToSchema)] pub struct Raw { - pub memory_usage: Option, + pub memory_usage: Option, pub cpu_percent: Option, } @@ -795,7 +795,7 @@ pub async fn get_metrics() -> MetricsRoot { let mut pid: Option = None; let mut cpu_percent: Option = None; let mut uptime: Option> = None; - let mut memory_usage: Option = None; + let mut memory_usage: Option = None; let mut runner: Runner = file::read_object(global!("pmc.dump")); HTTP_COUNTER.inc(); @@ -804,20 +804,20 @@ pub async fn get_metrics() -> MetricsRoot { if let Ok(process) = Process::new(process_id.get()) { pid = Some(process_id); uptime = Some(pid::uptime().unwrap()); - memory_usage = process.memory_info().ok(); + memory_usage = Some(process.memory_info().unwrap().rss()); cpu_percent = Some(pmc::service::get_process_cpu_usage_percentage(process_id.get::())); } } } - let memory_usage_fmt = match &memory_usage { - Some(usage) => helpers::format_memory(usage.rss()), + let memory_usage_fmt = match memory_usage { + Some(usage) => helpers::format_memory(usage), None => string!("0b"), }; let cpu_percent_fmt = match cpu_percent { Some(percent) => format!("{:.2}%", percent), - None => string!("0%"), + None => string!("0.00%"), }; let uptime_fmt = match uptime { diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs index a01640c..82ec9f3 100644 --- a/src/daemon/mod.rs +++ b/src/daemon/mod.rs @@ -137,7 +137,7 @@ pub fn health(format: &String) { let cpu_percent = match cpu_percent { Some(percent) => format!("{:.2}%", percent), - None => string!("0%"), + None => string!("0.00%"), }; let memory_usage = match memory_usage { diff --git a/src/webui/src/components/react/status.tsx b/src/webui/src/components/react/status.tsx index 58f4c1e..0deaaab 100644 --- a/src/webui/src/components/react/status.tsx +++ b/src/webui/src/components/react/status.tsx @@ -115,7 +115,7 @@ const Status = (props: { name: string; base: string }) => { let retryTimeout; let hasRun = false; - const source = new SSE(`${props.base}/live/daemon/${props.server}/metrics`, { headers }); + const source = new SSE(`${props.base}/live/daemon/${props.name}/metrics`, { headers }); setLive(source); @@ -124,7 +124,7 @@ const Status = (props: { name: string; base: string }) => { setItem(data); - memoryUsage.pushMax(data.raw.memory_usage.rss); + memoryUsage.pushMax(data.raw.memory_usage); cpuPercentage.pushMax(data.raw.cpu_percent); if (!hasRun) { -- GitLab