< prev index next >

src/hotspot/os/linux/osContainer_linux.cpp

Print this page
@  rev 54202 : 8217338: [Containers] Improve systemd slice memory limit support
|  Summary: Use hierachical memory limit in addition to memory_limits_in_bytes
~  Reviewed-by: duke

@@ -120,11 +120,29 @@
     }
 
     char *subsystem_path() { return _path; }
 };
 
-CgroupSubsystem* memory = NULL;
+class CgroupMemorySubsystem: CgroupSubsystem {
+ friend class OSContainer;
+
+ private:
+    /* Some container runtimes set limits via cgroup
+     * hierarchy. If set to true consider also memory.stat
+     * file if everything else seems unlimited */
+    bool _uses_mem_hierarchy;
+
+ public:
+    CgroupMemorySubsystem(char *root, char *mountpoint) : CgroupSubsystem::CgroupSubsystem(root, mountpoint) {
+      _uses_mem_hierarchy = false;
+    }
+
+    bool is_hierarchical() { return _uses_mem_hierarchy; }
+    void set_hierarchical(bool value) { _uses_mem_hierarchy = value; }
+};
+
+CgroupMemorySubsystem* memory = NULL;
 CgroupSubsystem* cpuset = NULL;
 CgroupSubsystem* cpu = NULL;
 CgroupSubsystem* cpuacct = NULL;
 
 typedef char * cptr;

@@ -179,10 +197,69 @@
     fclose(fp);
   return OSCONTAINER_ERROR;
 }
 PRAGMA_DIAG_POP
 
+PRAGMA_DIAG_PUSH
+PRAGMA_FORMAT_NONLITERAL_IGNORED
+template <typename T> int subsystem_file_line_contents(CgroupSubsystem* c,
+                                              const char *filename,
+                                              const char *matchline,
+                                              const char *scan_fmt,
+                                              T returnval) {
+  FILE *fp = NULL;
+  char *p;
+  char file[MAXPATHLEN+1];
+  char buf[MAXPATHLEN+1];
+  char discard[MAXPATHLEN+1];
+
+  if (c == NULL) {
+    log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL");
+    return OSCONTAINER_ERROR;
+  }
+  if (c->subsystem_path() == NULL) {
+    log_debug(os, container)("subsystem_file_contents: subsystem path is NULL");
+    return OSCONTAINER_ERROR;
+  }
+
+  strncpy(file, c->subsystem_path(), MAXPATHLEN);
+  file[MAXPATHLEN-1] = '\0';
+  int filelen = strlen(file);
+  if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) {
+    log_debug(os, container)("File path too long %s, %s", file, filename);
+    return OSCONTAINER_ERROR;
+  }
+  strncat(file, filename, MAXPATHLEN-filelen);
+  log_trace(os, container)("Path to %s is %s", filename, file);
+  fp = fopen(file, "r");
+  if (fp != NULL) {
+    int err = 0;
+    while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) {
+      if (strstr(p, matchline) != NULL) {
+        // discard matchline string prefix
+        int matched = sscanf(p, scan_fmt, discard, returnval);
+        if (matched == 2) {
+          fclose(fp);
+          return 0;
+        } else {
+          err = 1;
+          log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
+        }
+      }
+    }
+    if (err == 0) {
+      log_debug(os, container)("Empty file %s, or no match found for %s", file, matchline);
+    }
+  } else {
+    log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno));
+  }
+  if (fp != NULL)
+    fclose(fp);
+  return OSCONTAINER_ERROR;
+}
+PRAGMA_DIAG_POP
+
 #define GET_CONTAINER_INFO(return_type, subsystem, filename,              \
                            logstring, scan_fmt, variable)                 \
   return_type variable;                                                   \
 {                                                                         \
   int err;                                                                \

@@ -209,10 +286,26 @@
     return (return_type) NULL;                                            \
                                                                           \
   log_trace(os, container)(logstring, variable);                          \
 }
 
+#define GET_CONTAINER_INFO_LINE(return_type, subsystem, filename,         \
+                           matchline, logstring, scan_fmt, variable)      \
+  return_type variable;                                                   \
+{                                                                         \
+  int err;                                                                \
+  err = subsystem_file_line_contents(subsystem,                           \
+                                filename,                                 \
+                                matchline,                                \
+                                scan_fmt,                                 \
+                                &variable);                               \
+  if (err != 0)                                                           \
+    return (return_type) OSCONTAINER_ERROR;                               \
+                                                                          \
+  log_trace(os, container)(logstring, variable);                          \
+}
+
 /* init
  *
  * Initialize the container support and determine if
  * we are running under cgroup control.
  */

