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