1 /* 2 * Copyright (c) 2020, Red Hat Inc. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.platform; 27 28 import java.io.IOException; 29 import java.lang.System.Logger; 30 import java.lang.System.Logger.Level; 31 import java.nio.file.Paths; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.stream.Collectors; 36 import java.util.stream.Stream; 37 38 import jdk.internal.platform.cgroupv1.CgroupV1Subsystem; 39 import jdk.internal.platform.cgroupv2.CgroupV2Subsystem; 40 import jdk.internal.platform.cgroupv2.CgroupV2SubsystemController; 41 42 class CgroupSubsystemFactory { 43 44 private static final String CPU_CTRL = "cpu"; 45 private static final String CPUACCT_CTRL = "cpuacct"; 46 private static final String CPUSET_CTRL = "cpuset"; 47 private static final String BLKIO_CTRL = "blkio"; 48 private static final String MEMORY_CTRL = "memory"; 49 50 static CgroupMetrics create() { 51 Map<String, CgroupInfo> infos = new HashMap<>(); 52 try { 53 List<String> lines = CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/cgroups")); 54 for (String line : lines) { 55 if (line.startsWith("#")) { 56 continue; 57 } 58 CgroupInfo info = CgroupInfo.fromCgroupsLine(line); 59 switch (info.getName()) { 60 case CPU_CTRL: infos.put(CPU_CTRL, info); break; 61 case CPUACCT_CTRL: infos.put(CPUACCT_CTRL, info); break; 62 case CPUSET_CTRL: infos.put(CPUSET_CTRL, info); break; 63 case MEMORY_CTRL: infos.put(MEMORY_CTRL, info); break; 64 case BLKIO_CTRL: infos.put(BLKIO_CTRL, info); break; 65 } 66 } 67 } catch (IOException e) { 68 return null; 69 } 70 71 // For cgroups v1 all controllers need to have non-zero hierarchy id 72 boolean isCgroupsV2 = true; 73 boolean anyControllersEnabled = false; 74 boolean anyCgroupsV2Controller = false; 75 boolean anyCgroupsV1Controller = false; 76 for (CgroupInfo info: infos.values()) { 77 anyCgroupsV1Controller = anyCgroupsV1Controller || info.getHierarchyId() != 0; 78 anyCgroupsV2Controller = anyCgroupsV2Controller || info.getHierarchyId() == 0; 79 isCgroupsV2 = isCgroupsV2 && info.getHierarchyId() == 0; 80 anyControllersEnabled = anyControllersEnabled || info.isEnabled(); 81 } 82 83 // If no controller is enabled, return no metrics. 84 if (!anyControllersEnabled) { 85 return null; 86 } 87 // Warn about mixed cgroups v1 and cgroups v2 controllers. The code is 88 // not ready to deal with that on a per-controller basis. Return no metrics 89 // in that case 90 if (anyCgroupsV1Controller && anyCgroupsV2Controller) { 91 Logger logger = System.getLogger("jdk.internal.platform"); 92 logger.log(Level.WARNING, "Mixed cgroupv1 and cgroupv2 not supported. Metrics disabled."); 93 return null; 94 } 95 96 if (isCgroupsV2) { 97 // read mountinfo so as to determine root mount path 98 String mountPath = null; 99 try (Stream<String> lines = 100 CgroupUtil.readFilePrivileged(Paths.get("/proc/self/mountinfo"))) { 101 102 String l = lines.filter(line -> line.contains(" - cgroup2 ")) 103 .collect(Collectors.joining()); 104 String[] tokens = l.split(" "); 105 mountPath = tokens[4]; 106 } catch (IOException e) { 107 return null; 108 } 109 String cgroupPath = null; 110 try { 111 List<String> lines = CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/self/cgroup")); 112 for (String line: lines) { 113 String[] tokens = line.split(":"); 114 if (tokens.length != 3) { 115 return null; // something is not right. 116 } 117 if (!"0".equals(tokens[0])) { 118 // hierarchy must be zero for cgroups v2 119 return null; 120 } 121 cgroupPath = tokens[2]; 122 break; 123 } 124 } catch (IOException e) { 125 return null; 126 } 127 CgroupSubsystemController unified = new CgroupV2SubsystemController( 128 mountPath, 129 cgroupPath); 130 return new CgroupMetrics(new CgroupV2Subsystem(unified)); 131 } else { 132 return new CgroupV1Metrics(CgroupV1Subsystem.getInstance()); 133 } 134 } 135 }