misc: implement uv_getrusage_thread (#4666)

Refs: https://github.com/libuv/libuv/issues/3119

Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
Co-authored-by: James M Snell <jasnell@gmail.com>
This commit is contained in:
Juan José 2025-01-14 08:50:26 -05:00 committed by GitHub
parent e59e2a9e49
commit be8eec8c5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 140 additions and 24 deletions

View File

@ -360,6 +360,17 @@ API
On Windows not all fields are set, the unsupported fields are filled with zeroes. On Windows not all fields are set, the unsupported fields are filled with zeroes.
See :c:type:`uv_rusage_t` for more details. See :c:type:`uv_rusage_t` for more details.
.. c:function:: int uv_getrusage_thread(uv_rusage_t* rusage)
Gets the resource usage measures for the calling thread.
.. versionadded:: 1.50.0
.. note::
Not supported on all platforms. May return `UV_ENOTSUP`.
On macOS and Windows not all fields are set, the unsupported fields are filled with zeroes.
See :c:type:`uv_rusage_t` for more details.
.. c:function:: uv_pid_t uv_os_getpid(void) .. c:function:: uv_pid_t uv_os_getpid(void)
Returns the current process ID. Returns the current process ID.

View File

@ -1295,6 +1295,7 @@ typedef struct {
} uv_rusage_t; } uv_rusage_t;
UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
UV_EXTERN int uv_getrusage_thread(uv_rusage_t* rusage);
UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);

View File

