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..f9b5eff978d 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,74 @@ 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 (-1 != 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, exitTime, kernelTime, userTime; + + /* WARNING! Not supported on Win95! Need to test to ensure this fails gracefully */ + + 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) */ + + omrthread_t self = omrthread_self(); + + int64_t userTime = omrthread_get_self_user_time(self); + int64_t cpuTime = omrthread_get_self_cpu_time(self); + + if ((-1 == cpuTime) || (-1 == userTime)) { + return -1; + } + + threadTime->sysTime = cpuTime - userTime; + threadTime->userTime = userTime; + + return 0; +#endif +}