Path: blob/master/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
40951 views
/*1* Copyright (c) 2020, Red Hat Inc.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "cgroupV2Subsystem_linux.hpp"2526/* cpu_shares27*28* Return the amount of cpu shares available to the process29*30* return:31* Share number (typically a number relative to 1024)32* (2048 typically expresses 2 CPUs worth of processing)33* -1 for no share setup34* OSCONTAINER_ERROR for not supported35*/36int CgroupV2Subsystem::cpu_shares() {37GET_CONTAINER_INFO(int, _unified, "/cpu.weight",38"Raw value for CPU shares is: %d", "%d", shares);39// Convert default value of 100 to no shares setup40if (shares == 100) {41log_debug(os, container)("CPU Shares is: %d", -1);42return -1;43}4445// CPU shares (OCI) value needs to get translated into46// a proper Cgroups v2 value. See:47// https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller48//49// Use the inverse of (x == OCI value, y == cgroupsv2 value):50// ((262142 * y - 1)/9999) + 2 = x51//52int x = 262142 * shares - 1;53double frac = x/9999.0;54x = ((int)frac) + 2;55log_trace(os, container)("Scaled CPU shares value is: %d", x);56// Since the scaled value is not precise, return the closest57// multiple of PER_CPU_SHARES for a more conservative mapping58if ( x <= PER_CPU_SHARES ) {59// will always map to 1 CPU60log_debug(os, container)("CPU Shares is: %d", x);61return x;62}63int f = x/PER_CPU_SHARES;64int lower_multiple = f * PER_CPU_SHARES;65int upper_multiple = (f + 1) * PER_CPU_SHARES;66int distance_lower = MAX2(lower_multiple, x) - MIN2(lower_multiple, x);67int distance_upper = MAX2(upper_multiple, x) - MIN2(upper_multiple, x);68x = distance_lower <= distance_upper ? lower_multiple : upper_multiple;69log_trace(os, container)("Closest multiple of %d of the CPU Shares value is: %d", PER_CPU_SHARES, x);70log_debug(os, container)("CPU Shares is: %d", x);71return x;72}7374/* cpu_quota75*76* Return the number of microseconds per period77* process is guaranteed to run.78*79* return:80* quota time in microseconds81* -1 for no quota82* OSCONTAINER_ERROR for not supported83*/84int CgroupV2Subsystem::cpu_quota() {85char * cpu_quota_str = cpu_quota_val();86int limit = (int)limit_from_str(cpu_quota_str);87log_trace(os, container)("CPU Quota is: %d", limit);88return limit;89}9091char * CgroupV2Subsystem::cpu_cpuset_cpus() {92GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.cpus",93"cpuset.cpus is: %s", "%1023s", cpus, 1024);94if (cpus == NULL) {95return NULL;96}97return os::strdup(cpus);98}99100char* CgroupV2Subsystem::cpu_quota_val() {101GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpu.max",102"Raw value for CPU quota is: %s", "%s %*d", quota, 1024);103if (quota == NULL) {104return NULL;105}106return os::strdup(quota);107}108109char * CgroupV2Subsystem::cpu_cpuset_memory_nodes() {110GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.mems",111"cpuset.mems is: %s", "%1023s", mems, 1024);112if (mems == NULL) {113return NULL;114}115return os::strdup(mems);116}117118int CgroupV2Subsystem::cpu_period() {119GET_CONTAINER_INFO(int, _unified, "/cpu.max",120"CPU Period is: %d", "%*s %d", period);121return period;122}123124/* memory_usage_in_bytes125*126* Return the amount of used memory used by this cgroup and decendents127*128* return:129* memory usage in bytes or130* -1 for unlimited131* OSCONTAINER_ERROR for not supported132*/133jlong CgroupV2Subsystem::memory_usage_in_bytes() {134GET_CONTAINER_INFO(jlong, _unified, "/memory.current",135"Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage);136return memusage;137}138139jlong CgroupV2Subsystem::memory_soft_limit_in_bytes() {140char* mem_soft_limit_str = mem_soft_limit_val();141return limit_from_str(mem_soft_limit_str);142}143144jlong CgroupV2Subsystem::memory_max_usage_in_bytes() {145// Log this string at trace level so as to make tests happy.146log_trace(os, container)("Maximum Memory Usage is not supported.");147return OSCONTAINER_ERROR; // not supported148}149150char* CgroupV2Subsystem::mem_soft_limit_val() {151GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.low",152"Memory Soft Limit is: %s", "%s", mem_soft_limit_str, 1024);153if (mem_soft_limit_str == NULL) {154return NULL;155}156return os::strdup(mem_soft_limit_str);157}158159// Note that for cgroups v2 the actual limits set for swap and160// memory live in two different files, memory.swap.max and memory.max161// respectively. In order to properly report a cgroup v1 like162// compound value we need to sum the two values. Setting a swap limit163// without also setting a memory limit is not allowed.164jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() {165char* mem_swp_limit_str = mem_swp_limit_val();166jlong swap_limit = limit_from_str(mem_swp_limit_str);167if (swap_limit >= 0) {168jlong memory_limit = read_memory_limit_in_bytes();169assert(memory_limit >= 0, "swap limit without memory limit?");170return memory_limit + swap_limit;171}172return swap_limit;173}174175char* CgroupV2Subsystem::mem_swp_limit_val() {176GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.max",177"Memory and Swap Limit is: %s", "%s", mem_swp_limit_str, 1024);178if (mem_swp_limit_str == NULL) {179return NULL;180}181return os::strdup(mem_swp_limit_str);182}183184/* memory_limit_in_bytes185*186* Return the limit of available memory for this process.187*188* return:189* memory limit in bytes or190* -1 for unlimited, OSCONTAINER_ERROR for an error191*/192jlong CgroupV2Subsystem::read_memory_limit_in_bytes() {193char * mem_limit_str = mem_limit_val();194jlong limit = limit_from_str(mem_limit_str);195if (log_is_enabled(Trace, os, container)) {196if (limit == -1) {197log_trace(os, container)("Memory Limit is: Unlimited");198} else {199log_trace(os, container)("Memory Limit is: " JLONG_FORMAT, limit);200}201}202return limit;203}204205jlong CgroupV2Subsystem::limit_from_str(char* limit_str) {206if (limit_str == NULL) {207return OSCONTAINER_ERROR;208}209// Unlimited memory in Cgroups V2 is the literal string 'max'210if (strcmp("max", limit_str) == 0) {211os::free(limit_str);212return (jlong)-1;213}214julong limit;215if (sscanf(limit_str, JULONG_FORMAT, &limit) != 1) {216os::free(limit_str);217return OSCONTAINER_ERROR;218}219os::free(limit_str);220return (jlong)limit;221}222223char* CgroupV2Subsystem::mem_limit_val() {224GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.max",225"Raw value for memory limit is: %s", "%s", mem_limit_str, 1024);226if (mem_limit_str == NULL) {227return NULL;228}229return os::strdup(mem_limit_str);230}231232char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) {233char buf[MAXPATHLEN+1];234int buflen;235strncpy(buf, mount_path, MAXPATHLEN);236buf[MAXPATHLEN] = '\0';237buflen = strlen(buf);238if ((buflen + strlen(cgroup_path)) > MAXPATHLEN) {239return NULL;240}241strncat(buf, cgroup_path, MAXPATHLEN-buflen);242buf[MAXPATHLEN] = '\0';243return os::strdup(buf);244}245246247248