#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
+#include <sys/resource.h>
#if HAVE_MACH_ABSOLUTE_TIME
#include <mach/mach_time.h>
#endif
}
return 1;
}
+
+#if defined(_ARM_) || defined(_ARM64_)
+#define SYSCONF_GET_NUMPROCS _SC_NPROCESSORS_CONF
+#else
+#define SYSCONF_GET_NUMPROCS _SC_NPROCESSORS_ONLN
+#endif
+
+int32_t SystemNative_GetCpuUtilization(ProcessCpuInformation* previousCpuInfo)
+{
+ static long numProcessors = 0;
+
+ if (numProcessors <= 0)
+ {
+ numProcessors = sysconf(SYSCONF_GET_NUMPROCS);
+ if (numProcessors <= 0)
+ {
+ return 0;
+ }
+ }
+
+ uint64_t kernelTime = 0;
+ uint64_t userTime = 0;
+
+ struct rusage resUsage;
+ if (getrusage(RUSAGE_SELF, &resUsage) == -1)
+ {
+ assert(false);
+ return 0;
+ }
+ else
+ {
+ kernelTime = ((uint64_t)(resUsage.ru_stime.tv_sec) * SecondsToNanoSeconds) + (uint64_t)(resUsage.ru_stime.tv_usec);
+ userTime = ((uint64_t)(resUsage.ru_utime.tv_sec) * SecondsToNanoSeconds) + (uint64_t)(resUsage.ru_utime.tv_usec);
+ }
+
+ uint64_t timestamp;
+ uint64_t resolution;
+
+ if (!SystemNative_GetTimestamp(×tamp) || !SystemNative_GetTimestampResolution(&resolution))
+ {
+ return 0;
+ }
+
+ uint64_t currentTime = timestamp * SecondsToNanoSeconds / resolution;
+
+ uint64_t lastRecordedCurrentTime = previousCpuInfo->lastRecordedCurrentTime;
+ uint64_t lastRecordedKernelTime = previousCpuInfo->lastRecordedKernelTime;
+ uint64_t lastRecordedUserTime = previousCpuInfo->lastRecordedUserTime;
+
+ uint64_t cpuTotalTime = 0;
+ if (currentTime > lastRecordedCurrentTime)
+ {
+ // cpuTotalTime is based on clock time. Since multiple threads can run in parallel,
+ // we need to scale cpuTotalTime cover the same amount of total CPU time.
+ // rusage time is already scaled across multiple processors.
+ cpuTotalTime = (currentTime - lastRecordedCurrentTime);
+ cpuTotalTime *= (uint64_t)numProcessors;
+ }
+
+ uint64_t cpuBusyTime = 0;
+ if (userTime >= lastRecordedUserTime && kernelTime >= lastRecordedKernelTime)
+ {
+ cpuBusyTime = (userTime - lastRecordedUserTime) + (kernelTime - lastRecordedKernelTime);
+ }
+
+ int32_t cpuUtilization = 0;
+ if (cpuTotalTime > 0 && cpuBusyTime > 0)
+ {
+ cpuUtilization = (int32_t)(cpuBusyTime / cpuTotalTime);
+ }
+
+ assert(cpuUtilization >= 0 && cpuUtilization <= 100);
+
+ previousCpuInfo->lastRecordedCurrentTime = currentTime;
+ previousCpuInfo->lastRecordedUserTime = userTime;
+ previousCpuInfo->lastRecordedKernelTime = kernelTime;
+
+ return cpuUtilization;
+}
int64_t tv_nsec; // nanoseconds
} TimeSpec;
+typedef struct ProcessCpuInformation
+{
+ uint64_t lastRecordedCurrentTime;
+ uint64_t lastRecordedKernelTime;
+ uint64_t lastRecordedUserTime;
+} ProcessCpuInformation;
+
+
/**
* Sets the last access and last modified time of a file
*
DLLEXPORT int32_t SystemNative_GetAbsoluteTime(uint64_t* timestamp);
DLLEXPORT int32_t SystemNative_GetTimebaseInfo(uint32_t* numer, uint32_t* denom);
+
+/**
+ * The main purpose of this function is to compute the overall CPU utilization
+ * for the CLR thread pool to regulate the number of worker threads.
+ * Since there is no consistent API on Unix to get the CPU utilization
+ * from a user process, getrusage and gettimeofday are used to
+ * compute the current process's CPU utilization instead.
+ */
+DLLEXPORT int32_t SystemNative_GetCpuUtilization(ProcessCpuInformation* previousCpuInfo);