< 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 +1,7 @@
 /*
- * 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -23,25 +23,29 @@
  * 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 = "";
 
-    private volatile long memoryMaxUsage = Long.MIN_VALUE;
-
     public CgroupV2Subsystem(CgroupSubsystemController unified) {
         this.unified = unified;
     }
 
     private long getLongVal(String file) {

@@ -61,12 +65,11 @@
         return TimeUnit.MICROSECONDS.toNanos(micros);
     }
 
     @Override
     public long[] getPerCpuUsage() {
-        // Not supported
-        return new long[0];
+        return null; // Not supported.
     }
 
     @Override
     public long getCpuUserUsage() {
         long micros = CgroupSubsystemController.getLongEntry(unified, "cpu.stat", "user_usec");

@@ -91,33 +94,33 @@
 
     private long getFromCpuMax(int tokenIdx) {
         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);
     }
 
     private long limitFromString(String strVal) {
         if (MAX_VAL.equals(strVal)) {
-            return CgroupSubsystemController.RETVAL_UNLIMITED;
+            return Metrics.LONG_RETVAL_UNLIMITED;
         }
         return Long.parseLong(strVal);
     }
 
     @Override
     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
         // a proper Cgroups v2 value. See:
         // https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller

@@ -163,20 +166,20 @@
 
     @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 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 new int[0]; // not available
+            return null; // not available
         }
         return CgroupSubsystemController.stringRangeToIntArray(effCpuSetVal);
     }
 
     @Override

@@ -189,16 +192,16 @@
         return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(unified, "cpuset.mems.effective"));
     }
 
     @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
     public long getMemoryFailCount() {
         return CgroupSubsystemController.getLongEntry(unified, "memory.events", "max");

@@ -210,100 +213,155 @@
         return limitFromString(strVal);
     }
 
     @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
     public long getMemoryAndSwapLimit() {
         String strVal = CgroupSubsystemController.getStringValue(unified, "memory.swap.max");
         return limitFromString(strVal);
     }
 
     @Override
     public long getMemoryAndSwapMaxUsage() {
-        return CgroupSubsystemController.RETVAL_NOT_SUPPORTED;
+        return Metrics.LONG_RETVAL_NOT_SUPPORTED;
     }
 
     @Override
     public long getMemoryAndSwapUsage() {
         return getLongVal("memory.swap.current");
     }
 
     @Override
-    public boolean isMemoryOOMKillEnabled() {
-        return false; // Not supported.
+    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 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<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 >