Skip to content

Commit

Permalink
feat: add system metric counter in windows
Browse files Browse the repository at this point in the history
  • Loading branch information
helintongh committed Sep 13, 2024
1 parent f36ebc5 commit 8844b4d
Showing 1 changed file with 244 additions and 4 deletions.
248 changes: 244 additions & 4 deletions include/cinatra/ylt/metric/system_metric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
#if defined(__GNUC__)
#include <sys/resource.h>
#include <sys/time.h>
#endif

#if defined(WIN32)
#include <psapi.h>
#include <tlhelp32.h>
#include <windows.h>

// Link with Psapi.lib
#pragma comment(lib, "Psapi.lib")
#endif

#include <chrono>
#include <cstdint>
Expand Down Expand Up @@ -73,6 +83,175 @@ inline int read_command_output_through_popen(std::ostream& os,
}
#endif

#if defined(WIN32)
typedef struct timeval {
long tv_sec;
long tv_usec;
} timeval;

inline int gettimeofday(struct timeval* tp, struct timezone* tzp) {
// Note: some broken versions only have 8 trailing zero's, the correct epoch
// has 9 trailing zero's This magic number is the number of 100 nanosecond
// intervals since January 1, 1601 (UTC) until 00:00:00 January 1, 1970
static const uint64_t epoch = ((uint64_t)116444736000000000ULL);

SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;

GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((uint64_t)file_time.dwLowDateTime);
time += ((uint64_t)file_time.dwHighDateTime) << 32;

tp->tv_sec = (long)((time - epoch) / 10000000L);
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
return 0;
}

#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN (-1)

struct rusage {
struct timeval ru_utime; /* user time used */
struct timeval ru_stime; /* system time used */
};

inline int getrusage(int who, struct rusage* rusage) {
FILETIME starttime;
FILETIME exittime;
FILETIME kerneltime;
FILETIME usertime;
ULARGE_INTEGER li;

if (who != RUSAGE_SELF) {
/* Only RUSAGE_SELF is supported in this implementation for now */
errno = EINVAL;
return -1;
}

if (rusage == (struct rusage*)NULL) {
errno = EFAULT;
return -1;
}
memset(rusage, 0, sizeof(struct rusage));
if (GetProcessTimes(GetCurrentProcess(), &starttime, &exittime, &kerneltime,
&usertime) == 0) {
return -1;
}

/* Convert FILETIMEs (0.1 us) to struct timeval */
memcpy(&li, &kerneltime, sizeof(FILETIME));
li.QuadPart /= 10L; /* Convert to microseconds */
rusage->ru_stime.tv_sec = li.QuadPart / 1000000L;
rusage->ru_stime.tv_usec = li.QuadPart % 1000000L;

memcpy(&li, &usertime, sizeof(FILETIME));
li.QuadPart /= 10L; /* Convert to microseconds */
rusage->ru_utime.tv_sec = li.QuadPart / 1000000L;
rusage->ru_utime.tv_usec = li.QuadPart % 1000000L;

return 0;
}

inline SIZE_T get_shared_memory_size(HANDLE h_process) {
MEMORY_BASIC_INFORMATION mbi;
SIZE_T base_address = 0;
SIZE_T shared_memory_size = 0;

while (VirtualQueryEx(h_process, (LPCVOID)base_address, &mbi, sizeof(mbi))) {
if (mbi.State == MEM_COMMIT) {
if (mbi.Type == MEM_MAPPED || mbi.Type == MEM_IMAGE) {
shared_memory_size += mbi.RegionSize;
}
}
base_address = (SIZE_T)mbi.BaseAddress + mbi.RegionSize;
}

return shared_memory_size;
}

inline DWORD getppid() {
HANDLE h_snapshot;
PROCESSENTRY32 pe32;
DWORD ppid = 0, pid = GetCurrentProcessId();

h_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
try {
if (h_snapshot == INVALID_HANDLE_VALUE)
return ppid;

ZeroMemory(&pe32, sizeof(pe32));
pe32.dwSize = sizeof(pe32);
if (!Process32First(h_snapshot, &pe32))
return ppid;

do {
if (pe32.th32ProcessID == pid) {
ppid = pe32.th32ParentProcessID;
break;
}
} while (Process32Next(h_snapshot, &pe32));

} catch (...) {
if (h_snapshot != INVALID_HANDLE_VALUE)
CloseHandle(h_snapshot);
}

if (h_snapshot != INVALID_HANDLE_VALUE)
CloseHandle(h_snapshot);

return ppid;
}

