From c4e9657d59723a6273ce68bda935680e1b3596c5 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 1 May 2019 13:54:56 -0700 Subject: [PATCH] unix,win: add uv_get_constrained_memory() Fixes: https://github.com/libuv/libuv/issues/2286 PR-URL: https://github.com/libuv/libuv/pull/2289 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- docs/src/misc.rst | 13 +++++++++++++ include/uv.h | 1 + src/unix/aix.c | 5 +++++ src/unix/darwin.c | 5 +++++ src/unix/freebsd.c | 5 +++++ src/unix/ibmi.c | 5 +++++ src/unix/linux-core.c | 39 +++++++++++++++++++++++++++++++++++++++ src/unix/netbsd.c | 5 +++++ src/unix/openbsd.c | 5 +++++ src/unix/os390.c | 5 +++++ src/unix/sunos.c | 5 +++++ src/win/util.c | 5 +++++ test/test-get-memory.c | 6 ++++-- 13 files changed, 102 insertions(+), 2 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 4ad4e40af..ef70e14bf 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -461,6 +461,19 @@ API Gets memory information (in bytes). +.. c:function:: uint64_t uv_get_constrained_memory(void) + + Gets the amount of memory available to the process (in bytes) based on + limits imposed by the OS. If there is no such constraint, or the constraint + is unknown, `0` is returned. Note that it is not unusual for this value to + be less than or greater than :c:func:`uv_get_total_memory`. + + .. note:: + This function currently only returns a non-zero value on Linux, based + on cgroups if it is present. + + .. versionadded:: 1.29.0 + .. c:function:: uint64_t uv_hrtime(void) Returns the current high-resolution real time. This is expressed in diff --git a/include/uv.h b/include/uv.h index df15b8367..f97801cec 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1561,6 +1561,7 @@ UV_EXTERN int uv_chdir(const char* dir); UV_EXTERN uint64_t uv_get_free_memory(void); UV_EXTERN uint64_t uv_get_total_memory(void); +UV_EXTERN uint64_t uv_get_constrained_memory(void); UV_EXTERN uint64_t uv_hrtime(void); diff --git a/src/unix/aix.c b/src/unix/aix.c index ec1fb8b01..1f36926c0 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -344,6 +344,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { perfstat_cpu_total_t ps_total; int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 31ad8a9e4..e4cd8ff7e 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -117,6 +117,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 0f729cfd4..7de88d6a5 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -137,6 +137,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c index 04b5654b9..8b355033e 100644 --- a/src/unix/ibmi.c +++ b/src/unix/ibmi.c @@ -183,6 +183,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { SSTS0200 rcvr; diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 1e42bcc94..12324c40b 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -1011,3 +1011,42 @@ uint64_t uv_get_total_memory(void) { return 0; } + + +static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) { + char filename[256]; + uint64_t rc; + int fd; + ssize_t n; + char buf[32]; /* Large enough to hold an encoded uint64_t. */ + + snprintf(filename, 256, "/sys/fs/cgroup/%s/%s", cgroup, param); + + rc = 0; + fd = uv__open_cloexec(filename, O_RDONLY); + + if (fd < 0) + return 0; + + n = read(fd, buf, sizeof(buf) - 1); + + if (n > 0) { + buf[n] = '\0'; + sscanf(buf, "%llu", &rc); + } + + if (uv__close_nocheckstdio(fd)) + abort(); + + return rc; +} + + +uint64_t uv_get_constrained_memory(void) { + /* + * This might return 0 if there was a problem getting the memory limit from + * cgroups. This is OK because a return value of 0 signifies that the memory + * limit is unknown. + */ + return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes"); +} diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index a2a4e5215..c649bb375 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -126,6 +126,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + int uv_resident_set_memory(size_t* rss) { kvm_t *kd = NULL; struct kinfo_proc2 *kinfo = NULL; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index bffb58bcd..ffae7683d 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -136,6 +136,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + int uv_resident_set_memory(size_t* rss) { struct kinfo_proc kinfo; size_t page_size = getpagesize(); diff --git a/src/unix/os390.c b/src/unix/os390.c index 70e389ece..273ded7ca 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -356,6 +356,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + int uv_resident_set_memory(size_t* rss) { char* ascb; char* rax; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index fb6b070fd..f323d1def 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -380,6 +380,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { (void) getloadavg(avg, 3); } diff --git a/src/win/util.c b/src/win/util.c index 0e8c339d2..7ca83213a 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -320,6 +320,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + uv_pid_t uv_os_getpid(void) { return GetCurrentProcessId(); } diff --git a/test/test-get-memory.c b/test/test-get-memory.c index 2396939bc..0e0864038 100644 --- a/test/test-get-memory.c +++ b/test/test-get-memory.c @@ -25,10 +25,12 @@ TEST_IMPL(get_memory) { uint64_t free_mem = uv_get_free_memory(); uint64_t total_mem = uv_get_total_memory(); + uint64_t constrained_mem = uv_get_constrained_memory(); - printf("free_mem=%llu, total_mem=%llu\n", + printf("free_mem=%llu, total_mem=%llu, constrained_mem=%llu\n", (unsigned long long) free_mem, - (unsigned long long) total_mem); + (unsigned long long) total_mem, + (unsigned long long) constrained_mem); ASSERT(free_mem > 0); ASSERT(total_mem > 0);