@ -52,6 +52,8 @@
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
# include <mach/mach.h>
# include <mach/thread_info.h>
# include <sys/filio.h> # include <sys/filio.h>
# include <sys/sysctl.h> # include <sys/sysctl.h>
#endif /* defined(__APPLE__) */ #endif /* defined(__APPLE__) */
@ -999,10 +1001,10 @@ int uv__fd_exists(uv_loop_t* loop, int fd) {
} }
int uv_getrusage(uv_rusage_t* rusage) { static int uv__getrusage(int who, uv_rusage_t* rusage) {
struct rusage usage; struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage)) if (getrusage(who, &usage))
return UV__ERR(errno); return UV__ERR(errno);
rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
@ -1041,6 +1043,48 @@ int uv_getrusage(uv_rusage_t* rusage) {
} }
int uv_getrusage(uv_rusage_t* rusage) {
return uv__getrusage(RUSAGE_SELF, rusage);
}
int uv_getrusage_thread(uv_rusage_t* rusage) {
#if defined(__APPLE__)
mach_msg_type_number_t count;
thread_basic_info_data_t info;
kern_return_t kr;
thread_t thread;
thread = mach_thread_self();
count = THREAD_BASIC_INFO_COUNT;
kr = thread_info(thread,
THREAD_BASIC_INFO,
(thread_info_t)&info,
&count);
if (kr != KERN_SUCCESS) {
mach_port_deallocate(mach_task_self(), thread);
return UV_EINVAL;
}
memset(rusage, 0, sizeof(*rusage));
rusage->ru_utime.tv_sec = info.user_time.seconds;
rusage->ru_utime.tv_usec = info.user_time.microseconds;
rusage->ru_stime.tv_sec = info.system_time.seconds;
rusage->ru_stime.tv_usec = info.system_time.microseconds;
mach_port_deallocate(mach_task_self(), thread);
return 0;
#elif defined(RUSAGE_THREAD)
return uv__getrusage(RUSAGE_THREAD, rusage);
#endif /* defined(__APPLE__) */
return UV_ENOTSUP;
}
int uv__open_cloexec(const char* path, int flags) { int uv__open_cloexec(const char* path, int flags) {
#if defined(O_CLOEXEC) #if defined(O_CLOEXEC)
int fd; int fd;

View File

@ -874,56 +874,100 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
int uv_getrusage(uv_rusage_t *uv_rusage) { int uv_getrusage(uv_rusage_t *uv_rusage) {
FILETIME createTime, exitTime, kernelTime, userTime; FILETIME create_time, exit_time, kernel_time, user_time;
SYSTEMTIME kernelSystemTime, userSystemTime; SYSTEMTIME kernel_system_time, user_system_time;
PROCESS_MEMORY_COUNTERS memCounters; PROCESS_MEMORY_COUNTERS mem_counters;
IO_COUNTERS ioCounters; IO_COUNTERS io_counters;
int ret; int ret;
ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); ret = GetProcessTimes(GetCurrentProcess(),
&create_time,
&exit_time,
&kernel_time,
&user_time);
if (ret == 0) { if (ret == 0) {
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
} }
ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime); ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time);
if (ret == 0) { if (ret == 0) {
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
} }
ret = FileTimeToSystemTime(&userTime, &userSystemTime); ret = FileTimeToSystemTime(&user_time, &user_system_time);
if (ret == 0) { if (ret == 0) {
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
} }
ret = GetProcessMemoryInfo(GetCurrentProcess(), ret = GetProcessMemoryInfo(GetCurrentProcess(),
&memCounters, &mem_counters,
sizeof(memCounters)); sizeof(mem_counters));
if (ret == 0) { if (ret == 0) {
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
} }
ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); ret = GetProcessIoCounters(GetCurrentProcess(), &io_counters);
if (ret == 0) { if (ret == 0) {
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
} }
memset(uv_rusage, 0, sizeof(*uv_rusage)); memset(uv_rusage, 0, sizeof(*uv_rusage));
uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 +
userSystemTime.wMinute * 60 + user_system_time.wMinute * 60 +
userSystemTime.wSecond; user_system_time.wSecond;
uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000; uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000;
uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 + uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 +
kernelSystemTime.wMinute * 60 + kernel_system_time.wMinute * 60 +
kernelSystemTime.wSecond; kernel_system_time.wSecond;
uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000;
uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; uv_rusage->ru_majflt = (uint64_t) mem_counters.PageFaultCount;
uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; uv_rusage->ru_maxrss = (uint64_t) mem_counters.PeakWorkingSetSize / 1024;
uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; uv_rusage->ru_oublock = (uint64_t) io_counters.WriteOperationCount;
uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; uv_rusage->ru_inblock = (uint64_t) io_counters.ReadOperationCount;
return 0;
}
int uv_getrusage_thread(uv_rusage_t* uv_rusage) {
FILETIME create_time, exit_time, kernel_time, user_time;
SYSTEMTIME kernel_system_time, user_system_time;
int ret;
ret = GetThreadTimes(GetCurrentThread(),
&create_time,
&exit_time,
&kernel_time,
&user_time);
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time);
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
ret = FileTimeToSystemTime(&user_time, &user_system_time);
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
memset(uv_rusage, 0, sizeof(*uv_rusage));
uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 +
user_system_time.wMinute * 60 +
user_system_time.wSecond;
uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000;
uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 +
kernel_system_time.wMinute * 60 +
kernel_system_time.wSecond;
uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000;
return 0; return 0;
} }

View File

@ -236,5 +236,21 @@ TEST_IMPL(platform_output) {
printf(" version: %s\n", uname.version); printf(" version: %s\n", uname.version);
printf(" machine: %s\n", uname.machine); printf(" machine: %s\n", uname.machine);
ASSERT_OK(uv_getrusage_thread(&rusage));
ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0);
ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0);
ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0);
ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0);
printf("uv_getrusage_thread:\n");
printf(" user: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_utime.tv_sec,
(unsigned long long) rusage.ru_utime.tv_usec);
printf(" system: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_stime.tv_sec,
(unsigned long long) rusage.ru_stime.tv_usec);
printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt);
printf(" maximum resident set size: %llu\n",
(unsigned long long) rusage.ru_maxrss);
return 0; return 0;
} }