1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef CGROUP_SUBSYSTEM_LINUX_HPP 26 #define CGROUP_SUBSYSTEM_LINUX_HPP 27 28 #include "memory/allocation.hpp" 29 #include "runtime/os.hpp" 30 #include "utilities/globalDefinitions.hpp" 31 #include "utilities/macros.hpp" 32 #include "osContainer_linux.hpp" 33 34 /* 35 * PER_CPU_SHARES has been set to 1024 because CPU shares' quota 36 * is commonly used in cloud frameworks like Kubernetes[1], 37 * AWS[2] and Mesos[3] in a similar way. They spawn containers with 38 * --cpu-shares option values scaled by PER_CPU_SHARES. Thus, we do 39 * the inverse for determining the number of possible available 40 * CPUs to the JVM inside a container. See JDK-8216366. 41 * 42 * [1] https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu 43 * In particular: 44 * When using Docker: 45 * The spec.containers[].resources.requests.cpu is converted to its core value, which is potentially 46 * fractional, and multiplied by 1024. The greater of this number or 2 is used as the value of the 47 * --cpu-shares flag in the docker run command. 48 * [2] https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html 49 * [3] https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/docker/docker.cpp#L648 50 * https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/slave/containerizer/mesos/isolators/cgroups/constants.hpp#L30 51 */ 52 #define PER_CPU_SHARES 1024 53 54 class CgroupSubsystem: CHeapObj<mtInternal> { 55 friend class CgroupSubsystemFactory; 56 private: 57 virtual int cpu_quota(); 58 virtual int cpu_period(); 59 virtual int cpu_shares(); 60 virtual jlong memory_usage_in_bytes(); 61 virtual jlong memory_and_swap_limit_in_bytes(); 62 virtual jlong memory_soft_limit_in_bytes(); 63 virtual jlong memory_max_usage_in_bytes(); 64 virtual char * cpu_cpuset_cpus(); 65 virtual char * cpu_cpuset_memory_nodes(); 66 public: 67 jlong available_memory(); 68 int active_processor_count(int physical_proc_count); 69 void print_container_info(outputStream* st, int physical_proc_count); 70 virtual jlong memory_limit_in_bytes(); 71 virtual const char * container_type(); 72 }; 73 74 class CgroupController: CHeapObj<mtInternal> { 75 friend class CgroupSubsystemFactory; 76 public: 77 virtual char *subsystem_path(); 78 }; 79 80 class CgroupSubsystemFactory: AllStatic { 81 public: 82 static CgroupSubsystem* create(); 83 }; 84 85 class CgroupV1Controller: public CgroupController { 86 friend class CgroupSubsystemFactory; 87 private: 88 /* mountinfo contents */ 89 char *_root; 90 char *_mount_point; 91 92 /* Constructed subsystem directory */ 93 char *_path; 94 95 public: 96 CgroupV1Controller(char *root, char *mountpoint) { 97 _root = os::strdup(root); 98 _mount_point = os::strdup(mountpoint); 99 _path = NULL; 100 } 101 102 virtual void set_subsystem_path(char *cgroup_path); 103 char *subsystem_path() { return _path; } 104 }; 105 106 class CgroupV1MemoryController: public CgroupV1Controller { 107 friend class CgroupSubsystemFactory; 108 109 public: 110 bool is_hierarchical() { return _uses_mem_hierarchy; } 111 private: 112 /* Some container runtimes set limits via cgroup 113 * hierarchy. If set to true consider also memory.stat 114 * file if everything else seems unlimited */ 115 bool _uses_mem_hierarchy; 116 jlong uses_mem_hierarchy(); 117 void set_subsystem_path(char *cgroup_path); 118 void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } 119 120 public: 121 CgroupV1MemoryController(char *root, char *mountpoint) : CgroupV1Controller(root, mountpoint) { 122 _uses_mem_hierarchy = false; 123 } 124 125 }; 126 127 class CgroupV1Subsystem: CgroupSubsystem { 128 friend class CgroupSubsystemFactory; 129 130 public: 131 jlong memory_limit_in_bytes(); 132 133 private: 134 julong _unlimited_memory; 135 136 /* controllers */ 137 CgroupV1MemoryController* _memory = NULL; 138 CgroupV1Controller* _cpuset = NULL; 139 CgroupV1Controller* _cpu = NULL; 140 CgroupV1Controller* _cpuacct = NULL; 141 142 jlong memory_and_swap_limit_in_bytes(); 143 jlong memory_soft_limit_in_bytes(); 144 jlong memory_usage_in_bytes(); 145 jlong memory_max_usage_in_bytes(); 146 char * cpu_cpuset_cpus(); 147 char * cpu_cpuset_memory_nodes(); 148 149 int cpu_quota(); 150 int cpu_period(); 151 152 int cpu_shares(); 153 154 const char * container_type() { 155 return "cgroupv1"; 156 } 157 158 public: 159 CgroupV1Subsystem(CgroupV1Controller* cpuset, 160 CgroupV1Controller* cpu, 161 CgroupV1Controller* cpuacct, 162 CgroupV1MemoryController* memory) { 163 _cpuset = cpuset; 164 _cpu = cpu; 165 _cpuacct = cpuacct; 166 _memory = memory; 167 _unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size(); 168 } 169 }; 170 171 #endif // CGROUP_SUBSYSTEM_LINUX_HPP