< prev index next >
src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java
Print this page
@ rev 57586 : Review changes
|
o rev 57585 : 8231111: Cgroups v2: Rework Metrics in java.base so as to recognize unified hierarchy
| Reviewed-by: bobv
~
o rev 56863 : 8231111: Cgroups v2: Rework Metrics in java.base so as to recognize unified hierarchy
| Reviewed-by: bobv
~
*** 1,7 ****
/*
! * Copyright (c) 2019, Red Hat Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2020, Red Hat Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 23,47 ****
* questions.
*/
package jdk.internal.platform.cgroupv2;
import java.util.concurrent.TimeUnit;
import jdk.internal.platform.CgroupSubsystem;
import jdk.internal.platform.CgroupSubsystemController;
public class CgroupV2Subsystem implements CgroupSubsystem {
private final CgroupSubsystemController unified;
private static final String PROVIDER_NAME = "cgroupv2";
private static final int PER_CPU_SHARES = 1024;
private static final String MAX_VAL = "max";
private static final Object EMPTY_STR = "";
- private volatile long memoryMaxUsage = Long.MIN_VALUE;
-
public CgroupV2Subsystem(CgroupSubsystemController unified) {
this.unified = unified;
}
private long getLongVal(String file) {
--- 23,51 ----
* questions.
*/
package jdk.internal.platform.cgroupv2;
+ import java.io.IOException;
+ import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
+ import java.util.function.Function;
+ import java.util.stream.Collectors;
import jdk.internal.platform.CgroupSubsystem;
import jdk.internal.platform.CgroupSubsystemController;
+ import jdk.internal.platform.CgroupUtil;
+ import jdk.internal.platform.Metrics;
public class CgroupV2Subsystem implements CgroupSubsystem {
private final CgroupSubsystemController unified;
private static final String PROVIDER_NAME = "cgroupv2";
private static final int PER_CPU_SHARES = 1024;
private static final String MAX_VAL = "max";
private static final Object EMPTY_STR = "";
public CgroupV2Subsystem(CgroupSubsystemController unified) {
this.unified = unified;
}
private long getLongVal(String file) {
*** 61,72 ****
return TimeUnit.MICROSECONDS.toNanos(micros);
}
@Override
public long[] getPerCpuUsage() {
! // Not supported
! return new long[0];
}
@Override
public long getCpuUserUsage() {
long micros = CgroupSubsystemController.getLongEntry(unified, "cpu.stat", "user_usec");
--- 65,75 ----
return TimeUnit.MICROSECONDS.toNanos(micros);
}
@Override
public long[] getPerCpuUsage() {
! return null; // Not supported.
}
@Override
public long getCpuUserUsage() {
long micros = CgroupSubsystemController.getLongEntry(unified, "cpu.stat", "user_usec");
*** 91,123 ****
private long getFromCpuMax(int tokenIdx) {
String cpuMaxRaw = CgroupSubsystemController.getStringValue(unified, "cpu.max");
if (cpuMaxRaw == null) {
// likely file not found
! return CgroupSubsystemController.RETVAL_UNLIMITED;
}
// $MAX $PERIOD
String[] tokens = cpuMaxRaw.split("\\s+");
if (tokens.length != 2) {
! return CgroupSubsystemController.RETVAL_ERROR;
}
String quota = tokens[tokenIdx];
return limitFromString(quota);
}
private long limitFromString(String strVal) {
if (MAX_VAL.equals(strVal)) {
! return CgroupSubsystemController.RETVAL_UNLIMITED;
}
return Long.parseLong(strVal);
}
@Override
public long getCpuShares() {
long sharesRaw = getLongVal("cpu.weight");
if (sharesRaw == 100 || sharesRaw == 0) {
! return CgroupSubsystemController.RETVAL_UNLIMITED;
}
int shares = (int)sharesRaw;
// CPU shares (OCI) value needs to get translated into
// a proper Cgroups v2 value. See:
// https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller
--- 94,126 ----
private long getFromCpuMax(int tokenIdx) {
String cpuMaxRaw = CgroupSubsystemController.getStringValue(unified, "cpu.max");
if (cpuMaxRaw == null) {
// likely file not found
! return Metrics.LONG_RETVAL_UNLIMITED;
}
// $MAX $PERIOD
String[] tokens = cpuMaxRaw.split("\\s+");
if (tokens.length != 2) {
! return Metrics.LONG_RETVAL_UNLIMITED;
}
String quota = tokens[tokenIdx];
return limitFromString(quota);
}
private long limitFromString(String strVal) {
if (MAX_VAL.equals(strVal)) {
! return Metrics.LONG_RETVAL_UNLIMITED;
}
return Long.parseLong(strVal);
}
@Override
public long getCpuShares() {
long sharesRaw = getLongVal("cpu.weight");
if (sharesRaw == 100 || sharesRaw == 0) {
! return Metrics.LONG_RETVAL_UNLIMITED;
}
int shares = (int)sharesRaw;
// CPU shares (OCI) value needs to get translated into
// a proper Cgroups v2 value. See:
// https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller
*** 163,182 ****
@Override
public int[] getCpuSetCpus() {
String cpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus");
if (cpuSetVal == null || EMPTY_STR.equals(cpuSetVal)) {
! return new int[0]; // not available
}
return CgroupSubsystemController.stringRangeToIntArray(cpuSetVal);
}
@Override
public int[] getEffectiveCpuSetCpus() {
String effCpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus.effective");
if (effCpuSetVal == null || EMPTY_STR.equals(effCpuSetVal)) {
! return new int[0]; // not available
}
return CgroupSubsystemController.stringRangeToIntArray(effCpuSetVal);
}
@Override
--- 166,185 ----
@Override
public int[] getCpuSetCpus() {
String cpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus");
if (cpuSetVal == null || EMPTY_STR.equals(cpuSetVal)) {
! return null; // not available
}
return CgroupSubsystemController.stringRangeToIntArray(cpuSetVal);
}
@Override
public int[] getEffectiveCpuSetCpus() {
String effCpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus.effective");
if (effCpuSetVal == null || EMPTY_STR.equals(effCpuSetVal)) {
! return null; // not available
}
return CgroupSubsystemController.stringRangeToIntArray(effCpuSetVal);
}
@Override
*** 189,204 ****
return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(unified, "cpuset.mems.effective"));
}
@Override
public double getCpuSetMemoryPressure() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
! public boolean isCpuSetMemoryPressureEnabled() {
! return false; // not supported
}
@Override
public long getMemoryFailCount() {
return CgroupSubsystemController.getLongEntry(unified, "memory.events", "max");
--- 192,207 ----
return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(unified, "cpuset.mems.effective"));
}
@Override
public double getCpuSetMemoryPressure() {
! return Metrics.DOUBLE_RETVAL_NOT_SUPPORTED;
}
@Override
! public Boolean isCpuSetMemoryPressureEnabled() {
! return Metrics.BOOL_RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemoryFailCount() {
return CgroupSubsystemController.getLongEntry(unified, "memory.events", "max");
*** 210,309 ****
return limitFromString(strVal);
}
@Override
public long getMemoryMaxUsage() {
! return memoryMaxUsage;
}
@Override
public long getMemoryUsage() {
! long memUsage = getLongVal("memory.current");
! // synthesize memory max usage by piggy-backing on current usage
! if (memoryMaxUsage < memUsage) {
! memoryMaxUsage = memUsage;
! }
! return memUsage;
}
@Override
public long getKernelMemoryFailCount() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getKernelMemoryLimit() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getKernelMemoryMaxUsage() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getKernelMemoryUsage() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryFailCount() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryLimit() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryMaxUsage() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryUsage() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemoryAndSwapFailCount() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemoryAndSwapLimit() {
String strVal = CgroupSubsystemController.getStringValue(unified, "memory.swap.max");
return limitFromString(strVal);
}
@Override
public long getMemoryAndSwapMaxUsage() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemoryAndSwapUsage() {
return getLongVal("memory.swap.current");
}
@Override
! public boolean isMemoryOOMKillEnabled() {
! return false; // Not supported.
}
@Override
public long getMemorySoftLimit() {
String softLimitStr = CgroupSubsystemController.getStringValue(unified, "memory.high");
return limitFromString(softLimitStr);
}
@Override
public long getBlkIOServiceCount() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
@Override
public long getBlkIOServiced() {
! return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
}
}
--- 213,367 ----
return limitFromString(strVal);
}
@Override
public long getMemoryMaxUsage() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemoryUsage() {
! return getLongVal("memory.current");
}
@Override
public long getKernelMemoryFailCount() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getKernelMemoryLimit() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getKernelMemoryMaxUsage() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getKernelMemoryUsage() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryFailCount() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryLimit() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryMaxUsage() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getTcpMemoryUsage() {
! return CgroupSubsystemController.getLongEntry(unified, "memory.stat", "sock");
}
@Override
public long getMemoryAndSwapFailCount() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemoryAndSwapLimit() {
String strVal = CgroupSubsystemController.getStringValue(unified, "memory.swap.max");
return limitFromString(strVal);
}
@Override
public long getMemoryAndSwapMaxUsage() {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemoryAndSwapUsage() {
return getLongVal("memory.swap.current");
}
@Override
! public Boolean isMemoryOOMKillEnabled() {
! return Metrics.BOOL_RETVAL_NOT_SUPPORTED;
}
@Override
public long getMemorySoftLimit() {
String softLimitStr = CgroupSubsystemController.getStringValue(unified, "memory.high");
return limitFromString(softLimitStr);
}
@Override
public long getBlkIOServiceCount() {
! return sumTokensIOStat(CgroupV2Subsystem::lineToRandWIOs);
}
+
@Override
public long getBlkIOServiced() {
! return sumTokensIOStat(CgroupV2Subsystem::lineToRBytesAndWBytesIO);
! }
!
! private long sumTokensIOStat(Function<String, Long> mapFunc) {
! try {
! return CgroupUtil.readFilePrivileged(Paths.get(unified.path(), "io.stat"))
! .map(mapFunc)
! .collect(Collectors.summingLong(e -> e));
! } catch (IOException e) {
! return Metrics.LONG_RETVAL_NOT_SUPPORTED;
! }
! }
!
! private static String[] getRWIOMatchTokenNames() {
! return new String[] { "rios", "wios" };
! }
!
! private static String[] getRWBytesIOMatchTokenNames() {
! return new String[] { "rbytes", "wbytes" };
! }
!
! public static Long lineToRandWIOs(String line) {
! String[] matchNames = getRWIOMatchTokenNames();
! return ioStatLineToLong(line, matchNames);
! }
!
! public static Long lineToRBytesAndWBytesIO(String line) {
! String[] matchNames = getRWBytesIOMatchTokenNames();
! return ioStatLineToLong(line, matchNames);
! }
!
! private static Long ioStatLineToLong(String line, String[] matchNames) {
! if (line == null || EMPTY_STR.equals(line)) {
! return Long.valueOf(0);
! }
! String[] tokens = line.split("\\s+");
! long retval = 0;
! for (String t: tokens) {
! String[] valKeys = t.split("=");
! if (valKeys.length != 2) {
! // ignore device ids $MAJ:$MIN
! continue;
! }
! for (String match: matchNames) {
! if (match.equals(valKeys[0])) {
! retval += longOrZero(valKeys[1]);
! }
! }
! }
! return Long.valueOf(retval);
! }
!
! private static long longOrZero(String val) {
! long lVal = 0;
! try {
! lVal = Long.parseLong(val);
! } catch (NumberFormatException e) {
! // keep at 0
! }
! return lVal;
}
}
< prev index next >