--- old/src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java 2020-01-09 20:39:16.066142327 +0100 +++ new/src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java 2020-01-09 20:39:15.926142180 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Red Hat Inc. + * 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 @@ -25,10 +25,16 @@ 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 { @@ -38,8 +44,6 @@ 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; } @@ -63,8 +67,7 @@ @Override public long[] getPerCpuUsage() { - // Not supported - return new long[0]; + return null; // Not supported. } @Override @@ -93,12 +96,12 @@ String cpuMaxRaw = CgroupSubsystemController.getStringValue(unified, "cpu.max"); if (cpuMaxRaw == null) { // likely file not found - return CgroupSubsystemController.RETVAL_UNLIMITED; + return Metrics.LONG_RETVAL_UNLIMITED; } // $MAX $PERIOD String[] tokens = cpuMaxRaw.split("\\s+"); if (tokens.length != 2) { - return CgroupSubsystemController.RETVAL_ERROR; + return Metrics.LONG_RETVAL_UNLIMITED; } String quota = tokens[tokenIdx]; return limitFromString(quota); @@ -106,7 +109,7 @@ private long limitFromString(String strVal) { if (MAX_VAL.equals(strVal)) { - return CgroupSubsystemController.RETVAL_UNLIMITED; + return Metrics.LONG_RETVAL_UNLIMITED; } return Long.parseLong(strVal); } @@ -115,7 +118,7 @@ public long getCpuShares() { long sharesRaw = getLongVal("cpu.weight"); if (sharesRaw == 100 || sharesRaw == 0) { - return CgroupSubsystemController.RETVAL_UNLIMITED; + return Metrics.LONG_RETVAL_UNLIMITED; } int shares = (int)sharesRaw; // CPU shares (OCI) value needs to get translated into @@ -165,7 +168,7 @@ public int[] getCpuSetCpus() { String cpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus"); if (cpuSetVal == null || EMPTY_STR.equals(cpuSetVal)) { - return new int[0]; // not available + return null; // not available } return CgroupSubsystemController.stringRangeToIntArray(cpuSetVal); } @@ -174,7 +177,7 @@ 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 null; // not available } return CgroupSubsystemController.stringRangeToIntArray(effCpuSetVal); } @@ -191,12 +194,12 @@ @Override public double getCpuSetMemoryPressure() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.DOUBLE_RETVAL_NOT_SUPPORTED; } @Override - public boolean isCpuSetMemoryPressureEnabled() { - return false; // not supported + public Boolean isCpuSetMemoryPressureEnabled() { + return Metrics.BOOL_RETVAL_NOT_SUPPORTED; } @Override @@ -212,62 +215,57 @@ @Override public long getMemoryMaxUsage() { - return memoryMaxUsage; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @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; + return getLongVal("memory.current"); } @Override public long getKernelMemoryFailCount() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override public long getKernelMemoryLimit() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override public long getKernelMemoryMaxUsage() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override public long getKernelMemoryUsage() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override public long getTcpMemoryFailCount() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override public long getTcpMemoryLimit() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override public long getTcpMemoryMaxUsage() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override public long getTcpMemoryUsage() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return CgroupSubsystemController.getLongEntry(unified, "memory.stat", "sock"); } @Override public long getMemoryAndSwapFailCount() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override @@ -278,7 +276,7 @@ @Override public long getMemoryAndSwapMaxUsage() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return Metrics.LONG_RETVAL_NOT_SUPPORTED; } @Override @@ -287,8 +285,8 @@ } @Override - public boolean isMemoryOOMKillEnabled() { - return false; // Not supported. + public Boolean isMemoryOOMKillEnabled() { + return Metrics.BOOL_RETVAL_NOT_SUPPORTED; } @Override @@ -299,11 +297,71 @@ @Override public long getBlkIOServiceCount() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return sumTokensIOStat(CgroupV2Subsystem::lineToRandWIOs); } + @Override public long getBlkIOServiced() { - return CgroupSubsystemController.RETVAL_NOT_SUPPORTED; + return sumTokensIOStat(CgroupV2Subsystem::lineToRBytesAndWBytesIO); + } + + private long sumTokensIOStat(Function 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; } }