system
parent
2cc2b2d262
commit
93f56ebcb2
|
@ -9,22 +9,29 @@
|
|||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <x86intrin.h>
|
||||
|
||||
#include <x86intrin.h>
|
||||
|
||||
#endif
|
||||
#else
|
||||
#include <chrono>
|
||||
#endif
|
||||
#include <cstdint>
|
||||
|
||||
namespace blt::system {
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
namespace blt::system
|
||||
{
|
||||
//#ifdef __GNUC__
|
||||
// #define GNU_INLINE __attribute__((__gnu_inline__, __always_inline__))
|
||||
//#else
|
||||
// #define GNU_INLINE
|
||||
//#endif
|
||||
inline std::uint64_t rdtsc(){
|
||||
inline std::uint64_t rdtsc()
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
#else
|
||||
|
@ -33,6 +40,144 @@ namespace blt::system {
|
|||
}
|
||||
// TODO: system memory and current CPU usage. (Linux Only currently)
|
||||
|
||||
struct linux_proc_stat
|
||||
{
|
||||
// pid %d
|
||||
std::int32_t PID;
|
||||
// comm %s
|
||||
std::string exec_name;
|
||||
/*
|
||||
* R Running
|
||||
* S Sleeping in an interruptible wait
|
||||
* D Waiting in uninterruptible disk sleep
|
||||
* Z Zombie
|
||||
* T Stopped (on a signal) or (before Linux 2.6.33) trace stopped
|
||||
* t Tracing stop (Linux 2.6.33 onward)
|
||||
* W Paging (only before Linux 2.6.0)
|
||||
* X Dead (from Linux 2.6.0 onward)
|
||||
* x Dead (Linux 2.6.33 to 3.13 only)
|
||||
* K Wakekill (Linux 2.6.33 to 3.13 only)
|
||||
* W Waking (Linux 2.6.33 to 3.13 only)
|
||||
* P Parked (Linux 3.9 to 3.13 only)
|
||||
* I Idle (Linux 4.14 onward)
|
||||
*/
|
||||
// state %c
|
||||
char state;
|
||||
// pid of parent
|
||||
std::int32_t parent_pid;
|
||||
// group id of process
|
||||
std::int32_t group_id;
|
||||
// session id of process
|
||||
std::int32_t session_id;
|
||||
// controlling terminal
|
||||
std::int32_t tty_nr;
|
||||
// The ID of the foreground process group of the controlling terminal of the process.
|
||||
std::int32_t tpgid;
|
||||
std::uint32_t flags;
|
||||
std::uint64_t minflt;
|
||||
std::uint64_t cminflt;
|
||||
std::uint64_t majflt;
|
||||
std::uint64_t cmajflt;
|
||||
// amount of time process has been scheduled in user mode measured in clock ticks (divide by sysconf(_SC_CLK_TCK))
|
||||
std::uint64_t utime;
|
||||
// amount of time that this process has been scheduled in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
|
||||
std::uint64_t stime;
|
||||
// children times
|
||||
std::int64_t cutime;
|
||||
std::int64_t cstime;
|
||||
std::int64_t priority;
|
||||
std::int64_t nice;
|
||||
std::int64_t num_threads;
|
||||
std::int64_t itrealvalue;
|
||||
// The time the process started after system boot. Since Linux 2.6, the value is expressed in clock ticks (divide by sysconf(_SC_CLK_TCK)).
|
||||
std::uint64_t starttime;
|
||||
// Virtual memory size in bytes.
|
||||
std::uint64_t vsize;
|
||||
// Resident Set Size: number of pages the process has in real memory.
|
||||
// This is just the pages which count toward text, data, or stack space. This does not include pages which have not been demand-loaded
|
||||
// in, or which are swapped out. This value is inaccurate; see /proc/pid/statm below.
|
||||
std::int64_t rss;
|
||||
// Current soft limit in bytes on the rss of the process; see the description of RLIMIT_RSS in getrlimit(2).
|
||||
std::uint64_t rsslim;
|
||||
std::uint64_t startcode;
|
||||
std::uint64_t endcode;
|
||||
std::uint64_t startstack;
|
||||
std::uint64_t kstkesp;
|
||||
std::uint64_t signal;
|
||||
std::uint64_t blocked;
|
||||
std::uint64_t sigignore;
|
||||
std::uint64_t sigcatch;
|
||||
std::uint64_t wchan;
|
||||
std::uint64_t nswap;
|
||||
std::uint64_t cnswap;
|
||||
std::int32_t exit_signal;
|
||||
std::int32_t processor;
|
||||
std::uint32_t rt_priority;
|
||||
std::uint32_t policy;
|
||||
std::uint64_t delayacct_blkio_ticks;
|
||||
std::uint64_t guest_time;
|
||||
std::int64_t cguest_time;
|
||||
std::uint64_t start_data;
|
||||
std::uint64_t end_data;
|
||||
std::uint64_t start_brk;
|
||||
std::uint64_t arg_start;
|
||||
std::uint64_t arg_end;
|
||||
std::uint64_t env_start;
|
||||
std::uint64_t env_end;
|
||||
std::int32_t exit_code;
|
||||
};
|
||||
|
||||
struct memory_info_t
|
||||
{
|
||||
// total program size (bytes) (same as VmSize in status)
|
||||
std::uint64_t size;
|
||||
// size of memory portions (bytes) (same as VmRSS in status)
|
||||
std::uint64_t resident;
|
||||
// number of bytes that are shared (i.e. backed by a file, same as RssFile+RssShmem in status)
|
||||
std::uint64_t shared;
|
||||
// number of bytes that are 'code' (not including libs; broken, includes data segment)
|
||||
std::uint64_t text;
|
||||
// number of pages of library (0)
|
||||
std::uint64_t lib;
|
||||
// number of bytes of data/stack (including libs; broken, includes library text)
|
||||
std::uint64_t data;
|
||||
// number of dirty pages (0)
|
||||
std::uint64_t dt;
|
||||
};
|
||||
|
||||
struct timeval {
|
||||
time_t tv_sec; /* Seconds */
|
||||
suseconds_t tv_usec; /* Microseconds */
|
||||
};
|
||||
|
||||
struct rusage {
|
||||
timeval ru_utime; /* user CPU time used */
|
||||
timeval ru_stime; /* system CPU time used */
|
||||
long ru_maxrss; /* maximum resident set size */
|
||||
|
||||
long ru_ixrss; /* integral shared memory size */
|
||||
long ru_idrss; /* integral unshared data size */
|
||||
long ru_isrss; /* integral unshared stack size */
|
||||
|
||||
long ru_minflt; /* page reclaims (soft page faults) */
|
||||
long ru_majflt; /* page faults (hard page faults) */
|
||||
|
||||
long ru_nswap; /* swaps */
|
||||
|
||||
long ru_inblock; /* block input operations */
|
||||
long ru_oublock; /* block output operations */
|
||||
long ru_msgsnd; /* IPC messages sent */
|
||||
long ru_msgrcv; /* IPC messages received */
|
||||
long ru_nsignals; /* signals received */
|
||||
long ru_nvcsw; /* voluntary context switches */
|
||||
long ru_nivcsw; /* involuntary context switches */
|
||||
};
|
||||
|
||||
std::optional<blt::system::rusage> get_resources_process();
|
||||
std::optional<blt::system::rusage> get_resources_thread();
|
||||
|
||||
memory_info_t get_memory_process();
|
||||
|
||||
}
|
||||
|
||||
#endif //BLT_SYSTEM_H
|
||||
|
|
|
@ -4,5 +4,139 @@
|
|||
* See LICENSE file for license detail
|
||||
*/
|
||||
#include <blt/std/system.h>
|
||||
#include <blt/std/binary_tree.h>
|
||||
#include <blt/math/math.h>
|
||||
#include <blt/std/logging.h>
|
||||
|
||||
#include <sys/time.h> /* for struct timeval */
|
||||
#include <climits> /* for CLK_TCK */
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include <unistd.h>
|
||||
#include <blt/std/loader.h>
|
||||
#include "blt/std/assert.h"
|
||||
|
||||
inline long blt_get_page_size()
|
||||
{
|
||||
return sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
//struct proc_statm_t
|
||||
//{
|
||||
// // total program size (pages) (same as VmSize in status)
|
||||
// std::uint64_t size;
|
||||
// // size of memory portions (pages) (same as VmRSS in status)
|
||||
// std::uint64_t resident;
|
||||
// // number of pages that are shared (i.e. backed by a file, same as RssFile+RssShmem in status)
|
||||
// std::uint64_t shared;
|
||||
// // number of pages that are 'code' (not including libs; broken, includes data segment)
|
||||
// std::uint64_t text;
|
||||
// // number of pages of library (0)
|
||||
// std::uint64_t lib;
|
||||
// // number of pages of data/stack (including libs; broken, includes library text)
|
||||
// std::uint64_t data;
|
||||
// // number of dirty pages (0)
|
||||
// std::uint64_t dt;
|
||||
//};
|
||||
|
||||
blt::system::memory_info_t process_proc()
|
||||
{
|
||||
static auto page_size = blt_get_page_size();
|
||||
|
||||
auto str = blt::fs::getFile("/proc/self/statm");
|
||||
|
||||
auto data = blt::string::split(str, ' ');
|
||||
BLT_ASSERT(data.size() == 7 && "Something went wrong when parsing /proc/self/statm! Expected 7 values!");
|
||||
|
||||
blt::system::memory_info_t mem {};
|
||||
|
||||
mem.size = page_size * std::stoull(data[0]);
|
||||
mem.resident = page_size * std::stoull(data[1]);
|
||||
mem.shared = page_size * std::stoull(data[2]);
|
||||
mem.text = page_size * std::stoull(data[3]);
|
||||
mem.lib = page_size * std::stoull(data[4]);
|
||||
mem.data = page_size * std::stoull(data[5]);
|
||||
mem.dt = page_size * std::stoull(data[6]);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace blt
|
||||
{
|
||||
std::optional<system::rusage> get_resources(int who)
|
||||
{
|
||||
system::rusage usage{};
|
||||
std::memset(&usage, 0, sizeof(system::rusage));
|
||||
#ifdef WIN32
|
||||
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 */
|
||||
BLT_WARN("Only RUSAGE_SELF is supported in this implementation for now");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (GetProcessTimes(GetCurrentProcess(),
|
||||
&starttime, &exittime, &kerneltime, &usertime) == 0)
|
||||
{
|
||||
BLT_WARN("Unable to get process resource usage, error: %d", GetLastError());
|
||||
return {};
|
||||
}
|
||||
|
||||
/* Convert FILETIMEs (0.1 us) to struct timeval */
|
||||
memcpy(&li, &kerneltime, sizeof(FILETIME));
|
||||
li.QuadPart /= 10L; /* Convert to microseconds */
|
||||
usage.ru_stime.tv_sec = li.QuadPart / 1000000L;
|
||||
usage.ru_stime.tv_usec = li.QuadPart % 1000000L;
|
||||
|
||||
memcpy(&li, &usertime, sizeof(FILETIME));
|
||||
li.QuadPart /= 10L; /* Convert to microseconds */
|
||||
usage.ru_utime.tv_sec = li.QuadPart / 1000000L;
|
||||
usage.ru_utime.tv_usec = li.QuadPart % 1000000L;
|
||||
#else
|
||||
if (getrusage(who, (struct rusage*) &usage) != 0)
|
||||
{
|
||||
BLT_ERROR("Failed to get rusage %d", errno);
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
return usage;
|
||||
}
|
||||
|
||||
std::optional<system::rusage> system::get_resources_process()
|
||||
{
|
||||
return get_resources(RUSAGE_SELF);
|
||||
}
|
||||
|
||||
std::optional<system::rusage> system::get_resources_thread()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return get_resources(RUSAGE_SELF);
|
||||
#else
|
||||
return get_resources(RUSAGE_THREAD);
|
||||
#endif
|
||||
}
|
||||
|
||||
system::memory_info_t system::get_memory_process()
|
||||
{
|
||||
#ifdef WIN32
|
||||
BLT_WARN("Unsupported OS");
|
||||
return {};
|
||||
#else
|
||||
|
||||
return process_proc();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue