# HG changeset patch # User sgehwolf # Date 1552383807 -3600 # Node ID ccaca70e893cc923e7f52c07f4728c22460fcf5c # Parent e3d3b961123936df43620133bf17245770f00703 8217338: [Containers] Improve systemd slice memory limit support Summary: Use hierachical memory limit in addition to memory_limits_in_bytes Reviewed-by: bobv, dholmes diff -r e3d3b9611239 -r ccaca70e893c src/os/linux/vm/osContainer_linux.cpp --- a/src/os/linux/vm/osContainer_linux.cpp Fri Mar 29 08:36:33 2019 +0100 +++ b/src/os/linux/vm/osContainer_linux.cpp Tue Mar 12 10:43:27 2019 +0100 @@ -115,7 +115,25 @@ } }; -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; @@ -124,24 +142,27 @@ PRAGMA_DIAG_PUSH PRAGMA_FORMAT_NONLITERAL_IGNORED -template int subsystem_file_contents(CgroupSubsystem* c, +template 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]; + bool found_match = false; if (c == NULL) { if (PrintContainerInfo) { - tty->print_cr("subsystem_file_contents: CgroupSubsytem* is NULL"); + tty->print_cr("subsystem_file_line_contents: CgroupSubsytem* is NULL"); } return OSCONTAINER_ERROR; } if (c->subsystem_path() == NULL) { if (PrintContainerInfo) { - tty->print_cr("subsystem_file_contents: subsystem path is NULL"); + tty->print_cr("subsystem_file_line_contents: subsystem path is NULL"); } return OSCONTAINER_ERROR; } @@ -161,19 +182,33 @@ } fp = fopen(file, "r"); if (fp != NULL) { - p = fgets(buf, MAXPATHLEN, fp); - if (p != NULL) { - int matched = sscanf(p, scan_fmt, returnval); - if (matched == 1) { + int err = 0; + while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) { + found_match = false; + if (matchline == NULL) { + // single-line file case + int matched = sscanf(p, scan_fmt, returnval); + found_match = (matched == 1); + } else { + // multi-line file case + if (strstr(p, matchline) != NULL) { + // discard matchline string prefix + int matched = sscanf(p, scan_fmt, discard, returnval); + found_match = (matched == 2); + } else { + continue; // substring not found + } + } + if (found_match) { fclose(fp); return 0; } else { + err = 1; if (PrintContainerInfo) { tty->print_cr("Type %s not found in file %s", scan_fmt, file); } } - } else { - if (PrintContainerInfo) { + if (err == 0 && PrintContainerInfo) { tty->print_cr("Empty file %s", file); } } @@ -193,10 +228,11 @@ return_type variable; \ { \ int err; \ - err = subsystem_file_contents(subsystem, \ - filename, \ - scan_fmt, \ - &variable); \ + err = subsystem_file_line_contents(subsystem, \ + filename, \ + NULL, \ + scan_fmt, \ + &variable); \ if (err != 0) \ return (return_type) OSCONTAINER_ERROR; \ \ @@ -209,10 +245,11 @@ char variable[bufsize]; \ { \ int err; \ - err = subsystem_file_contents(subsystem, \ - filename, \ - scan_fmt, \ - variable); \ + err = subsystem_file_line_contents(subsystem, \ + filename, \ + NULL, \ + scan_fmt, \ + variable); \ if (err != 0) \ return (return_type) NULL; \ \ @@ -220,6 +257,24 @@ tty->print_cr(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; \ + \ + if (PrintContainerInfo) \ + tty->print_cr(logstring, variable); \ +} + + /* init * * Initialize the container support and determine if @@ -281,7 +336,7 @@ } 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) { @@ -368,6 +423,10 @@ 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) { @@ -384,6 +443,9 @@ // command line arguments have been processed. if ((mem_limit = memory_limit_in_bytes()) > 0) { os::Linux::set_physical_memory(mem_limit); + if (PrintContainerInfo) { + tty->print_cr("Memory Limit is: " JLONG_FORMAT, mem_limit); + } } _is_containerized = true; @@ -398,6 +460,21 @@ } } +/* 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 * @@ -414,7 +491,20 @@ if (memlimit >= _unlimited_memory) { if (PrintContainerInfo) { - tty->print_cr("Memory Limit is: Unlimited"); + tty->print_cr("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) { + if (PrintContainerInfo) { + tty->print_cr("Hierarchical Memory Limit is: Unlimited"); + } + } else { + return (jlong)hier_memlimit; + } } return (jlong)-1; } @@ -428,7 +518,20 @@ "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit); if (memswlimit >= _unlimited_memory) { if (PrintContainerInfo) { - tty->print_cr("Memory and Swap Limit is: Unlimited"); + tty->print_cr("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) { + if (PrintContainerInfo) { + tty->print_cr("Hierarchical Memory and Swap Limit is: Unlimited"); + } + } else { + return (jlong)hier_memlimit; + } } return (jlong)-1; } else { diff -r e3d3b9611239 -r ccaca70e893c src/os/linux/vm/osContainer_linux.hpp --- a/src/os/linux/vm/osContainer_linux.hpp Fri Mar 29 08:36:33 2019 +0100 +++ b/src/os/linux/vm/osContainer_linux.hpp Tue Mar 12 10:43:27 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ static inline bool is_containerized(); static const char * container_type(); + static jlong uses_mem_hierarchy(); static jlong memory_limit_in_bytes(); static jlong memory_and_swap_limit_in_bytes(); static jlong memory_soft_limit_in_bytes();