@@ -264,11 +357,11 @@
     if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- cgroup %*s %s", tmproot, tmpmount, tmpcgroups) != 3) {
       continue;
     }
     while ((token = strsep(&cptr, ",")) != NULL) {
       if (strcmp(token, "memory") == 0) {
-        memory = new CgroupSubsystem(tmproot, tmpmount);
+        memory = new CgroupMemorySubsystem(tmproot, tmpmount);
       } else if (strcmp(token, "cpuset") == 0) {
         cpuset = new CgroupSubsystem(tmproot, tmpmount);
       } else if (strcmp(token, "cpu") == 0) {
         cpu = new CgroupSubsystem(tmproot, tmpmount);
       } else if (strcmp(token, "cpuacct") == 0) {

@@ -342,10 +435,14 @@
     }
 
     while ((token = strsep(&controllers, ",")) != NULL) {
       if (strcmp(token, "memory") == 0) {
         memory->set_subsystem_path(base);
+        jlong hierarchy = uses_mem_hierarchy();
+        if (hierarchy > 0) {
+          memory->set_hierarchical(true);
+        }
       } else if (strcmp(token, "cpuset") == 0) {
         cpuset->set_subsystem_path(base);
       } else if (strcmp(token, "cpu") == 0) {
         cpu->set_subsystem_path(base);
       } else if (strcmp(token, "cpuacct") == 0) {

@@ -358,10 +455,11 @@
 
   // We need to update the amount of physical memory now that
   // command line arguments have been processed.
   if ((mem_limit = memory_limit_in_bytes()) > 0) {
     os::Linux::set_physical_memory(mem_limit);
+    log_info(os, container)("Memory Limit is: " JLONG_FORMAT, mem_limit);
   }
 
   _is_containerized = true;
 
 }

@@ -372,10 +470,25 @@
   } else {
     return NULL;
   }
 }
 
+/* uses_mem_hierarchy
+ *
+ * Return whether or not hierarchical cgroup accounting is being
+ * done.
+ *
+ * return:
+ *    A number > 0 if true, or
+ *    OSCONTAINER_ERROR for not supported
+ */
+jlong OSContainer::uses_mem_hierarchy() {
+  GET_CONTAINER_INFO(jlong, memory, "/memory.use_hierarchy",
+                    "Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy);
+  return use_hierarchy;
+}
+
 
 /* memory_limit_in_bytes
  *
  * Return the limit of available memory for this process.
  *

@@ -387,11 +500,22 @@
 jlong OSContainer::memory_limit_in_bytes() {
   GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes",
                      "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
 
   if (memlimit >= _unlimited_memory) {
-    log_trace(os, container)("Memory Limit is: Unlimited");
+    log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited");
+    if (memory->is_hierarchical()) {
+      const char* matchline = "hierarchical_memory_limit";
+      char* format = "%s " JULONG_FORMAT;
+      GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
+                             "Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit)
+      if (hier_memlimit >= _unlimited_memory) {
+        log_trace(os, container)("Hierarchical Memory Limit is: Unlimited");
+      } else {
+        return (jlong)hier_memlimit;
+      }
+    }
     return (jlong)-1;
   }
   else {
     return (jlong)memlimit;
   }

@@ -399,11 +523,22 @@
 
 jlong OSContainer::memory_and_swap_limit_in_bytes() {
   GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
                      "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
   if (memswlimit >= _unlimited_memory) {
-    log_trace(os, container)("Memory and Swap Limit is: Unlimited");
+    log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited");
+    if (memory->is_hierarchical()) {
+      const char* matchline = "hierarchical_memsw_limit";
+      char* format = "%s " JULONG_FORMAT;
+      GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
+                             "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit)
+      if (hier_memlimit >= _unlimited_memory) {
+        log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
+      } else {
+        return (jlong)hier_memlimit;
+      }
+    }
     return (jlong)-1;
   } else {
     return (jlong)memswlimit;
   }
 }
< prev index next >