1 /*
   2  * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
   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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.test.lib.containers.cgroup;
  25 
  26 import java.io.File;
  27 import java.io.FileNotFoundException;
  28 import java.io.IOException;
  29 import java.nio.file.Files;
  30 import java.nio.file.Path;
  31 import java.nio.file.Paths;
  32 import java.util.Arrays;
  33 import java.util.HashMap;
  34 import java.util.Map;
  35 import java.util.Scanner;
  36 import java.util.Set;
  37 import java.util.stream.Collectors;
  38 import java.util.stream.LongStream;
  39 import java.util.stream.Stream;
  40 
  41 import jdk.internal.platform.Metrics;
  42 import jdk.internal.platform.MetricsCgroupV1;
  43 
  44 public class MetricsTesterCgroupV1 implements CgroupMetricsTester {
  45 
  46     private static long unlimited_minimum = 0x7FFFFFFFFF000000L;
  47     long startSysVal;
  48     long startUserVal;
  49     long startUsage;
  50     long startPerCpu[];
  51 
  52     enum Controller {
  53         MEMORY("memory"),
  54         CPUSET("cpuset"),
  55         CPU("cpu"),
  56         CPUACCT("cpuacct"),
  57         BLKIO("blkio");
  58 
  59         private String value;
  60 
  61         Controller(String value) {
  62             this.value = value;
  63         }
  64 
  65         public String value() {
  66             return value;
  67         }
  68     }
  69 
  70     private static final Set<String> allowedSubSystems =
  71             Stream.of(Controller.values()).map(Controller::value).collect(Collectors.toSet());
  72 
  73     private static final Map<String, String[]> subSystemPaths = new HashMap<>();
  74 
  75     private static void setPath(String[] line) {
  76         String cgroupPath = line[2];
  77         String[] subSystems = line[1].split(",");
  78 
  79         for (String subSystem : subSystems) {
  80             if (allowedSubSystems.contains(subSystem)) {
  81                 String[] paths = subSystemPaths.get(subSystem);
  82                 String finalPath = "";
  83                 String root = paths[0];
  84                 String mountPoint = paths[1];
  85                 if (root != null && cgroupPath != null) {
  86                     if (root.equals("/")) {
  87                         if (!cgroupPath.equals("/")) {
  88                             finalPath = mountPoint + cgroupPath;
  89                         } else {
  90                             finalPath = mountPoint;
  91                         }
  92                     } else {
  93                         if (root.equals(cgroupPath)) {
  94                             finalPath = mountPoint;
  95                         } else {
  96                             if (cgroupPath.startsWith(root)) {
  97                                 if (cgroupPath.length() > root.length()) {
  98                                     String cgroupSubstr = cgroupPath.substring(root.length());
  99                                     finalPath = mountPoint + cgroupSubstr;
 100                                 }
 101                             }
 102                         }
 103                     }
 104                 }
 105                 subSystemPaths.put(subSystem, new String[]{finalPath, mountPoint});
 106             }
 107         }
 108     }
 109 
 110     private static void createSubsystems(String[] line) {
 111         if (line.length < 5) return;
 112         Path p = Paths.get(line[4]);
 113         String subsystemName = p.getFileName().toString();
 114         if (subsystemName != null) {
 115             for (String subSystem : subsystemName.split(",")) {
 116                 if (allowedSubSystems.contains(subSystem)) {
 117                     subSystemPaths.put(subSystem, new String[]{line[3], line[4]});
 118                 }
 119             }
 120         }
 121     }
 122 
 123     public void setup() {
 124         Metrics metrics = Metrics.systemMetrics();
 125         // Initialize CPU usage metrics before we do any testing.
 126         startSysVal = metrics.getCpuSystemUsage();
 127         startUserVal = metrics.getCpuUserUsage();
 128         startUsage = metrics.getCpuUsage();
 129         startPerCpu = metrics.getPerCpuUsage();
 130         if (startPerCpu == null) {
 131             startPerCpu = new long[0];
 132         }
 133 
 134         try {
 135             Stream<String> lines = Files.lines(Paths.get("/proc/self/mountinfo"));
 136             lines.filter(line -> line.contains(" - cgroup cgroup "))
 137                     .map(line -> line.split(" "))
 138                     .forEach(MetricsTesterCgroupV1::createSubsystems);
 139             lines.close();
 140 
 141             lines = Files.lines(Paths.get("/proc/self/cgroup"));
 142             lines.map(line -> line.split(":"))
 143                     .filter(line -> (line.length >= 3))
 144                     .forEach(MetricsTesterCgroupV1::setPath);
 145             lines.close();
 146         } catch (IOException e) {
 147         }
 148     }
 149 
 150     private static String getFileContents(Controller subSystem, String fileName) {
 151         String fname = subSystemPaths.get(subSystem.value())[0] + File.separator + fileName;
 152         try {
 153             return new Scanner(new File(fname)).useDelimiter("\\Z").next();
 154         } catch (FileNotFoundException e) {
 155             System.err.println("Unable to open : " + fname);
 156             return null;
 157         }
 158     }
 159 
 160     private static long getLongValueFromFile(Controller subSystem, String fileName) {
 161         String data = getFileContents(subSystem, fileName);
 162         return (data == null || data.isEmpty()) ? 0L : convertStringToLong(data);
 163     }
 164 
 165     private static long convertStringToLong(String strval) {
 166         return CgroupMetricsTester.convertStringToLong(strval, Long.MAX_VALUE);
 167     }
 168 
 169     private static long getLongValueFromFile(Controller subSystem, String metric, String subMetric) {
 170         String stats = getFileContents(subSystem, metric);
 171         String[] tokens = stats.split("[\\r\\n]+");
 172         for (int i = 0; i < tokens.length; i++) {
 173             if (tokens[i].startsWith(subMetric)) {
 174                 String strval = tokens[i].split("\\s+")[1];
 175                 return convertStringToLong(strval);
 176             }
 177         }
 178         return 0L;
 179     }
 180 
 181     private static double getDoubleValueFromFile(Controller subSystem, String fileName) {
 182         String data = getFileContents(subSystem, fileName);
 183         return data.isEmpty() ? 0.0 : Double.parseDouble(data);
 184     }
 185 
 186     private static void fail(Controller system, String metric, long oldVal, long testVal) {
 187         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 188     }
 189 
 190     private static void fail(Controller system, String metric, String oldVal, String testVal) {
 191         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 192     }
 193 
 194     private static void fail(Controller system, String metric, double oldVal, double testVal) {
 195         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 196     }
 197 
 198     private static void fail(Controller system, String metric, boolean oldVal, boolean testVal) {
 199         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 200     }
 201 
 202     private static void warn(Controller system, String metric, long oldVal, long testVal) {
 203         CgroupMetricsTester.warn(system.value, metric, oldVal, testVal);
 204     }
 205 
 206     public void testMemorySubsystem() {
 207         MetricsCgroupV1 metrics = (MetricsCgroupV1)Metrics.systemMetrics();
 208 
 209         // User Memory
 210         long oldVal = metrics.getMemoryFailCount();
 211         long newVal = getLongValueFromFile(Controller.MEMORY, "memory.failcnt");
 212         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 213             fail(Controller.MEMORY, "memory.failcnt", oldVal, newVal);
 214         }
 215 
 216         oldVal = metrics.getMemoryLimit();
 217         newVal = getLongValueFromFile(Controller.MEMORY, "memory.limit_in_bytes");
 218         newVal = newVal > unlimited_minimum ? -1L : newVal;
 219         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 220             fail(Controller.MEMORY, "memory.limit_in_bytes", oldVal, newVal);
 221         }
 222 
 223         oldVal = metrics.getMemoryMaxUsage();
 224         newVal = getLongValueFromFile(Controller.MEMORY, "memory.max_usage_in_bytes");
 225         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 226             fail(Controller.MEMORY, "memory.max_usage_in_bytes", oldVal, newVal);
 227         }
 228 
 229         oldVal = metrics.getMemoryUsage();
 230         newVal = getLongValueFromFile(Controller.MEMORY, "memory.usage_in_bytes");
 231         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 232             fail(Controller.MEMORY, "memory.usage_in_bytes", oldVal, newVal);
 233         }
 234 
 235         // Kernel memory
 236         oldVal = metrics.getKernelMemoryFailCount();
 237         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.failcnt");
 238         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 239             fail(Controller.MEMORY, "memory.kmem.failcnt", oldVal, newVal);
 240         }
 241 
 242         oldVal = metrics.getKernelMemoryLimit();
 243         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.limit_in_bytes");
 244         newVal = newVal > unlimited_minimum ? -1L : newVal;
 245         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 246             fail(Controller.MEMORY, "memory.kmem.limit_in_bytes", oldVal, newVal);
 247         }
 248 
 249         oldVal = metrics.getKernelMemoryMaxUsage();
 250         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.max_usage_in_bytes");
 251         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 252             fail(Controller.MEMORY, "memory.kmem.max_usage_in_bytes", oldVal, newVal);
 253         }
 254 
 255         oldVal = metrics.getKernelMemoryUsage();
 256         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.usage_in_bytes");
 257         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 258             fail(Controller.MEMORY, "memory.kmem.usage_in_bytes", oldVal, newVal);
 259         }
 260 
 261         //TCP Memory
 262         oldVal = metrics.getTcpMemoryFailCount();
 263         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.failcnt");
 264         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 265             fail(Controller.MEMORY, "memory.kmem.tcp.failcnt", oldVal, newVal);
 266         }
 267 
 268         oldVal = metrics.getTcpMemoryLimit();
 269         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes");
 270         newVal = newVal > unlimited_minimum ? -1L : newVal;
 271         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 272             fail(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes", oldVal, newVal);
 273         }
 274 
 275         oldVal = metrics.getTcpMemoryMaxUsage();
 276         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes");
 277         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 278             fail(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes", oldVal, newVal);
 279         }
 280 
 281         oldVal = metrics.getTcpMemoryUsage();
 282         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes");
 283         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 284             fail(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes", oldVal, newVal);
 285         }
 286 
 287         //  Memory and Swap
 288         oldVal = metrics.getMemoryAndSwapFailCount();
 289         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.failcnt");
 290         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 291             fail(Controller.MEMORY, "memory.memsw.failcnt", oldVal, newVal);
 292         }
 293 
 294         oldVal = metrics.getMemoryAndSwapLimit();
 295         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.limit_in_bytes");
 296         newVal = newVal > unlimited_minimum ? -1L : newVal;
 297         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 298             fail(Controller.MEMORY, "memory.memsw.limit_in_bytes", oldVal, newVal);
 299         }
 300 
 301         oldVal = metrics.getMemoryAndSwapMaxUsage();
 302         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.max_usage_in_bytes");
 303         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 304             fail(Controller.MEMORY, "memory.memsw.max_usage_in_bytes", oldVal, newVal);
 305         }
 306 
 307         oldVal = metrics.getMemoryAndSwapUsage();
 308         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.usage_in_bytes");
 309         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 310             fail(Controller.MEMORY, "memory.memsw.usage_in_bytes", oldVal, newVal);
 311         }
 312 
 313         oldVal = metrics.getMemorySoftLimit();
 314         newVal = getLongValueFromFile(Controller.MEMORY, "memory.soft_limit_in_bytes");
 315         newVal = newVal > unlimited_minimum ? -1L : newVal;
 316         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 317             fail(Controller.MEMORY, "memory.soft_limit_in_bytes", oldVal, newVal);
 318         }
 319 
 320         boolean oomKillEnabled = metrics.isMemoryOOMKillEnabled();
 321         boolean newOomKillEnabled = getLongValueFromFile(Controller.MEMORY,
 322                 "memory.oom_control", "oom_kill_disable") == 0L ? true : false;
 323         if (oomKillEnabled != newOomKillEnabled) {
 324             throw new RuntimeException("Test failed for - " + Controller.MEMORY.value + ":"
 325                     + "memory.oom_control:oom_kill_disable" + ", expected ["
 326                     + oomKillEnabled + "], got [" + newOomKillEnabled + "]");
 327         }
 328     }
 329 
 330     public void testCpuAccounting() {
 331         MetricsCgroupV1 metrics = (MetricsCgroupV1)Metrics.systemMetrics();
 332         long oldVal = metrics.getCpuUsage();
 333         long newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.usage");
 334 
 335         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 336             warn(Controller.CPUACCT, "cpuacct.usage", oldVal, newVal);
 337         }
 338 
 339         String newValsStr = getFileContents(Controller.CPUACCT, "cpuacct.usage_percpu");
 340         Long[] newVals = new Long[0];
 341         if (newValsStr != null) {
 342             newVals = Stream.of(newValsStr
 343                 .split("\\s+"))
 344                 .map(Long::parseLong)
 345                 .toArray(Long[]::new);
 346         }
 347         long[] oldValsPrim = metrics.getPerCpuUsage();
 348         Long[] oldVals = LongStream.of(oldValsPrim == null ? new long[0] : oldValsPrim)
 349                                     .boxed().toArray(Long[]::new);
 350         for (int i = 0; i < oldVals.length; i++) {
 351             if (!CgroupMetricsTester.compareWithErrorMargin(oldVals[i], newVals[i])) {
 352                 warn(Controller.CPUACCT, "cpuacct.usage_percpu", oldVals[i], newVals[i]);
 353             }
 354         }
 355 
 356         oldVal = metrics.getCpuUserUsage();
 357         newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "user");
 358         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 359             warn(Controller.CPUACCT, "cpuacct.usage - user", oldVal, newVal);
 360         }
 361 
 362         oldVal = metrics.getCpuSystemUsage();
 363         newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "system");
 364         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 365             warn(Controller.CPUACCT, "cpuacct.usage - system", oldVal, newVal);
 366         }
 367     }
 368 
 369     public void testCpuSchedulingMetrics() {
 370         MetricsCgroupV1 metrics = (MetricsCgroupV1)Metrics.systemMetrics();
 371         long oldVal = metrics.getCpuPeriod();
 372         long newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.cfs_period_us");
 373         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 374             fail(Controller.CPUACCT, "cpu.cfs_period_us", oldVal, newVal);
 375         }
 376 
 377         oldVal = metrics.getCpuQuota();
 378         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.cfs_quota_us");
 379         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 380             fail(Controller.CPUACCT, "cpu.cfs_quota_us", oldVal, newVal);
 381         }
 382 
 383         oldVal = metrics.getCpuShares();
 384         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.shares");
 385         if (newVal == 0 || newVal == 1024) newVal = -1;
 386         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 387             fail(Controller.CPUACCT, "cpu.shares", oldVal, newVal);
 388         }
 389 
 390         oldVal = metrics.getCpuNumPeriods();
 391         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_periods");
 392         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 393             fail(Controller.CPUACCT, "cpu.stat - nr_periods", oldVal, newVal);
 394         }
 395 
 396         oldVal = metrics.getCpuNumThrottled();
 397         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_throttled");
 398         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 399             fail(Controller.CPUACCT, "cpu.stat - nr_throttled", oldVal, newVal);
 400         }
 401 
 402         oldVal = metrics.getCpuThrottledTime();
 403         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "throttled_time");
 404         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 405             fail(Controller.CPUACCT, "cpu.stat - throttled_time", oldVal, newVal);
 406         }
 407     }
 408 
 409     public void testCpuSets() {
 410         MetricsCgroupV1 metrics = (MetricsCgroupV1)Metrics.systemMetrics();
 411         Integer[] oldVal = Arrays.stream(metrics.getCpuSetCpus()).boxed().toArray(Integer[]::new);
 412         Arrays.sort(oldVal);
 413 
 414         String cpusstr = getFileContents(Controller.CPUSET, "cpuset.cpus");
 415         // Parse range string in the format 1,2-6,7
 416         Integer[] newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 417         Arrays.sort(newVal);
 418         if (Arrays.compare(oldVal, newVal) != 0) {
 419             fail(Controller.CPUSET, "cpuset.cpus", Arrays.toString(oldVal),
 420                 Arrays.toString(newVal));
 421         }
 422 
 423         int [] cpuSets = metrics.getEffectiveCpuSetCpus();
 424 
 425         // Skip this test if this metric is not supported on this platform
 426         if (cpuSets.length != 0) {
 427             oldVal = Arrays.stream(cpuSets).boxed().toArray(Integer[]::new);
 428             Arrays.sort(oldVal);
 429             cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_cpus");
 430             newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 431             Arrays.sort(newVal);
 432             if (Arrays.compare(oldVal, newVal) != 0) {
 433                 fail(Controller.CPUSET, "cpuset.effective_cpus", Arrays.toString(oldVal),
 434                         Arrays.toString(newVal));
 435             }
 436         }
 437 
 438         oldVal = Arrays.stream(metrics.getCpuSetMems()).boxed().toArray(Integer[]::new);
 439         Arrays.sort(oldVal);
 440         cpusstr = getFileContents(Controller.CPUSET, "cpuset.mems");
 441         newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 442         Arrays.sort(newVal);
 443         if (Arrays.compare(oldVal, newVal) != 0) {
 444             fail(Controller.CPUSET, "cpuset.mems", Arrays.toString(oldVal),
 445                     Arrays.toString(newVal));
 446         }
 447 
 448         int [] cpuSetMems = metrics.getEffectiveCpuSetMems();
 449 
 450         // Skip this test if this metric is not supported on this platform
 451         if (cpuSetMems.length != 0) {
 452             oldVal = Arrays.stream(cpuSetMems).boxed().toArray(Integer[]::new);
 453             Arrays.sort(oldVal);
 454             cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_mems");
 455             newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 456             Arrays.sort(newVal);
 457             if (Arrays.compare(oldVal, newVal) != 0) {
 458                 fail(Controller.CPUSET, "cpuset.effective_mems", Arrays.toString(oldVal),
 459                         Arrays.toString(newVal));
 460             }
 461         }
 462 
 463         double oldValue = metrics.getCpuSetMemoryPressure();
 464         double newValue = getDoubleValueFromFile(Controller.CPUSET, "cpuset.memory_pressure");
 465         if (!CgroupMetricsTester.compareWithErrorMargin(oldValue, newValue)) {
 466             fail(Controller.CPUSET, "cpuset.memory_pressure", oldValue, newValue);
 467         }
 468 
 469         boolean oldV = metrics.isCpuSetMemoryPressureEnabled();
 470         boolean newV = getLongValueFromFile(Controller.CPUSET,
 471                 "cpuset.memory_pressure_enabled") == 1 ? true : false;
 472         if (oldV != newV) {
 473             fail(Controller.CPUSET, "cpuset.memory_pressure_enabled", oldV, newV);
 474         }
 475     }
 476 
 477     private void testBlkIO() {
 478         MetricsCgroupV1 metrics = (MetricsCgroupV1)Metrics.systemMetrics();
 479             long oldVal = metrics.getBlkIOServiceCount();
 480         long newVal = getLongValueFromFile(Controller.BLKIO,
 481                 "blkio.throttle.io_service_bytes", "Total");
 482         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 483             fail(Controller.BLKIO, "blkio.throttle.io_service_bytes - Total",
 484                     oldVal, newVal);
 485         }
 486 
 487         oldVal = metrics.getBlkIOServiced();
 488         newVal = getLongValueFromFile(Controller.BLKIO, "blkio.throttle.io_serviced", "Total");
 489         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 490             fail(Controller.BLKIO, "blkio.throttle.io_serviced - Total", oldVal, newVal);
 491         }
 492     }
 493 
 494     public void testCpuConsumption() throws IOException, InterruptedException {
 495         MetricsCgroupV1 metrics = (MetricsCgroupV1)Metrics.systemMetrics();
 496         // make system call
 497         long newSysVal = metrics.getCpuSystemUsage();
 498         long newUserVal = metrics.getCpuUserUsage();
 499         long newUsage = metrics.getCpuUsage();
 500         long[] newPerCpu = metrics.getPerCpuUsage();
 501         if (newPerCpu == null) {
 502             newPerCpu = new long[0];
 503         }
 504 
 505         // system/user CPU usage counters may be slowly increasing.
 506         // allow for equal values for a pass
 507         if (newSysVal < startSysVal) {
 508             fail(Controller.CPU, "getCpuSystemUsage", newSysVal, startSysVal);
 509         }
 510 
 511         // system/user CPU usage counters may be slowly increasing.
 512         // allow for equal values for a pass
 513         if (newUserVal < startUserVal) {
 514             fail(Controller.CPU, "getCpuUserUsage", newUserVal, startUserVal);
 515         }
 516 
 517         if (newUsage <= startUsage) {
 518             fail(Controller.CPU, "getCpuUsage", newUsage, startUsage);
 519         }
 520 
 521         boolean success = false;
 522         for (int i = 0; i < startPerCpu.length; i++) {
 523             if (newPerCpu[i] > startPerCpu[i]) {
 524                 success = true;
 525                 break;
 526             }
 527         }
 528 
 529         if(!success) fail(Controller.CPU, "getPerCpuUsage", Arrays.toString(newPerCpu),
 530                 Arrays.toString(startPerCpu));
 531     }
 532 
 533     public void testMemoryUsage() throws Exception {
 534         MetricsCgroupV1 metrics = (MetricsCgroupV1)Metrics.systemMetrics();
 535         long memoryMaxUsage = metrics.getMemoryMaxUsage();
 536         long memoryUsage = metrics.getMemoryUsage();
 537         long newMemoryMaxUsage = 0, newMemoryUsage = 0;
 538 
 539         // allocate memory in a loop and check more than once for new values
 540         // otherwise we might see seldom the effect of decreasing new memory values
 541         // e.g. because the system could free up memory
 542         byte[][] bytes = new byte[32][];
 543         for (int i = 0; i < 32; i++) {
 544             bytes[i] = new byte[8*1024*1024];
 545             newMemoryUsage = metrics.getMemoryUsage();
 546             if (newMemoryUsage > memoryUsage) {
 547                 break;
 548             }
 549         }
 550         newMemoryMaxUsage = metrics.getMemoryMaxUsage();
 551 
 552         if (newMemoryMaxUsage < memoryMaxUsage) {
 553             fail(Controller.MEMORY, "getMemoryMaxUsage", memoryMaxUsage,
 554                     newMemoryMaxUsage);
 555         }
 556 
 557         if (newMemoryUsage < memoryUsage) {
 558             fail(Controller.MEMORY, "getMemoryUsage", memoryUsage, newMemoryUsage);
 559         }
 560     }
 561 
 562     @Override
 563     public void testMisc() {
 564         testBlkIO();
 565     }
 566 }