From dbd3fb1da3be14b05644365fe5b7c62e98eb28cc Mon Sep 17 00:00:00 2001 From: Gengchen Tuo Date: Thu, 10 Oct 2024 11:45:49 -0400 Subject: [PATCH] Add omrthread_get_thread_times() This function returns the user and system cpu time of the calling thread. This new function is needed so we can get both user time and system time using only one system call. Related: https://github.com/eclipse-openj9/openj9/pull/20186 Signed-off-by: Gengchen Tuo --- include_core/thread_api.h | 14 +++++++++ thread/common/thrprof.c | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/include_core/thread_api.h b/include_core/thread_api.h index 8fd03718435..ff93bec9ac7 100644 --- a/include_core/thread_api.h +++ b/include_core/thread_api.h @@ -62,6 +62,11 @@ typedef struct omrthread_process_time_t { int64_t _userTime; } omrthread_process_time_t; +typedef struct omrthread_thread_time_t { + int64_t userTime; + int64_t sysTime; +} omrthread_thread_time_t; + typedef struct omrthread_state_t { uintptr_t flags; omrthread_monitor_t blocker; @@ -1240,6 +1245,15 @@ omrthread_get_jvm_cpu_usage_info(J9ThreadsCpuUsage *cpuUsage); void omrthread_get_jvm_cpu_usage_info_error_recovery(void); +/** + * Gets the system and user CPU time of the current thread. + * + * @param[out] threadTime the pointer to the thread time structure + * @return 0 on success or -1 on failure + */ +intptr_t +omrthread_get_thread_times(omrthread_thread_time_t *threadTime); + /* ---------------- omrthreadattr.c ---------------- */ /** diff --git a/thread/common/thrprof.c b/thread/common/thrprof.c index 023085ff616..3d3cdf2d3a1 100644 --- a/thread/common/thrprof.c +++ b/thread/common/thrprof.c @@ -28,6 +28,11 @@ * APIs for querying per-thread statistics: CPU usage, stack usage. */ +#if defined(LINUX) +#define _GNU_SOURCE +#include +#endif /* defined(LINUX) */ + #include /* for memset() */ #include "omrcfg.h" @@ -1025,3 +1030,64 @@ omrthread_get_jvm_cpu_usage_info_error_recovery(void) GLOBAL_UNLOCK_SIMPLE(lib); } } + +intptr_t +omrthread_get_thread_times(omrthread_thread_time_t *threadTime) +{ +#if defined(LINUX) + struct rusage rUsage; + memset(&rUsage, 0, sizeof(rUsage)); + + if (0 == getrusage(RUSAGE_THREAD, &rUsage)) { + threadTime->userTime = (SEC_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_utime.tv_sec) + + (MICRO_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_utime.tv_usec); + threadTime->sysTime = (SEC_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_stime.tv_sec) + + (MICRO_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_stime.tv_usec); + + return 0; + } + + return -1; +#elif defined(OMR_OS_WINDOWS) && !defined(BREW) /* defined(LINUX) */ + omrthread_t self = omrthread_self(); + FILETIME creationTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + memset(&creationTime, 0, sizeof(creationTime)); + memset(&exitTime, 0, sizeof(exitTime)); + memset(&kernelTime, 0, sizeof(kernelTime)); + memset(&userTime, 0, sizeof(userTime)); + + if (GetThreadTimes(self->handle, &creationTime, &exitTime, &kernelTime, &userTime)) { + /* Time is in 100's of nanos. Convert to nanos. */ + threadTime->sysTime = ((int64_t)kernelTime.dwLowDateTime | ((int64_t)kernelTime.dwHighDateTime << 32)) * 100; + threadTime->userTime = ((int64_t)userTime.dwLowDateTime | ((int64_t)userTime.dwHighDateTime << 32)) * 100; + + return 0; + } + + return -1; +#elif defined(AIXPPC) /* defined(OMR_OS_WINDOWS) && !defined(BREW) */ + omrthread_t self = omrthread_self(); + + /* AIX provides a function call that returns an entire structure of + * information about the thread. + */ + struct rusage rUsage; + memset(&rUsage, 0, sizeof(rUsage)); + + if (0 == pthread_getrusage_np(self->handle, &rUsage, PTHRDSINFO_RUSAGE_COLLECT)) { + threadTime->userTime = (SEC_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_utime.tv_sec) + + (MICRO_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_utime.tv_usec); + threadTime->sysTime = (SEC_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_stime.tv_sec) + + (MICRO_TO_NANO_CONVERSION_CONSTANT * (int64_t)rUsage.ru_stime.tv_usec); + return 0; + } + + return -1; +#else /* defined(AIXPPC) */ + /* Return -1 since the user time can only be retrieved on Windows, Linux, and AIX. */ + return -1; +#endif /* defined(LINUX) */ +}