inline DWORD get_thread_number(DWORD processId) {
DWORD thread_count = 0;
HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

if (snapshot_handle == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to create snapshot. Error code: " << GetLastError()
<< std::endl;
return 0;
}

THREADENTRY32 threadEntry;
threadEntry.dwSize = sizeof(THREADENTRY32);

if (Thread32First(snapshot_handle, &threadEntry)) {
do {
if (threadEntry.th32OwnerProcessID == processId) {
++thread_count;
}
} while (Thread32Next(snapshot_handle, &threadEntry));
}
else {
std::cerr << "Failed to retrieve thread information. Error code: "
<< GetLastError() << std::endl;
}

CloseHandle(snapshot_handle);
return thread_count;
}

inline DWORD get_process_group(HANDLE process_handle) {
DWORD_PTR process_affinity_mask;
DWORD_PTR system_affinity_mask;

if (GetProcessAffinityMask(process_handle, &process_affinity_mask,
&system_affinity_mask)) {
// Output the processor group information
// Process Affinity Mask
DWORD grop_id = process_affinity_mask;
return grop_id;
}
else {
std::cerr << "Failed to get process affinity mask. Error code: "
<< GetLastError() << std::endl;
return 0;
}
}
#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 Down Expand Up @@ -145,7 +324,9 @@ inline void stat_memory() {
long virtual_size = 0;
long resident = 0;
long share = 0;
#if defined(__GNUC__)
static long page_size = sysconf(_SC_PAGE_SIZE);
#endif

#if defined(__APPLE__)
static pid_t pid = getpid();
Expand All @@ -169,9 +350,33 @@ inline void stat_memory() {
file >> virtual_size >> resident >> share;
#endif

#if defined(WIN32)
DWORD current_process = GetCurrentProcessId();
// open process
HANDLE h_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, current_process);
if (h_process == NULL) {
virtual_size = 0;
resident = 0;
share = 0;
}
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(h_process, &pmc, sizeof(pmc))) {
virtual_size = pmc.PagefileUsage;
resident = pmc.WorkingSetSize;
}
share = get_shared_memory_size(h_process);

CloseHandle(h_process);

process_memory_virtual->update(virtual_size);
process_memory_resident->update(resident);
process_memory_shared->update(share);
#else
process_memory_virtual->update(virtual_size * page_size);
process_memory_resident->update(resident * page_size);
process_memory_shared->update(share * page_size);
#endif
}

struct ProcIO {
Expand Down Expand Up @@ -199,8 +404,7 @@ inline void stat_io() {
"ylt_process_io_write_second");

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

#if defined(__APPLE__)
#endif

#if defined(WIN32)
DWORD current_process_id = GetCurrentProcessId();
// open process
HANDLE h_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, current_process_id);
if (h_process == NULL) {
s.rchar = 0;
s.wchar = 0;
s.syscr = 0;
s.syscw = 0;
}
else {
IO_COUNTERS io_counters = {0};
if (GetProcessIoCounters(h_process, &io_counters)) {
s.rchar = io_counters.ReadOperationCount;
s.wchar = io_counters.WriteOperationCount;
s.syscr = io_counters.ReadOperationCount;
s.syscw = io_counters.WriteOperationCount;
}
}

CloseHandle(h_process);
#endif

process_io_read_bytes_second->update(s.rchar);
process_io_write_bytes_second->update(s.wchar);
process_io_read_second->update(s.syscr);
Expand Down Expand Up @@ -344,6 +575,16 @@ inline void process_status() {
&stat.flags, &stat.priority, &stat.nice) != 8) {
return;
}
#elif defined(WIN32)
stat.pid = GetCurrentProcessId();
stat.ppid = getppid();

HANDLE h_process =
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, stat.pid);
stat.priority = GetPriorityClass(h_process);
stat.num_threads = get_thread_number(stat.pid);
stat.pgrp = get_process_group(h_process);
CloseHandle(h_process);
#endif
process_uptime->inc();
process_priority->update(stat.priority);
Expand Down Expand Up @@ -455,5 +696,4 @@ inline bool start_system_metric() {

return true;
}
} // namespace ylt::metric
#endif
} // namespace ylt::metric

0 comments on commit 8844b4d

Please sign in to comment.