--- /dev/null 2019-10-18 10:01:04.558192918 +0200 +++ new/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp 2019-10-18 18:16:16.595144008 +0200 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2019, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cgroupV2Subsystem_linux.hpp" + +/* cpu_shares + * + * Return the amount of cpu shares available to the process + * + * return: + * Share number (typically a number relative to 1024) + * (2048 typically expresses 2 CPUs worth of processing) + * -1 for no share setup + * OSCONTAINER_ERROR for not supported + */ +int CgroupV2Subsystem::cpu_shares() { + GET_CONTAINER_INFO(int, _unified->controller(), "/cpu.weight", + "CPU Shares is: %d", "%d", shares); + // Convert default value of 100 to no shares setup + if (shares == 100) return -1; + + // CPU shares (OCI) value needs to get translated into + // a proper Cgroups v2 value. See: + // https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller + // + // Use the inverse of (x == OCI value, y == cgroupsv2 value): + // ((262142 * y - 1)/9999) + 2 = x + // + int x = 262142 * shares - 1; + double frac = x/9999.0; + x = ((int)frac) + 2; + log_trace(os, container)("Scaled CPU Shares value is: %d", x); + // Since the scaled value is not precise, return the closest + // multiple of PER_CPU_SHARES for a more conservative mapping + if ( x <= PER_CPU_SHARES ) { + // will always map to 1 CPU + return x; + } + int f = x/PER_CPU_SHARES; + int lower_multiple = f * PER_CPU_SHARES; + int upper_multiple = (f + 1) * PER_CPU_SHARES; + int distance_lower = MAX2(lower_multiple, x) - MIN2(lower_multiple, x); + int distance_upper = MAX2(upper_multiple, x) - MIN2(upper_multiple, x); + x = distance_lower <= distance_upper ? lower_multiple : upper_multiple; + log_trace(os, container)("Closest multiple of %d of the CPU Shares value is: %d", PER_CPU_SHARES, x); + return x; +} + +/* cpu_quota + * + * Return the number of milliseconds per period + * process is guaranteed to run. + * + * return: + * quota time in milliseconds + * -1 for no quota + * OSCONTAINER_ERROR for not supported + */ +int CgroupV2Subsystem::cpu_quota() { + char * cpu_quota_str = cpu_quota_val(); + return (int)limit_from_str(cpu_quota_str); +} + +char * CgroupV2Subsystem::cpu_cpuset_cpus() { + GET_CONTAINER_INFO_CPTR(cptr, _unified->controller(), "/cpuset.cpus", + "cpuset.cpus is: %s", "%1023s", cpus, 1024); + if (cpus == NULL) { + return NULL; + } + return os::strdup(cpus); +} + +char* CgroupV2Subsystem::cpu_quota_val() { + GET_CONTAINER_INFO_CPTR(cptr, _unified->controller(), "/cpu.max", + "CPU Quota is: %s", "%s %*d", quota, 1024); + if (quota == NULL) { + return NULL; + } + return os::strdup(quota); +} + +char * CgroupV2Subsystem::cpu_cpuset_memory_nodes() { + GET_CONTAINER_INFO_CPTR(cptr, _unified->controller(), "/cpuset.mems", + "cpuset.mems is: %s", "%1023s", mems, 1024); + if (mems == NULL) { + return NULL; + } + return os::strdup(mems); +} + +int CgroupV2Subsystem::cpu_period() { + GET_CONTAINER_INFO(int, _unified->controller(), "/cpu.max", + "CPU Period is: %d", "%*s %d", period); + return period; +} + +/* memory_usage_in_bytes + * + * Return the amount of used memory used by this cgroup and decendents + * + * return: + * memory usage in bytes or + * -1 for unlimited + * OSCONTAINER_ERROR for not supported + */ +jlong CgroupV2Subsystem::memory_usage_in_bytes() { + GET_CONTAINER_INFO(jlong, _unified->controller(), "/memory.current", + "Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage); + return memusage; +} + +jlong CgroupV2Subsystem::memory_soft_limit_in_bytes() { + char* mem_soft_limit_str = mem_soft_limit_val(); + return limit_from_str(mem_soft_limit_str); +} + +jlong CgroupV2Subsystem::memory_max_usage_in_bytes() { + return OSCONTAINER_ERROR; // Not supported for Cgroups V2. +} + +char* CgroupV2Subsystem::mem_soft_limit_val() { + GET_CONTAINER_INFO_CPTR(cptr, _unified->controller(), "/memory.high", + "Memory Soft Limit is: %s", "%s", mem_soft_limit_str, 1024); + if (mem_soft_limit_str == NULL) { + return NULL; + } + return os::strdup(mem_soft_limit_str); +} + +jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { + char* mem_swp_limit_str = mem_swp_limit_val(); + return limit_from_str(mem_swp_limit_str); +} + +char* CgroupV2Subsystem::mem_swp_limit_val() { + GET_CONTAINER_INFO_CPTR(cptr, _unified->controller(), "/memory.swap.max", + "Memory and Swap Limit is: %s", "%s", mem_swp_limit_str, 1024); + if (mem_swp_limit_str == NULL) { + return NULL; + } + return os::strdup(mem_swp_limit_str); +} + +/* memory_limit_in_bytes + * + * Return the limit of available memory for this process. + * + * return: + * memory limit in bytes or + * -1 for unlimited, OSCONTAINER_ERROR for an error + */ +jlong CgroupV2Subsystem::read_memory_limit_in_bytes() { + char * mem_limit_str = mem_limit_val(); + return limit_from_str(mem_limit_str); +} + +jlong CgroupV2Subsystem::limit_from_str(char* limit_str) { + if (limit_str == NULL) { + return OSCONTAINER_ERROR; + } + // Unlimited memory in Cgroups V2 is the literal string 'max' + if (strcmp("max", limit_str) == 0) { + os::free(limit_str); + return (jlong)-1; + } + julong limit; + if (sscanf(limit_str, JULONG_FORMAT, &limit) != 1) { + os::free(limit_str); + return OSCONTAINER_ERROR; + } + os::free(limit_str); + return (jlong)limit; +} + +char* CgroupV2Subsystem::mem_limit_val() { + GET_CONTAINER_INFO_CPTR(cptr, _unified->controller(), "/memory.max", + "Memory Limit is: %s", "%s", mem_limit_str, 1024); + if (mem_limit_str == NULL) { + return NULL; + } + return os::strdup(mem_limit_str); +} + +char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) { + char buf[MAXPATHLEN+1]; + int buflen; + strncpy(buf, mount_path, MAXPATHLEN); + buf[MAXPATHLEN] = '\0'; + buflen = strlen(buf); + if ((buflen + strlen(cgroup_path)) > MAXPATHLEN) { + return NULL; + } + strncat(buf, cgroup_path, MAXPATHLEN-buflen); + buf[MAXPATHLEN] = '\0'; + return os::strdup(buf); +} +