This is an automated email from the ASF dual-hosted git repository.

kgiusti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/master by this push:
     new 7e7e8a0  DISPATCH-1572: (partial fix) heuristic to determine available 
RAM
7e7e8a0 is described below

commit 7e7e8a0f7f588870538c492a296cb397feaf8e4f
Author: Kenneth Giusti <[email protected]>
AuthorDate: Wed Feb 12 09:36:58 2020 -0500

    DISPATCH-1572: (partial fix) heuristic to determine available RAM
    
    The patch merely implements a form of memory detection.  Additional
    work remains to implement low memory mitigation.
---
 .../qpid/dispatch/platform.h                       |  27 ++++-
 src/CMakeLists.txt                                 |   4 +
 src/config.h.in                                    |   1 +
 src/platform.c                                     | 113 +++++++++++++++++++++
 src/server.c                                       |  35 +++++++
 5 files changed, 176 insertions(+), 4 deletions(-)

diff --git a/src/config.h.in b/include/qpid/dispatch/platform.h
similarity index 55%
copy from src/config.h.in
copy to include/qpid/dispatch/platform.h
index 7947506..5e1a149 100644
--- a/src/config.h.in
+++ b/include/qpid/dispatch/platform.h
@@ -1,3 +1,5 @@
+#ifndef __dispatch_platform_h__
+#define __dispatch_platform_h__ 1
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -17,7 +19,24 @@
  * under the License.
  */
 
-#define QPID_DISPATCH_VERSION "${QPID_DISPATCH_VERSION}"
-#define QPID_DISPATCH_LIB 
"$<$<BOOL:${APPLE}>:@rpath/>$<TARGET_FILE_NAME:qpid-dispatch>"
-#define QPID_CONSOLE_STAND_ALONE_INSTALL_DIR 
"${CONSOLE_STAND_ALONE_INSTALL_DIR}"
-#cmakedefine01 QD_MEMORY_STATS
+#include <stdint.h>
+
+/**
+ * Platform specific utility functions
+ */
+
+/**
+ * Determine the amount of usable 'fast' memory (RAM only, not including swap)
+ * installed.  If resource constraints are in use (e.g setrlimit(),
+ * containerization, etc) for the qdrouterd process this routine should return
+ * the minimum of (physical memory, memory resource limit).
+ *
+ * This value is used by the router to detect and react to low memory
+ * conditions.
+ *
+ * Returns the size of fast memory in bytes or zero if the size cannot be
+ * determined.
+ */
+uintmax_t qd_platform_memory_size(void);
+
+#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0a01d43..4257d95 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -65,6 +65,7 @@ set(qpid_dispatch_SOURCES
   router_agent.c
   router_config.c
   address_lookup_utils.c
+  platform.c
   router_core/agent.c
   router_core/agent_address.c
   router_core/agent_config_address.c
