diff --git a/include/blt/std/system.h b/include/blt/std/system.h index 960521e..471220a 100755 --- a/include/blt/std/system.h +++ b/include/blt/std/system.h @@ -9,22 +9,29 @@ #ifndef __EMSCRIPTEN__ #ifdef _WIN32 - #include + #include #else - #include + + #include + #endif #else #include #endif -#include -namespace blt::system { +#include +#include +#include + +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 get_resources_process(); + std::optional get_resources_thread(); + + memory_info_t get_memory_process(); + } #endif //BLT_SYSTEM_H diff --git a/src/blt/std/system.cpp b/src/blt/std/system.cpp index 19083e5..e987d5d 100755 --- a/src/blt/std/system.cpp +++ b/src/blt/std/system.cpp @@ -4,5 +4,139 @@ * See LICENSE file for license detail */ #include -#include -#include \ No newline at end of file +#include + +#include /* for struct timeval */ +#include /* for CLK_TCK */ + +#include +#include + +#ifndef WIN32 + + #include + #include +#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 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::get_resources_process() + { + return get_resources(RUSAGE_SELF); + } + + std::optional 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 + } +} + +