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.
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)
Returns the current process ID.

View File

@ -1295,6 +1295,7 @@ typedef struct {
} uv_rusage_t;
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_tmpdir(char* buffer, size_t* size);

View File

@ -52,6 +52,8 @@
#endif
#if defined(__APPLE__)
# include <mach/mach.h>
# include <mach/thread_info.h>
# include <sys/filio.h>
# include <sys/sysctl.h>
#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;
if (getrusage(RUSAGE_SELF, &usage))
if (getrusage(who, &usage))
return UV__ERR(errno);
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) {
#if defined(O_CLOEXEC)
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) {
FILETIME createTime, exitTime, kernelTime, userTime;
SYSTEMTIME kernelSystemTime, userSystemTime;
PROCESS_MEMORY_COUNTERS memCounters;
IO_COUNTERS ioCounters;
FILETIME create_time, exit_time, kernel_time, user_time;
SYSTEMTIME kernel_system_time, user_system_time;
PROCESS_MEMORY_COUNTERS mem_counters;
IO_COUNTERS io_counters;
int ret;
ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
ret = GetProcessTimes(GetCurrentProcess(),
&create_time,
&exit_time,
&kernel_time,
&user_time);
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time);
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
ret = FileTimeToSystemTime(&userTime, &userSystemTime);
ret = FileTimeToSystemTime(&user_time, &user_system_time);
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
ret = GetProcessMemoryInfo(GetCurrentProcess(),
&memCounters,
sizeof(memCounters));
&mem_counters,
sizeof(mem_counters));
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
ret = GetProcessIoCounters(GetCurrentProcess(), &io_counters);
if (ret == 0) {
return uv_translate_sys_error(GetLastError());
}
memset(uv_rusage, 0, sizeof(*uv_rusage));
uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
userSystemTime.wMinute * 60 +
userSystemTime.wSecond;
uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
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 = kernelSystemTime.wHour * 3600 +
kernelSystemTime.wMinute * 60 +
kernelSystemTime.wSecond;
uv_rusage->ru_stime.tv_usec = kernelSystemTime.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;
uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
uv_rusage->ru_majflt = (uint64_t) mem_counters.PageFaultCount;
uv_rusage->ru_maxrss = (uint64_t) mem_counters.PeakWorkingSetSize / 1024;
uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
uv_rusage->ru_oublock = (uint64_t) io_counters.WriteOperationCount;
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;
}

View File

@ -236,5 +236,21 @@ TEST_IMPL(platform_output) {
printf(" version: %s\n", uname.version);
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;
}