@@ -157,6 +158,9 @@ set_target_properties(qpid-dispatch PROPERTIES
 install(TARGETS qpid-dispatch
   LIBRARY DESTINATION ${QPID_DISPATCH_HOME})
 
+# check for various function availability
+check_symbol_exists(getrlimit sys/resource.h QD_HAVE_GETRLIMIT)
+
 # 
https://stackoverflow.com/questions/54771452/expanding-a-variable-cmakedefine-and-generator-expression-in-template-file
 file(READ "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" CONFIG_H_IN)
 string(CONFIGURE "${CONFIG_H_IN}" CONFIG_H_TMP)
diff --git a/src/config.h.in b/src/config.h.in
index 7947506..21ea9e1 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -21,3 +21,4 @@
 #define QPID_DISPATCH_LIB 
"$<$<BOOL:${APPLE}>:@rpath/>$<TARGET_FILE_NAME:qpid-dispatch>"
 #define QPID_CONSOLE_STAND_ALONE_INSTALL_DIR 
"${CONSOLE_STAND_ALONE_INSTALL_DIR}"
 #cmakedefine01 QD_MEMORY_STATS
+#cmakedefine01 QD_HAVE_GETRLIMIT
diff --git a/src/platform.c b/src/platform.c
new file mode 100644
index 0000000..b1cd61b
--- /dev/null
+++ b/src/platform.c
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <qpid/dispatch/platform.h>
+#include <qpid/dispatch/ctools.h>
+
+
+uintmax_t qd_platform_memory_size(void)
+{
+    bool found = false;
+    uintmax_t rlimit = UINTMAX_MAX;
+
+#if QD_HAVE_GETRLIMIT
+    {
+        // determine if this process has a hard or soft limit set for its total
+        // virtual address space
+        struct rlimit rl = {0};
+        // note rlim_max >= rlim_cur (see man getrlimit) use smallest value
+        if (getrlimit(RLIMIT_AS, &rl) == 0) {
+            if (rl.rlim_cur != RLIM_INFINITY) {
+                rlimit = (uintmax_t)rl.rlim_cur;
+                found = true;
+            } else if (rl.rlim_max != RLIM_INFINITY) {
+                rlimit = (uintmax_t)rl.rlim_max;
+                found = true;
+            }
+        }
+    }
+#endif // QD_HAVE_GETRLIMIT
+
+    // although a resource limit may be set be sure it does not exceed the
+    // available "fast" memory.
+
+    // @TODO(kgiusti) this is linux-specific (see man proc)
+    uintmax_t mlimit = UINTMAX_MAX;
+    FILE *minfo_fp = fopen("/proc/meminfo", "r");
+    if (minfo_fp) {
+        size_t buflen = 0;
+        char *buffer = 0;
+        uintmax_t tmp;
+        while (getline(&buffer, &buflen, minfo_fp) != -1) {
+            if (sscanf(buffer, "MemTotal: %"SCNuMAX, &tmp) == 1) {
+                mlimit = tmp * 1024;  // MemTotal is in KiB
+                found = true;
+                break;
+            }
+        }
+        free(buffer);  // allocated by getline
+        fclose(minfo_fp);
+    }
+
+    // and if qdrouterd is running within a container check the cgroups memory
+    // controller. Hard and soft memory limits can be set.
+
+    uintmax_t climit = UINTMAX_MAX;
+    {
+        uintmax_t soft = UINTMAX_MAX;
+        uintmax_t hard = UINTMAX_MAX;
+        bool c_set = false;
+
+        FILE *cg_fp = fopen("/sys/fs/cgroup/memory/memory.limit_in_bytes", 
"r");
+        if (cg_fp) {
+            if (fscanf(cg_fp, "%"SCNuMAX, &hard) == 1) {
+                c_set = true;
+            }
+            fclose(cg_fp);
+        }
+
+        cg_fp = fopen("/sys/fs/cgroup/memory/memory.soft_limit_in_bytes", "r");
+        if (cg_fp) {
+            if (fscanf(cg_fp, "%"SCNuMAX, &soft) == 1) {
+                c_set = true;
+            }
+            fclose(cg_fp);
+        }
+
+        if (c_set) {
+            climit = MIN(soft, hard);
+            found = true;
+        }
+    }
+
+    if (found) {
+        uintmax_t tmp = MIN(mlimit, climit);
+        return MIN(rlimit, tmp);
+    }
+
+    return 0;
+}
diff --git a/src/server.c b/src/server.c
index 8644ef5..4bc78fd 100644
--- a/src/server.c
+++ b/src/server.c
@@ -28,6 +28,7 @@
 #include <qpid/dispatch/server.h>
 #include <qpid/dispatch/failoverlist.h>
 #include <qpid/dispatch/alloc.h>
+#include <qpid/dispatch/platform.h>
 
 #include <proton/event.h>
 #include <proton/listener.h>
@@ -1318,6 +1319,27 @@ void qd_server_trace_all_connections()
     }
 }
 
+
+static double normalize_memory_size(const uint64_t bytes, const char **suffix)
+{
+    static const char * const units[] = {"B", "KiB", "MiB", "GiB", "TiB"};
+    const int units_ct = 5;
+    const double base = 1024.0;
+
+    double value = (double)bytes;
+    for (int i = 0; i < units_ct; ++i) {
+        if (value < base) {
+            if (suffix)
+                *suffix = units[i];
+            return value;
+        }
+        value /= base;
+    }
+    if (suffix)
+        *suffix = units[units_ct - 1];
+    return value;
+}
+
 void qd_server_run(qd_dispatch_t *qd)
 {
     qd_server_t *qd_server = qd->server;
@@ -1327,6 +1349,19 @@ void qd_server_run(qd_dispatch_t *qd)
     qd_log(qd_server->log_source,
            QD_LOG_NOTICE, "Operational, %d Threads Running (process ID %ld)",
            qd_server->thread_count, (long)getpid());
+
+    const uintmax_t ram_size = qd_platform_memory_size();
+    const uint64_t  vm_size = qd_router_memory_usage();
+    if (ram_size && vm_size) {
+        const char *suffix_vm = 0;
+        const char *suffix_ram = 0;
+        double vm = normalize_memory_size(vm_size, &suffix_vm);
+        double ram = normalize_memory_size(ram_size, &suffix_ram);
+        qd_log(qd_server->log_source, QD_LOG_NOTICE,
+               "Process VmSize %.2f %s (%.2f %s available memory)",
+               vm, suffix_vm, ram, suffix_ram);
+    }
+
 #ifndef NDEBUG
     qd_log(qd_server->log_source, QD_LOG_INFO, "Running in DEBUG Mode");
 #endif


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to