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.nio.file.Paths; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.stream.Collectors; 34 import java.util.stream.Stream; 35 36 import jdk.internal.platform.cgroupv1.CgroupV1Subsystem; 37 import jdk.internal.platform.cgroupv2.CgroupV2Subsystem; 38 import jdk.internal.platform.cgroupv2.CgroupV2SubsystemController; 39 40 class CgroupSubsystemFactory { 41 42 private static final String CPU_CTRL = "cpu"; 43 private static final String CPUACCT_CTRL = "cpuacct"; 44 private static final String CPUSET_CTRL = "cpuset"; 45 private static final String BLKIO_CTRL = "blkio"; 46 private static final String MEMORY_CTRL = "memory"; 47 48 static CgroupMetrics create() { 49 Map<String, CgroupInfo> infos = new HashMap<>(); 50 try { 51 List<String> lines = CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/cgroups")); 52 for (String line : lines) { 53 if (line.startsWith("#")) { 54 continue; 55 } 56 CgroupInfo info = CgroupInfo.fromCgroupsLine(line); 57 switch (info.getName()) { 58 case CPU_CTRL: infos.put(CPU_CTRL, info); break; 59 case CPUACCT_CTRL: infos.put(CPUACCT_CTRL, info); break; 60 case CPUSET_CTRL: infos.put(CPUSET_CTRL, info); break; 61 case MEMORY_CTRL: infos.put(MEMORY_CTRL, info); break; 62 case BLKIO_CTRL: infos.put(BLKIO_CTRL, info); break; 63 } 64 } 65 } catch (IOException e) { 66 return null; 67 } 68 69 // For cgroups v1 all controllers need to have non-zero hierarchy id 70 boolean isCgroupsV2 = true; 71 boolean anyControllersEnabled = false; 72 boolean anyCgroupsV2Controller = false; 73 boolean anyCgroupsV1Controller = false; 74 for (CgroupInfo info: infos.values()) { 75 anyCgroupsV1Controller = anyCgroupsV1Controller || info.getHierarchyId() != 0; 76 anyCgroupsV2Controller = anyCgroupsV2Controller || info.getHierarchyId() == 0; 77 isCgroupsV2 = isCgroupsV2 && info.getHierarchyId() == 0; 78 anyControllersEnabled = anyControllersEnabled || info.isEnabled(); 79 } 80 81 // If no controller is enabled, return no metrics. 82 if (!anyControllersEnabled) { 83 return null; 84 } 85 // Warn about mixed cgroups v1 and cgroups v2 controllers. The code is 86 // not ready to deal with that on a per-controller basis. Return no metrics 87 // in that case 88 if (anyCgroupsV1Controller && anyCgroupsV2Controller) { 89 System.err.println("Warning: Mixed cgroupv1 and cgroupv2 not supported. Metrics disabled."); 90 return null; 91 } 92 93 if (isCgroupsV2) { 94 // read mountinfo so as to determine root mount path 95 String mountPath = null; 96 try (Stream<String> lines = 97 CgroupUtil.readFilePrivileged(Paths.get("/proc/self/mountinfo"))) { 98 99 String l = lines.filter(line -> line.contains(" - cgroup2 ")) 100 .collect(Collectors.joining()); 101 String[] tokens = l.split(" "); 102 mountPath = tokens[4]; 103 } catch (IOException e) { 104 return null; 105 } 106 String cgroupPath = null; 107 try { 108 List<String> lines = CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/self/cgroup")); 109 for (String line: lines) { 110 String[] tokens = line.split(":"); 111 if (tokens.length != 3) { 112 return null; // something is not right. 113 } 114 if (!Integer.valueOf(0).toString().equals(tokens[0])) { 115 // hierarchy must be zero for cgroups v2 116 return null; 117 } 118 cgroupPath = tokens[2]; 119 break; 120 } 121 } catch (IOException e) { 122 return null; 123 } 124 CgroupSubsystemController unified = new CgroupV2SubsystemController( 125 mountPath, 126 cgroupPath); 127 return new CgroupMetrics(new CgroupV2Subsystem(unified)); 128 } else { 129 return new CgroupV1Metrics(CgroupV1Subsystem.getInstance()); 130 } 131 } 132 }