8254001: [Metrics] Enhance parsing of cgroup interface files for version detection

Reviewed-by: hseigel, andrew
This commit is contained in:
Severin Gehwolf 2021-02-24 19:39:46 +00:00
parent 65492129a9
commit a50725db2a
5 changed files with 453 additions and 274 deletions

View file

@ -26,17 +26,21 @@
package jdk.internal.platform;
/**
* Data structure to hold info from /proc/self/cgroup
* Data structure to hold info from /proc/self/cgroup,
* /proc/cgroups and /proc/self/mountinfo
*
* man 7 cgroups
*
* @see CgroupSubsystemFactory
*/
class CgroupInfo {
public class CgroupInfo {
private final String name;
private final int hierarchyId;
private final boolean enabled;
private String mountPoint;
private String mountRoot;
private String cgroupPath;
private CgroupInfo(String name, int hierarchyId, boolean enabled) {
this.name = name;
@ -44,18 +48,64 @@ class CgroupInfo {
this.enabled = enabled;
}
String getName() {
public String getName() {
return name;
}
int getHierarchyId() {
public int getHierarchyId() {
return hierarchyId;
}
boolean isEnabled() {
public boolean isEnabled() {
return enabled;
}
public String getMountPoint() {
return mountPoint;
}
public void setMountPoint(String mountPoint) {
this.mountPoint = mountPoint;
}
public String getMountRoot() {
return mountRoot;
}
public void setMountRoot(String mountRoot) {
this.mountRoot = mountRoot;
}
public String getCgroupPath() {
return cgroupPath;
}
public void setCgroupPath(String cgroupPath) {
this.cgroupPath = cgroupPath;
}
/*
* Creates a CgroupInfo instance from a line in /proc/cgroups.
* Comment token (hash) is handled by the caller.
*
* Example (annotated):
*
* #subsys_name hierarchy num_cgroups enabled
* cpuset 10 1 1 (a)
* cpu 7 8 1 (b)
* [...]
*
* Line (a) would yield:
* info = new CgroupInfo("cpuset", 10, true);
* return info;
* Line (b) results in:
* info = new CgroupInfo("cpu", 7, true);
* return info;
*
*
* See CgroupSubsystemFactory.determineType()
*
*/
static CgroupInfo fromCgroupsLine(String line) {
String[] tokens = line.split("\\s+");
if (tokens.length != 4) {

View file

@ -26,13 +26,17 @@
package jdk.internal.platform;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@ -68,17 +72,19 @@ public class CgroupSubsystemFactory {
*/
private static final Pattern MOUNTINFO_PATTERN = Pattern.compile(
"^[^\\s]+\\s+[^\\s]+\\s+[^\\s]+\\s+" + // (1), (2), (3)
"[^\\s]+\\s+([^\\s]+)\\s+" + // (4), (5) - group 1: mount point
"([^\\s]+)\\s+([^\\s]+)\\s+" + // (4), (5) - group 1, 2: root, mount point
"[^-]+-\\s+" + // (6), (7), (8)
"([^\\s]+)\\s+" + // (9) - group 2: filesystem type
"([^\\s]+)\\s+" + // (9) - group 3: filesystem type
".*$"); // (10), (11)
static CgroupMetrics create() {
Optional<CgroupTypeResult> optResult = null;
try {
optResult = determineType("/proc/self/mountinfo", "/proc/cgroups");
optResult = determineType("/proc/self/mountinfo", "/proc/cgroups", "/proc/self/cgroup");
} catch (IOException e) {
return null;
} catch (UncheckedIOException e) {
return null;
}
if (optResult.isEmpty()) {
@ -100,17 +106,37 @@ public class CgroupSubsystemFactory {
return null;
}
Map<String, CgroupInfo> infos = result.getInfos();
if (result.isCgroupV2()) {
CgroupSubsystem subsystem = CgroupV2Subsystem.getInstance();
// For unified it doesn't matter which controller we pick.
CgroupInfo anyController = infos.get(MEMORY_CTRL);
CgroupSubsystem subsystem = CgroupV2Subsystem.getInstance(anyController);
return subsystem != null ? new CgroupMetrics(subsystem) : null;
} else {
CgroupV1Subsystem subsystem = CgroupV1Subsystem.getInstance();
CgroupV1Subsystem subsystem = CgroupV1Subsystem.getInstance(infos);
return subsystem != null ? new CgroupV1MetricsImpl(subsystem) : null;
}
}
public static Optional<CgroupTypeResult> determineType(String mountInfo, String cgroups) throws IOException {
Map<String, CgroupInfo> infos = new HashMap<>();
/*
* Determine the type of the cgroup system (v1 - legacy or hybrid - or, v2 - unified)
* based on three files:
*
* (1) mountInfo (i.e. /proc/self/mountinfo)
* (2) cgroups (i.e. /proc/cgroups)
* (3) selfCgroup (i.e. /proc/self/cgroup)
*
* File 'cgroups' is inspected for the hierarchy ID of the mounted cgroup pseudo
* filesystem. The hierarchy ID, in turn, helps us distinguish cgroups v2 and
* cgroup v1. For a system with zero hierarchy ID, but with >= 1 relevant cgroup
* controllers mounted in 'mountInfo' we can infer it's cgroups v2. Anything else
* will be cgroup v1 (hybrid or legacy). File 'selfCgroup' is being used for
* figuring out the mount path of the controller in the cgroup hierarchy.
*/
public static Optional<CgroupTypeResult> determineType(String mountInfo,
String cgroups,
String selfCgroup) throws IOException {
final Map<String, CgroupInfo> infos = new HashMap<>();
List<String> lines = CgroupUtil.readAllLinesPrivileged(Paths.get(cgroups));
for (String line : lines) {
if (line.startsWith("#")) {
@ -141,44 +167,187 @@ public class CgroupSubsystemFactory {
anyControllersEnabled = anyControllersEnabled || info.isEnabled();
}
// If there are no mounted, relevant cgroup controllers in mountinfo and only
// 0 hierarchy IDs in /proc/cgroups have been seen, we are on a cgroups v1 system.
// If there are no mounted, relevant cgroup controllers in 'mountinfo' and only
// 0 hierarchy IDs in file 'cgroups' have been seen, we are on a cgroups v1 system.
// However, continuing in that case does not make sense as we'd need
// information from mountinfo for the mounted controller paths which we wouldn't
// find anyway in that case.
try (Stream<String> mntInfo = CgroupUtil.readFilePrivileged(Paths.get(mountInfo))) {
boolean anyCgroupMounted = mntInfo.anyMatch(CgroupSubsystemFactory::isRelevantControllerMount);
if (!anyCgroupMounted && isCgroupsV2) {
return Optional.empty();
}
lines = CgroupUtil.readAllLinesPrivileged(Paths.get(mountInfo));
boolean anyCgroupMounted = false;
for (String line: lines) {
boolean cgroupsControllerFound = amendCgroupInfos(line, infos, isCgroupsV2);
anyCgroupMounted = anyCgroupMounted || cgroupsControllerFound;
}
CgroupTypeResult result = new CgroupTypeResult(isCgroupsV2, anyControllersEnabled, anyCgroupsV2Controller, anyCgroupsV1Controller);
if (!anyCgroupMounted) {
return Optional.empty();
}
// Map a cgroup version specific 'action' to a line in 'selfCgroup' (i.e.
// /proc/self/cgroups) , split on the ':' token, so as to set the appropriate
// path to the cgroup controller in cgroup data structures 'infos'.
// See:
// setCgroupV1Path() for the action run for cgroups v1 systems
// setCgroupV2Path() for the action run for cgroups v2 systems
try (Stream<String> selfCgroupLines =
CgroupUtil.readFilePrivileged(Paths.get(selfCgroup))) {
Consumer<String[]> action = (tokens -> setCgroupV1Path(infos, tokens));
if (isCgroupsV2) {
action = (tokens -> setCgroupV2Path(infos, tokens));
}
selfCgroupLines.map(line -> line.split(":"))
.filter(tokens -> (tokens.length >= 3))
.forEach(action);
}
CgroupTypeResult result = new CgroupTypeResult(isCgroupsV2,
anyControllersEnabled,
anyCgroupsV2Controller,
anyCgroupsV1Controller,
Collections.unmodifiableMap(infos));
return Optional.of(result);
}
private static boolean isRelevantControllerMount(String line) {
Matcher lineMatcher = MOUNTINFO_PATTERN.matcher(line.trim());
if (lineMatcher.matches()) {
String mountPoint = lineMatcher.group(1);
String fsType = lineMatcher.group(2);
if (fsType.equals("cgroup")) {
String filename = Paths.get(mountPoint).getFileName().toString();
for (String fn: filename.split(",")) {
switch (fn) {
case MEMORY_CTRL: // fall through
case CPU_CTRL:
case CPUSET_CTRL:
case CPUACCT_CTRL:
case BLKIO_CTRL:
return true;
default: break; // ignore not recognized controllers
}
}
} else if (fsType.equals("cgroup2")) {
return true;
}
}
return false;
/*
* Sets the path to the cgroup controller for cgroups v2 based on a line
* in /proc/self/cgroup file (represented as the 'tokens' array).
*
* Example:
*
* 0::/
*
* => tokens = [ "0", "", "/" ]
*/
private static void setCgroupV2Path(Map<String, CgroupInfo> infos,
String[] tokens) {
int hierarchyId = Integer.parseInt(tokens[0]);
String cgroupPath = tokens[2];
for (CgroupInfo info: infos.values()) {
assert hierarchyId == info.getHierarchyId() && hierarchyId == 0;
info.setCgroupPath(cgroupPath);
}
}
/*
* Sets the path to the cgroup controller for cgroups v1 based on a line
* in /proc/self/cgroup file (represented as the 'tokens' array).
*
* Note that multiple controllers might be joined at a single path.
*
* Example:
*
* 7:cpu,cpuacct:/system.slice/docker-74ad896fb40bbefe0f181069e4417505fffa19052098f27edf7133f31423bc0b.scope
*
* => tokens = [ "7", "cpu,cpuacct", "/system.slice/docker-74ad896fb40bbefe0f181069e4417505fffa19052098f27edf7133f31423bc0b.scope" ]
*/
private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
String[] tokens) {
String controllerName = tokens[1];
String cgroupPath = tokens[2];
if (controllerName != null && cgroupPath != null) {
for (String cName: controllerName.split(",")) {
switch (cName) {
case MEMORY_CTRL: // fall through
case CPUSET_CTRL:
case CPUACCT_CTRL:
case CPU_CTRL:
case BLKIO_CTRL:
CgroupInfo info = infos.get(cName);
info.setCgroupPath(cgroupPath);
break;
// Ignore not recognized controllers
default:
break;
}
}
}
}
/**
* Amends cgroup infos with mount path and mount root. The passed in
* 'mntInfoLine' represents a single line in, for example,
* /proc/self/mountinfo. Each line is matched with MOUNTINFO_PATTERN
* (see above), so as to extract the relevant tokens from the line.
*
* Host example cgroups v1:
*
* 44 30 0:41 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,seclabel,devices
*
* Container example cgroups v1:
*
* 1901 1894 0:37 /system.slice/docker-2291eeb92093f9d761aaf971782b575e9be56bd5930d4b5759b51017df3c1387.scope /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime master:12 - cgroup cgroup rw,seclabel,cpu,cpuacct
*
* Container example cgroups v2:
*
* 1043 1034 0:27 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup2 rw,seclabel,nsdelegate
*
*
* @return {@code true} iff a relevant controller has been found at the
* given line
*/
private static boolean amendCgroupInfos(String mntInfoLine,
Map<String, CgroupInfo> infos,
boolean isCgroupsV2) {
Matcher lineMatcher = MOUNTINFO_PATTERN.matcher(mntInfoLine.trim());
boolean cgroupv1ControllerFound = false;
boolean cgroupv2ControllerFound = false;
if (lineMatcher.matches()) {
String mountRoot = lineMatcher.group(1);
String mountPath = lineMatcher.group(2);
String fsType = lineMatcher.group(3);
if (fsType.equals("cgroup")) {
Path p = Paths.get(mountPath);
String[] controllerNames = p.getFileName().toString().split(",");
for (String controllerName: controllerNames) {
switch (controllerName) {
case MEMORY_CTRL: // fall-through
case CPU_CTRL:
case CPUACCT_CTRL:
case BLKIO_CTRL: {
CgroupInfo info = infos.get(controllerName);
assert info.getMountPoint() == null;
assert info.getMountRoot() == null;
info.setMountPoint(mountPath);
info.setMountRoot(mountRoot);
cgroupv1ControllerFound = true;
break;
}
case CPUSET_CTRL: {
CgroupInfo info = infos.get(controllerName);
if (info.getMountPoint() != null) {
// On some systems duplicate cpuset controllers get mounted in addition to
// the main cgroup controllers most likely under /sys/fs/cgroup. In that
// case pick the one under /sys/fs/cgroup and discard others.
if (!info.getMountPoint().startsWith("/sys/fs/cgroup")) {
info.setMountPoint(mountPath);
info.setMountRoot(mountRoot);
}
} else {
info.setMountPoint(mountPath);
info.setMountRoot(mountRoot);
}
cgroupv1ControllerFound = true;
break;
}
default:
// Ignore controllers which we don't recognize
break;
}
}
} else if (fsType.equals("cgroup2")) {
if (isCgroupsV2) { // will be false for hybrid
// All controllers have the same mount point and root mount
// for unified hierarchy.
for (CgroupInfo info: infos.values()) {
assert info.getMountPoint() == null;
assert info.getMountRoot() == null;
info.setMountPoint(mountPath);
info.setMountRoot(mountRoot);
}
}
cgroupv2ControllerFound = true;
}
}
return cgroupv1ControllerFound || cgroupv2ControllerFound;
}
public static final class CgroupTypeResult {
@ -186,15 +355,18 @@ public class CgroupSubsystemFactory {
private final boolean anyControllersEnabled;
private final boolean anyCgroupV2Controllers;
private final boolean anyCgroupV1Controllers;
private final Map<String, CgroupInfo> infos;
private CgroupTypeResult(boolean isCgroupV2,
boolean anyControllersEnabled,
boolean anyCgroupV2Controllers,
boolean anyCgroupV1Controllers) {
boolean anyCgroupV1Controllers,
Map<String, CgroupInfo> infos) {
this.isCgroupV2 = isCgroupV2;
this.anyControllersEnabled = anyControllersEnabled;
this.anyCgroupV1Controllers = anyCgroupV1Controllers;
this.anyCgroupV2Controllers = anyCgroupV2Controllers;
this.infos = infos;
}
public boolean isCgroupV2() {
@ -212,5 +384,9 @@ public class CgroupSubsystemFactory {
public boolean isAnyCgroupV1Controllers() {
return anyCgroupV1Controllers;
}
public Map<String, CgroupInfo> getInfos() {
return infos;
}
}
}

View file

@ -25,15 +25,11 @@
package jdk.internal.platform.cgroupv1;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
import java.util.Map;
import jdk.internal.platform.CgroupInfo;
import jdk.internal.platform.CgroupSubsystem;
import jdk.internal.platform.CgroupSubsystemController;
import jdk.internal.platform.CgroupUtil;
import jdk.internal.platform.CgroupV1Metrics;
public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
@ -42,172 +38,107 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
private CgroupV1SubsystemController cpuacct;
private CgroupV1SubsystemController cpuset;
private CgroupV1SubsystemController blkio;
private boolean activeSubSystems;
private static final CgroupV1Subsystem INSTANCE = initSubSystem();
private static volatile CgroupV1Subsystem INSTANCE;
private static final String PROVIDER_NAME = "cgroupv1";
private CgroupV1Subsystem() {
activeSubSystems = false;
}
private CgroupV1Subsystem() {}
public static CgroupV1Subsystem getInstance() {
/**
* Get a singleton instance of CgroupV1Subsystem. Initially, it creates a new
* object by retrieving the pre-parsed information from cgroup interface
* files from the provided 'infos' map.
*
* See CgroupSubsystemFactory.determineType() where the actual parsing of
* cgroup interface files happens.
*
* @return A singleton CgroupV1Subsystem instance, never null
*/
public static CgroupV1Subsystem getInstance(Map<String, CgroupInfo> infos) {
if (INSTANCE == null) {
CgroupV1Subsystem tmpSubsystem = initSubSystem(infos);
synchronized (CgroupV1Subsystem.class) {
if (INSTANCE == null) {
INSTANCE = tmpSubsystem;
}
}
}
return INSTANCE;
}
private static CgroupV1Subsystem initSubSystem() {
private static CgroupV1Subsystem initSubSystem(Map<String, CgroupInfo> infos) {
CgroupV1Subsystem subsystem = new CgroupV1Subsystem();
/**
* Find the cgroup mount points for subsystems
* by reading /proc/self/mountinfo
*
* Example for docker MemorySubSystem subsystem:
* 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/MemorySubSystem ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,MemorySubSystem
*
* Example for host:
* 34 28 0:29 / /sys/fs/cgroup/MemorySubSystem rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,MemorySubSystem
boolean anyActiveControllers = false;
/*
* Find the cgroup mount points for subsystem controllers
* by looking up relevant data in the infos map
*/
try (Stream<String> lines =
CgroupUtil.readFilePrivileged(Paths.get("/proc/self/mountinfo"))) {
lines.filter(line -> line.contains(" - cgroup "))
.map(line -> line.split(" "))
.forEach(entry -> createSubSystemController(subsystem, entry));
} catch (UncheckedIOException e) {
return null;
} catch (IOException e) {
return null;
}
/**
* Read /proc/self/cgroup and map host mount point to
* local one via /proc/self/mountinfo content above
*
* Docker example:
* 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb044
*
* Host example:
* 5:memory:/user.slice
*
* Construct a path to the process specific memory and cpuset
* cgroup directory.
*
* For a container running under Docker from memory example above
* the paths would be:
*
* /sys/fs/cgroup/memory
*
* For a Host from memory example above the path would be:
*
* /sys/fs/cgroup/memory/user.slice
*
*/
try (Stream<String> lines =
CgroupUtil.readFilePrivileged(Paths.get("/proc/self/cgroup"))) {
lines.map(line -> line.split(":"))
.filter(line -> (line.length >= 3))
.forEach(line -> setSubSystemControllerPath(subsystem, line));
} catch (UncheckedIOException e) {
return null;
} catch (IOException e) {
return null;
for (CgroupInfo info: infos.values()) {
switch (info.getName()) {
case "memory": {
if (info.getMountRoot() != null && info.getMountPoint() != null) {
CgroupV1MemorySubSystemController controller = new CgroupV1MemorySubSystemController(info.getMountRoot(), info.getMountPoint());
controller.setPath(info.getCgroupPath());
boolean isHierarchial = getHierarchical(controller);
controller.setHierarchical(isHierarchial);
boolean isSwapEnabled = getSwapEnabled(controller);
controller.setSwapEnabled(isSwapEnabled);
subsystem.setMemorySubSystem(controller);
anyActiveControllers = true;
}
break;
}
case "cpuset": {
if (info.getMountRoot() != null && info.getMountPoint() != null) {
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
controller.setPath(info.getCgroupPath());
subsystem.setCpuSetController(controller);
anyActiveControllers = true;
}
break;
}
case "cpuacct": {
if (info.getMountRoot() != null && info.getMountPoint() != null) {
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
controller.setPath(info.getCgroupPath());
subsystem.setCpuAcctController(controller);
anyActiveControllers = true;
}
break;
}
case "cpu": {
if (info.getMountRoot() != null && info.getMountPoint() != null) {
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
controller.setPath(info.getCgroupPath());
subsystem.setCpuController(controller);
anyActiveControllers = true;
}
break;
}
case "blkio": {
if (info.getMountRoot() != null && info.getMountPoint() != null) {
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
controller.setPath(info.getCgroupPath());
subsystem.setBlkIOController(controller);
anyActiveControllers = true;
}
break;
}
default:
throw new AssertionError("Unrecognized controller in infos: " + info.getName());
}
}
// Return Metrics object if we found any subsystems.
if (subsystem.activeSubSystems()) {
if (anyActiveControllers) {
return subsystem;
}
return null;
}
/**
* createSubSystem objects and initialize mount points
*/
private static void createSubSystemController(CgroupV1Subsystem subsystem, String[] mountentry) {
if (mountentry.length < 5) return;
Path p = Paths.get(mountentry[4]);
String[] subsystemNames = p.getFileName().toString().split(",");
for (String subsystemName: subsystemNames) {
switch (subsystemName) {
case "memory":
subsystem.setMemorySubSystem(new CgroupV1MemorySubSystemController(mountentry[3], mountentry[4]));
break;
case "cpuset":
subsystem.setCpuSetController(new CgroupV1SubsystemController(mountentry[3], mountentry[4]));
break;
case "cpuacct":
subsystem.setCpuAcctController(new CgroupV1SubsystemController(mountentry[3], mountentry[4]));
break;
case "cpu":
subsystem.setCpuController(new CgroupV1SubsystemController(mountentry[3], mountentry[4]));
break;
case "blkio":
subsystem.setBlkIOController(new CgroupV1SubsystemController(mountentry[3], mountentry[4]));
break;
default:
// Ignore subsystems that we don't support
break;
}
}
}
/**
* setSubSystemPath based on the contents of /proc/self/cgroup
*/
private static void setSubSystemControllerPath(CgroupV1Subsystem subsystem, String[] entry) {
String controllerName = entry[1];
String base = entry[2];
if (controllerName != null && base != null) {
for (String cName: controllerName.split(",")) {
switch (cName) {
case "memory":
setPath(subsystem, subsystem.memoryController(), base);
break;
case "cpuset":
setPath(subsystem, subsystem.cpuSetController(), base);
break;
case "cpu":
setPath(subsystem, subsystem.cpuController(), base);
break;
case "cpuacct":
setPath(subsystem, subsystem.cpuAcctController(), base);
break;
case "blkio":
setPath(subsystem, subsystem.blkIOController(), base);
break;
// Ignore subsystems that we don't support
default:
break;
}
}
}
}
private static void setPath(CgroupV1Subsystem subsystem, CgroupV1SubsystemController controller, String base) {
if (controller != null) {
controller.setPath(base);
if (controller instanceof CgroupV1MemorySubSystemController) {
CgroupV1MemorySubSystemController memorySubSystem = (CgroupV1MemorySubSystemController)controller;
boolean isHierarchial = getHierarchical(memorySubSystem);
memorySubSystem.setHierarchical(isHierarchial);
boolean isSwapEnabled = getSwapEnabled(memorySubSystem);
memorySubSystem.setSwapEnabled(isSwapEnabled);
}
subsystem.setActiveSubSystems();
}
}
private static boolean getSwapEnabled(CgroupV1MemorySubSystemController controller) {
long retval = getLongValue(controller, "memory.memsw.limit_in_bytes");
return retval > 0;
@ -219,14 +150,6 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
return hierarchical > 0;
}
private void setActiveSubSystems() {
activeSubSystems = true;
}
private boolean activeSubSystems() {
return activeSubSystems;
}
private void setMemorySubSystem(CgroupV1MemorySubSystemController memory) {
this.memory = memory;
}
@ -247,26 +170,6 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
this.blkio = blkio;
}
private CgroupV1SubsystemController memoryController() {
return memory;
}
private CgroupV1SubsystemController cpuController() {
return cpu;
}
private CgroupV1SubsystemController cpuAcctController() {
return cpuacct;
}
private CgroupV1SubsystemController cpuSetController() {
return cpuset;
}
private CgroupV1SubsystemController blkIOController() {
return blkio;
}
private static long getLongValue(CgroupSubsystemController controller,
String parm) {
return CgroupSubsystemController.getLongValue(controller,

View file

@ -28,19 +28,18 @@ package jdk.internal.platform.cgroupv2;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.platform.CgroupInfo;
import jdk.internal.platform.CgroupSubsystem;
import jdk.internal.platform.CgroupSubsystemController;
import jdk.internal.platform.CgroupUtil;
public class CgroupV2Subsystem implements CgroupSubsystem {
private static final CgroupV2Subsystem INSTANCE = initSubsystem();
private static volatile CgroupV2Subsystem INSTANCE;
private static final long[] LONG_ARRAY_NOT_SUPPORTED = null;
private static final int[] INT_ARRAY_UNAVAILABLE = null;
private final CgroupSubsystemController unified;
@ -65,48 +64,29 @@ public class CgroupV2Subsystem implements CgroupSubsystem {
return getLongVal(file, CgroupSubsystem.LONG_RETVAL_UNLIMITED);
}
private static CgroupV2Subsystem initSubsystem() {
// read mountinfo so as to determine root mount path
String mountPath = null;
try (Stream<String> lines =
CgroupUtil.readFilePrivileged(Paths.get("/proc/self/mountinfo"))) {
String l = lines.filter(line -> line.contains(" - cgroup2 "))
.collect(Collectors.joining());
String[] tokens = l.split(" ");
mountPath = tokens[4];
} catch (UncheckedIOException e) {
return null;
} catch (IOException e) {
return null;
}
String cgroupPath = null;
try {
List<String> lines = CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/self/cgroup"));
for (String line: lines) {
String[] tokens = line.split(":");
if (tokens.length != 3) {
return null; // something is not right.
/**
* Get the singleton instance of a cgroups v2 subsystem. On initialization,
* a new object from the given cgroup information 'anyController' is being
* created. Note that the cgroup information has been parsed from cgroup
* interface files ahead of time.
*
* See CgroupSubsystemFactory.determineType() for the cgroup interface
* files parsing logic.
*
* @return A singleton CgroupSubsystem instance, never null.
*/
public static CgroupSubsystem getInstance(CgroupInfo anyController) {
if (INSTANCE == null) {
CgroupSubsystemController unified = new CgroupV2SubsystemController(
anyController.getMountPoint(),
anyController.getCgroupPath());
CgroupV2Subsystem tmpCgroupSystem = new CgroupV2Subsystem(unified);
synchronized (CgroupV2Subsystem.class) {
if (INSTANCE == null) {
INSTANCE = tmpCgroupSystem;
}
if (!"0".equals(tokens[0])) {
// hierarchy must be zero for cgroups v2
return null;
}
cgroupPath = tokens[2];
break;
}
} catch (UncheckedIOException e) {
return null;
} catch (IOException e) {
return null;
}
CgroupSubsystemController unified = new CgroupV2SubsystemController(
mountPath,
cgroupPath);
return new CgroupV2Subsystem(unified);
}
public static CgroupSubsystem getInstance() {
return INSTANCE;
}