From 431a794a66cf53d55335e1855a57314517628e45 Mon Sep 17 00:00:00 2001 From: KWSys Upstream Date: Thu, 27 Aug 2026 10:22:58 -0400 Subject: [PATCH] KWSys 2026-08-27 (8f4afc3e) Code extracted from: https://gitlab.kitware.com/utils/kwsys.git at commit 8f4afc3eb87432ce47b5e6bdee5d7e432cd72736 (master). Upstream Shortlog ----------------- Martin Duffy (1): 81ab5b18 SystemInformation: Add ProcessResourceUsage API --- SystemInformation.cxx | 101 +++++++++++++++++++++++++++++++++++---- SystemInformation.hxx.in | 19 ++++++++ 2 files changed, 110 insertions(+), 10 deletions(-) diff --git a/SystemInformation.cxx b/SystemInformation.cxx index 0503b84d3b..6fd24ac7a6 100644 --- a/SystemInformation.cxx +++ b/SystemInformation.cxx @@ -28,6 +28,7 @@ // https://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx #include "kwsysPrivate.h" + #include KWSYS_HEADER(String.h) #include KWSYS_HEADER(SystemInformation.hxx) #include KWSYS_HEADER(Process.h) @@ -48,6 +49,10 @@ #include #include #include + +#if !defined(_WIN32) +# include +#endif #include #include #include @@ -67,15 +72,16 @@ using siginfo_t = int; # include # include // NTSTATUS #else -# include - # include // extern int errno; # include + # include +# include + # include // getrlimit # include +# include # include // int uname(struct utsname *buf); -# include #endif #if defined(__CYGWIN__) && !defined(_WIN32) @@ -87,6 +93,7 @@ using siginfo_t = int; defined(__DragonFly__) # include # include + # include # include # include @@ -108,6 +115,7 @@ using siginfo_t = int; # include # include # include + # include # include # if defined(KWSYS_SYS_HAS_IFADDRS_H) @@ -124,6 +132,7 @@ using siginfo_t = int; defined(__GLIBC__) || defined(__GNU__) # include # include + # include # if defined(KWSYS_SYS_HAS_IFADDRS_H) # include @@ -155,6 +164,18 @@ using ResourceLimitType = struct rlimit; # include #endif +#if defined(_WIN32) || defined(__CYGWIN__) +namespace { +unsigned __int64 fileTimeToUInt64(FILETIME const& ft) +{ + LARGE_INTEGER out; + out.HighPart = ft.dwHighDateTime; + out.LowPart = ft.dwLowDateTime; + return out.QuadPart; +} +} +#endif + #if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) # include # if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) @@ -171,6 +192,7 @@ using ResourceLimitType = struct rlimit; #include #include #include + #include #if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && \ @@ -780,6 +802,72 @@ long long SystemInformation::GetProcessId() return this->Implementation->GetProcessId(); } +bool SystemInformation::GetProcessResourceUsage( + SystemInformation::ProcessResourceUsage& usage, void* processHandle) +{ +#if defined(_WIN32) +# if defined(KWSYS_SYS_HAS_PSAPI) + HANDLE hProc = static_cast(processHandle); + if (!hProc) { + return false; + } + + FILETIME creationTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + if (!GetProcessTimes(hProc, &creationTime, &exitTime, &kernelTime, + &userTime)) { + return false; + } + + PROCESS_MEMORY_COUNTERS pmc; + if (!GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc))) { + return false; + } + + usage = SystemInformation::ProcessResourceUsage{}; + usage.ru_maxrss = + static_cast(pmc.PeakWorkingSetSize / 1024); + + unsigned __int64 const user100ns = fileTimeToUInt64(userTime); + unsigned __int64 const kernel100ns = fileTimeToUInt64(kernelTime); + unsigned __int64 const userUSec = user100ns / 10ULL; + unsigned __int64 const kernelUSec = kernel100ns / 10ULL; + + usage.ru_utime.tv_sec = static_cast(userUSec / 1000000ULL); + usage.ru_utime.tv_usec = static_cast(userUSec % 1000000ULL); + usage.ru_stime.tv_sec = static_cast(kernelUSec / 1000000ULL); + usage.ru_stime.tv_usec = static_cast(kernelUSec % 1000000ULL); + return true; +# else // !defined(KWSYS_SYS_HAS_PSAPI) + static_cast(usage); + static_cast(processHandle); + return false; +# endif +#else // !defined(_WIN32) + static_cast(processHandle); + struct rusage rusage; + if (getrusage(RUSAGE_CHILDREN, &rusage) != 0) { + return false; + } + usage = SystemInformation::ProcessResourceUsage{}; + usage.ru_maxrss = rusage.ru_maxrss; +# if defined(__APPLE__) + // Apple platforms report bytes. Convert to KiB. + usage.ru_maxrss /= 1024; +# elif defined(__sun) + // Solaris platforms report pages. Convert to KiB. + usage.ru_maxrss *= getpagesize() / 1024; +# endif + usage.ru_utime.tv_sec = rusage.ru_utime.tv_sec; + usage.ru_utime.tv_usec = rusage.ru_utime.tv_usec; + usage.ru_stime.tv_sec = rusage.ru_stime.tv_sec; + usage.ru_stime.tv_usec = rusage.ru_stime.tv_usec; + return true; +#endif +} + void SystemInformation::SetStackTraceOnError(int enable) { SystemInformationImplementation::SetStackTraceOnError(enable); @@ -1388,13 +1476,6 @@ double calculateCPULoad(unsigned __int64 idleTicks, return load; } -unsigned __int64 fileTimeToUInt64(FILETIME const& ft) -{ - LARGE_INTEGER out; - out.HighPart = ft.dwHighDateTime; - out.LowPart = ft.dwLowDateTime; - return out.QuadPart; -} #endif } // anonymous namespace diff --git a/SystemInformation.hxx.in b/SystemInformation.hxx.in index cb8c214d4a..7720a7dc0f 100644 --- a/SystemInformation.hxx.in +++ b/SystemInformation.hxx.in @@ -19,6 +19,19 @@ class @KWSYS_NAMESPACE@_EXPORT SystemInformation SystemInformationImplementation* Implementation; public: + struct TimeValue + { + long tv_sec; + long tv_usec; + }; + + struct ProcessResourceUsage + { + TimeValue ru_utime{}; + TimeValue ru_stime{}; + long ru_maxrss = 0; + }; + // possible parameter values for DoesCPUSupportFeature() static long int const CPU_FEATURE_MMX = 1 << 0; static long int const CPU_FEATURE_MMX_PLUS = 1 << 1; @@ -138,6 +151,12 @@ public: // Get system RAM used by this process id in units of KiB. long long GetProcMemoryUsed(); + // Retrieve resource usage for a finished child process. On Unix, this + // queries RUSAGE_CHILDREN for the current process. On Windows, the caller + // provides the child process handle to query. + static bool GetProcessResourceUsage(ProcessResourceUsage& usage, + void* processHandle = nullptr); + // Return the load average of the machine or -0.0 if it cannot // be determined. double GetLoadAverage();