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