Skip to content

Commit

Permalink
system_metric for mac
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos committed Aug 5, 2024
1 parent f2d8ba2 commit 6d6f3e5
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 30 deletions.
5 changes: 3 additions & 2 deletions include/ylt/metric/counter.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <atomic>
#include <chrono>
#include <variant>

#include "metric.hpp"
#include "thread_local_value.hpp"
Expand All @@ -11,7 +12,7 @@ enum class op_type_t { INC, DEC, SET };
#ifdef CINATRA_ENABLE_METRIC_JSON
struct json_counter_metric_t {
std::unordered_multimap<std::string, std::string> labels;
int64_t value;
std::variant<int64_t, double> value;
};
REFLECTION(json_counter_metric_t, labels, value);
struct json_counter_t {
Expand Down Expand Up @@ -125,7 +126,7 @@ class basic_counter : public metric_t {
return;
}
json_counter_t counter{name_, help_, std::string(metric_name())};
int64_t value = default_label_value_.value();
auto value = default_label_value_.value();
counter.metrics.push_back({{}, value});
iguana::to_json(counter, str);
return;
Expand Down
132 changes: 114 additions & 18 deletions include/ylt/metric/system_metric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,53 @@
#include "cinatra/ylt/metric/metric.hpp"
#endif

// reference: brpc/src/bvar/default_variables.cpp
// modified based on: brpc/src/bvar/default_variables.cpp

namespace ylt::metric {
namespace detail {

#if defined(__APPLE__)
#include <stdio.h>

inline int read_command_output_through_popen(std::ostream& os,
const char* cmd) {
FILE* pipe = popen(cmd, "r");
if (pipe == NULL) {
return -1;
}
char buffer[1024];
for (;;) {
size_t nr = fread(buffer, 1, sizeof(buffer), pipe);
if (nr != 0) {
os.write(buffer, nr);
}
if (nr != sizeof(buffer)) {
if (feof(pipe)) {
break;
}
else if (ferror(pipe)) {
break;
}
// retry;
}
}

const int wstatus = pclose(pipe);

if (wstatus < 0) {
return wstatus;
}
if (WIFEXITED(wstatus)) {
return WEXITSTATUS(wstatus);
}
if (WIFSIGNALED(wstatus)) {
os << "Child process was killed by signal " << WTERMSIG(wstatus);
}
errno = ECHILD;
return -1;
}
#endif

inline int64_t last_time_us = 0;
inline int64_t last_sys_time_us = 0;
inline int64_t last_user_time_us = 0;
Expand All @@ -39,7 +81,7 @@ inline int64_t gettimeofday_us() {
return now.tv_sec * 1000000L + now.tv_usec;
}

inline int64_t timeval_to_microseconds(const timeval &tv) {
inline int64_t timeval_to_microseconds(const timeval& tv) {
return tv.tv_sec * 1000000L + tv.tv_usec;
}

Expand Down Expand Up @@ -101,13 +143,29 @@ inline void stat_memory() {
long virtual_size = 0;
long resident = 0;
long share = 0;
static long page_size = sysconf(_SC_PAGE_SIZE);

#if defined(__APPLE__)
static pid_t pid = getpid();
static int64_t pagesize = getpagesize();
std::ostringstream oss;
char cmdbuf[128];
snprintf(cmdbuf, sizeof(cmdbuf), "ps -p %ld -o rss=,vsz=", (long)pid);
if (read_command_output_through_popen(oss, cmdbuf) != 0) {
return;
}
const std::string& result = oss.str();
if (sscanf(result.c_str(), "%ld %ld", &resident, &virtual_size) != 2) {
return;
}
#else
std::ifstream file("/proc/self/statm");
if (!file) {
return;
}

file >> virtual_size >> resident >> share;
static long page_size = sysconf(_SC_PAGE_SIZE);
#endif

process_memory_virtual->update(virtual_size * page_size);
process_memory_resident->update(resident * page_size);
Expand Down Expand Up @@ -138,6 +196,9 @@ inline void stat_io() {
system_metric_manager::instance().get_metric_static<gauge_t>(
"ylt_process_io_write_second");

ProcIO s{};
#if defined(__APPLE__)
#else
auto stream_file =
std::shared_ptr<FILE>(fopen("/proc/self/io", "r"), [](FILE *ptr) {
fclose(ptr);
Expand All @@ -146,13 +207,13 @@ inline void stat_io() {
return;
}

ProcIO s{};
if (fscanf(stream_file.get(),
"%*s %lu %*s %lu %*s %lu %*s %lu %*s %lu %*s %lu %*s %lu",
&s.rchar, &s.wchar, &s.syscr, &s.syscw, &s.read_bytes,
&s.write_bytes, &s.cancelled_write_bytes) != 7) {
return;
}
#endif

process_io_read_bytes_second->update(s.rchar);
process_io_write_bytes_second->update(s.wchar);
Expand All @@ -162,26 +223,41 @@ inline void stat_io() {

inline void stat_avg_load() {
static auto system_loadavg_1m =
system_metric_manager::instance().get_metric_static<gauge_t>(
system_metric_manager::instance().get_metric_static<gauge_d>(
"ylt_system_loadavg_1m");
static auto system_loadavg_5m =
system_metric_manager::instance().get_metric_static<gauge_t>(
system_metric_manager::instance().get_metric_static<gauge_d>(
"ylt_system_loadavg_5m");
static auto system_loadavg_15m =
system_metric_manager::instance().get_metric_static<gauge_t>(
system_metric_manager::instance().get_metric_static<gauge_d>(
"ylt_system_loadavg_15m");

double loadavg_1m = 0;
double loadavg_5m = 0;
double loadavg_15m = 0;

#if defined(__APPLE__)
std::ostringstream oss;
if (read_command_output_through_popen(oss, "sysctl -n vm.loadavg") != 0) {
return;
}
const std::string& result = oss.str();
if (sscanf(result.c_str(), "{ %lf %lf %lf }", &loadavg_1m, &loadavg_5m,
&loadavg_15m) != 3) {
return;
}
#else
std::ifstream file("/proc/loadavg");
if (!file) {
return;
}

double loadavg_1m = 0;
double loadavg_5m = 0;
double loadavg_15m = 0;
file >> loadavg_1m >> loadavg_5m >> loadavg_15m;
#endif

system_loadavg_1m->update(loadavg_1m);
system_loadavg_1m->update(loadavg_5m);
system_loadavg_1m->update(loadavg_15m);
system_loadavg_5m->update(loadavg_5m);
system_loadavg_15m->update(loadavg_15m);
}

struct ProcStat {
Expand Down Expand Up @@ -224,15 +300,16 @@ inline void process_status() {
system_metric_manager::instance().get_metric_static<gauge_t>(
"ylt_thread_count");

ProcStat stat{};
#if defined(__linux__)
auto stream_file =
std::shared_ptr<FILE>(fopen("/proc/self/stat", "r"), [](FILE *ptr) {
std::shared_ptr<FILE>(fopen("/proc/self/stat", "r"), [](FILE* ptr) {
fclose(ptr);
});
if (stream_file == nullptr) {
return;
}

ProcStat stat{};
if (fscanf(stream_file.get(),
"%d %*s %c "
"%d %d %d %d %d "
Expand All @@ -246,7 +323,26 @@ inline void process_status() {
&stat.nice, &stat.num_threads) != 19) {
return;
}

#elif defined(__APPLE__)
static pid_t proc_id = getpid();
std::ostringstream oss;
char cmdbuf[128];
snprintf(cmdbuf, sizeof(cmdbuf),
"ps -p %ld -o pid,ppid,pgid,sess"
",tpgid,flags,pri,nice | tail -n1",
(long)proc_id);
if (read_command_output_through_popen(oss, cmdbuf) != 0) {
return;
}
const std::string &result = oss.str();
if (sscanf(result.c_str(),
"%d %d %d %d"
"%d %u %ld %ld",
&stat.pid, &stat.ppid, &stat.pgrp, &stat.session, &stat.tpgid,
&stat.flags, &stat.priority, &stat.nice) != 8) {
return;
}
#endif
process_uptime->inc();
process_priority->update(stat.priority);
pid->update(stat.pid);
Expand Down Expand Up @@ -329,11 +425,11 @@ inline bool start_system_metric() {
system_metric_manager::instance().create_metric_static<gauge_t>(
"ylt_summary_failed_count", "");

system_metric_manager::instance().create_metric_static<gauge_t>(
system_metric_manager::instance().create_metric_static<gauge_d>(
"ylt_system_loadavg_1m", "");
system_metric_manager::instance().create_metric_static<gauge_t>(
system_metric_manager::instance().create_metric_static<gauge_d>(
"ylt_system_loadavg_5m", "");
system_metric_manager::instance().create_metric_static<gauge_t>(
system_metric_manager::instance().create_metric_static<gauge_d>(
"ylt_system_loadavg_15m", "");

system_metric_manager::instance().create_metric_static<gauge_t>(
Expand Down
20 changes: 10 additions & 10 deletions include/ylt/metric/thread_local_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,23 @@ class thread_local_value {
void dec(value_type value = 1) { local_value() -= value; }

value_type update(value_type value = 1) {
value_type val = reset();
local_value() = value;
return val;
}

value_type reset() {
value_type val = 0;
for (auto &t : duplicates_) {
if (t) {
val += t.load()->exchange(0);
value_type val = get_value(0).exchange(value);
for (size_t i = 1; i < duplicates_.size(); i++) {
if (duplicates_[i]) {
val += duplicates_[i].load()->exchange(0);
}
}
return val;
}

value_type reset() { return update(0); }

auto &local_value() {
static thread_local auto index = get_round_index(duplicates_.size());
return get_value(index);
}

auto &get_value(size_t index) {
if (duplicates_[index] == nullptr) {
auto ptr = new std::atomic<value_type>(0);

Expand Down

0 comments on commit 6d6f3e5

Please sign in to comment.