/* * Copyright (c) 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 * 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. * */ #ifndef CGROUP_SUBSYSTEM_LINUX_HPP #define CGROUP_SUBSYSTEM_LINUX_HPP #include "memory/allocation.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "osContainer_linux.hpp" /* * PER_CPU_SHARES has been set to 1024 because CPU shares' quota * is commonly used in cloud frameworks like Kubernetes[1], * AWS[2] and Mesos[3] in a similar way. They spawn containers with * --cpu-shares option values scaled by PER_CPU_SHARES. Thus, we do * the inverse for determining the number of possible available * CPUs to the JVM inside a container. See JDK-8216366. * * [1] https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu * In particular: * When using Docker: * The spec.containers[].resources.requests.cpu is converted to its core value, which is potentially * fractional, and multiplied by 1024. The greater of this number or 2 is used as the value of the * --cpu-shares flag in the docker run command. * [2] https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html * [3] https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/docker/docker.cpp#L648 * https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/slave/containerizer/mesos/isolators/cgroups/constants.hpp#L30 */ #define PER_CPU_SHARES 1024 // Four controllers: cpu, cpuset, cpuacct, memory #define CG_INFO_LENGTH 4 class CgroupSubsystem: CHeapObj { friend class CgroupSubsystemFactory; private: virtual int cpu_quota(); virtual int cpu_period(); virtual int cpu_shares(); virtual jlong memory_usage_in_bytes(); virtual jlong memory_and_swap_limit_in_bytes(); virtual jlong memory_soft_limit_in_bytes(); virtual jlong memory_max_usage_in_bytes(); virtual char * cpu_cpuset_cpus(); virtual char * cpu_cpuset_memory_nodes(); public: jlong available_memory(); int active_processor_count(int physical_proc_count); void print_container_info(outputStream* st, int physical_proc_count); virtual jlong memory_limit_in_bytes(); virtual const char * container_type(); }; class CgroupController: CHeapObj { friend class CgroupSubsystemFactory; public: virtual char *subsystem_path(); }; class CgroupSubsystemFactory: AllStatic { public: static CgroupSubsystem* create(); }; class CgroupV1Controller: public CgroupController { friend class CgroupSubsystemFactory; private: /* mountinfo contents */ char *_root; char *_mount_point; /* Constructed subsystem directory */ char *_path; public: CgroupV1Controller(char *root, char *mountpoint) { _root = os::strdup(root); _mount_point = os::strdup(mountpoint); _path = NULL; } virtual void set_subsystem_path(char *cgroup_path); char *subsystem_path() { return _path; } }; class CgroupV1MemoryController: public CgroupV1Controller { friend class CgroupSubsystemFactory; public: bool is_hierarchical() { return _uses_mem_hierarchy; } 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; jlong uses_mem_hierarchy(); void set_subsystem_path(char *cgroup_path); void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } public: CgroupV1MemoryController(char *root, char *mountpoint) : CgroupV1Controller(root, mountpoint) { _uses_mem_hierarchy = false; } }; class CgroupV1Subsystem: CgroupSubsystem { friend class CgroupSubsystemFactory; public: jlong memory_limit_in_bytes(); private: julong _unlimited_memory; /* controllers */ CgroupV1MemoryController* _memory = NULL; CgroupV1Controller* _cpuset = NULL; CgroupV1Controller* _cpu = NULL; CgroupV1Controller* _cpuacct = NULL; jlong memory_and_swap_limit_in_bytes(); jlong memory_soft_limit_in_bytes(); jlong memory_usage_in_bytes(); jlong memory_max_usage_in_bytes(); char * cpu_cpuset_cpus(); char * cpu_cpuset_memory_nodes(); int cpu_quota(); int cpu_period(); int cpu_shares(); const char * container_type() { return "cgroupv1"; } public: CgroupV1Subsystem(CgroupV1Controller* cpuset, CgroupV1Controller* cpu, CgroupV1Controller* cpuacct, CgroupV1MemoryController* memory) { _cpuset = cpuset; _cpu = cpu; _cpuacct = cpuacct; _memory = memory; _unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size(); } }; class CgroupV2Controller: public CgroupController { friend class CgroupSubsystemFactory; private: /* the mount path of the cgroup v2 hierarchy */ char *_mount_path; /* The cgroup path for the controller */ char *_cgroup_path; /* Constructed full path to the subsystem directory */ char *_path; static char* construct_path(char* mount_path, char *cgroup_path); public: CgroupV2Controller(char * mount_path, char *cgroup_path) { _mount_path = mount_path; _cgroup_path = os::strdup(cgroup_path); _path = construct_path(mount_path, cgroup_path); } char *subsystem_path() { return _path; } }; class CgroupV2Subsystem: CgroupSubsystem { friend class CgroupSubsystemFactory; private: /* One unified controller */ CgroupController* _unified = NULL; CgroupV2Subsystem(CgroupController* unified) { _unified = unified; } char *mem_limit_val(); char *mem_swp_limit_val(); char *mem_soft_limit_val(); char *cpu_quota_val(); int cpu_quota(); int cpu_period(); int cpu_shares(); jlong limit_from_str(char* limit_str); jlong memory_and_swap_limit_in_bytes(); jlong memory_soft_limit_in_bytes(); jlong memory_usage_in_bytes(); jlong memory_max_usage_in_bytes(); char * cpu_cpuset_cpus(); char * cpu_cpuset_memory_nodes(); public: jlong memory_limit_in_bytes(); const char * container_type() { return "cgroupv2"; } }; // Class representing info in /proc/self/cgroup. // See man 7 cgroups class CgroupInfo : public StackObj { friend class CgroupSubsystemFactory; private: char* _name; int _hierarchy_id; bool _enabled; char* _cgroup_path; }; #endif // CGROUP_SUBSYSTEM_LINUX_HPP