< prev index next >

test/lib/jdk/test/lib/containers/cgroup/MetricsTesterCgroupV1.java

Print this page
@  rev 58200 : 8240189: [TESTBUG] Some cgroup tests are failing after JDK-8231111
|  Reviewed-by: mbaesken
~


  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.CgroupV1Metrics;


  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() {


 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         CgroupV1Metrics metrics = (CgroupV1Metrics)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         CgroupV1Metrics metrics = (CgroupV1Metrics)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         CgroupV1Metrics metrics = (CgroupV1Metrics)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);


 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         CgroupV1Metrics metrics = (CgroupV1Metrics)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         CgroupV1Metrics metrics = (CgroupV1Metrics)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         CgroupV1Metrics metrics = (CgroupV1Metrics)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         CgroupV1Metrics metrics = (CgroupV1Metrics)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();


  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.CgroupSubsystem;
  42 import jdk.internal.platform.CgroupV1Metrics;
  43 import jdk.internal.platform.Metrics;
  44 import jdk.test.lib.Asserts;
  45 
  46 public class MetricsTesterCgroupV1 implements CgroupMetricsTester {
  47 
  48     // Aliased for readability
  49     private static final long RETVAL_UNAVAILABLE = CgroupSubsystem.LONG_RETVAL_UNLIMITED;
  50     private static long unlimited_minimum = 0x7FFFFFFFFF000000L;
  51     long startSysVal;
  52     long startUserVal;
  53     long startUsage;
  54     long startPerCpu[];
  55 
  56     enum Controller {
  57         MEMORY("memory"),
  58         CPUSET("cpuset"),
  59         CPU("cpu"),
  60         CPUACCT("cpuacct"),
  61         BLKIO("blkio");
  62 
  63         private String value;
  64 
  65         Controller(String value) {
  66             this.value = value;
  67         }
  68 
  69         public String value() {


 114     private static void createSubsystems(String[] line) {
 115         if (line.length < 5) return;
 116         Path p = Paths.get(line[4]);
 117         String subsystemName = p.getFileName().toString();
 118         if (subsystemName != null) {
 119             for (String subSystem : subsystemName.split(",")) {
 120                 if (allowedSubSystems.contains(subSystem)) {
 121                     subSystemPaths.put(subSystem, new String[]{line[3], line[4]});
 122                 }
 123             }
 124         }
 125     }
 126 
 127     public void setup() {
 128         Metrics metrics = Metrics.systemMetrics();
 129         // Initialize CPU usage metrics before we do any testing.
 130         startSysVal = metrics.getCpuSystemUsage();
 131         startUserVal = metrics.getCpuUserUsage();
 132         startUsage = metrics.getCpuUsage();
 133         startPerCpu = metrics.getPerCpuUsage();



 134 
 135         try {
 136             Stream<String> lines = Files.lines(Paths.get("/proc/self/mountinfo"));
 137             lines.filter(line -> line.contains(" - cgroup cgroup "))
 138                     .map(line -> line.split(" "))
 139                     .forEach(MetricsTesterCgroupV1::createSubsystems);
 140             lines.close();
 141 
 142             lines = Files.lines(Paths.get("/proc/self/cgroup"));
 143             lines.map(line -> line.split(":"))
 144                     .filter(line -> (line.length >= 3))
 145                     .forEach(MetricsTesterCgroupV1::setPath);
 146             lines.close();
 147         } catch (IOException e) {
 148         }
 149     }
 150 
 151     private static String getFileContents(Controller subSystem, String fileName) {
 152         String fname = subSystemPaths.get(subSystem.value())[0] + File.separator + fileName;
 153         try {
 154             return new Scanner(new File(fname)).useDelimiter("\\Z").next();
 155         } catch (FileNotFoundException e) {
 156             System.err.println("Unable to open : " + fname);
 157             return null;
 158         }
 159     }
 160 
 161     private static long getLongValueFromFile(Controller subSystem, String fileName) {
 162         String data = getFileContents(subSystem, fileName);
 163         return (data == null || data.isEmpty()) ? RETVAL_UNAVAILABLE : convertStringToLong(data);
 164     }
 165 
 166     private static long convertStringToLong(String strval) {
 167         return CgroupMetricsTester.convertStringToLong(strval, RETVAL_UNAVAILABLE, Long.MAX_VALUE);
 168     }
 169 
 170     private static long getLongValueFromFile(Controller subSystem, String metric, String subMetric) {
 171         String stats = getFileContents(subSystem, metric);
 172         String[] tokens = stats.split("[\\r\\n]+");
 173         for (int i = 0; i < tokens.length; i++) {
 174             if (tokens[i].startsWith(subMetric)) {
 175                 String strval = tokens[i].split("\\s+")[1];
 176                 return convertStringToLong(strval);
 177             }
 178         }
 179         return RETVAL_UNAVAILABLE;
 180     }
 181 
 182     private static double getDoubleValueFromFile(Controller subSystem, String fileName) {
 183         String data = getFileContents(subSystem, fileName);
 184         return data == null || data.isEmpty() ? RETVAL_UNAVAILABLE : Double.parseDouble(data);
 185     }
 186 
 187     private static void fail(Controller system, String metric, long oldVal, long testVal) {
 188         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 189     }
 190 
 191     private static void fail(Controller system, String metric, String oldVal, String testVal) {
 192         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 193     }
 194 
 195     private static void fail(Controller system, String metric, double oldVal, double testVal) {
 196         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 197     }
 198 
 199     private static void fail(Controller system, String metric, boolean oldVal, boolean testVal) {
 200         CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
 201     }
 202 
 203     private static void warn(Controller system, String metric, long oldVal, long testVal) {
 204         CgroupMetricsTester.warn(system.value, metric, oldVal, testVal);
 205     }
 206 
 207     private Long[] boxedArrayOrNull(long[] primitiveArray) {
 208         if (primitiveArray == null) {
 209             return null;
 210         }
 211         return LongStream.of(primitiveArray).boxed().toArray(Long[]::new);
 212     }
 213 
 214     public void testMemorySubsystem() {
 215         CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
 216 
 217         // User Memory
 218         long oldVal = metrics.getMemoryFailCount();
 219         long newVal = getLongValueFromFile(Controller.MEMORY, "memory.failcnt");
 220         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 221             fail(Controller.MEMORY, "memory.failcnt", oldVal, newVal);
 222         }
 223 
 224         oldVal = metrics.getMemoryLimit();
 225         newVal = getLongValueFromFile(Controller.MEMORY, "memory.limit_in_bytes");
 226         newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
 227         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 228             fail(Controller.MEMORY, "memory.limit_in_bytes", oldVal, newVal);
 229         }
 230 
 231         oldVal = metrics.getMemoryMaxUsage();
 232         newVal = getLongValueFromFile(Controller.MEMORY, "memory.max_usage_in_bytes");
 233         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 234             fail(Controller.MEMORY, "memory.max_usage_in_bytes", oldVal, newVal);
 235         }
 236 
 237         oldVal = metrics.getMemoryUsage();
 238         newVal = getLongValueFromFile(Controller.MEMORY, "memory.usage_in_bytes");
 239         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 240             fail(Controller.MEMORY, "memory.usage_in_bytes", oldVal, newVal);
 241         }
 242 
 243         // Kernel memory
 244         oldVal = metrics.getKernelMemoryFailCount();
 245         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.failcnt");
 246         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 247             fail(Controller.MEMORY, "memory.kmem.failcnt", oldVal, newVal);
 248         }
 249 
 250         oldVal = metrics.getKernelMemoryLimit();
 251         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.limit_in_bytes");
 252         newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
 253         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 254             fail(Controller.MEMORY, "memory.kmem.limit_in_bytes", oldVal, newVal);
 255         }
 256 
 257         oldVal = metrics.getKernelMemoryMaxUsage();
 258         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.max_usage_in_bytes");
 259         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 260             fail(Controller.MEMORY, "memory.kmem.max_usage_in_bytes", oldVal, newVal);
 261         }
 262 
 263         oldVal = metrics.getKernelMemoryUsage();
 264         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.usage_in_bytes");
 265         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 266             fail(Controller.MEMORY, "memory.kmem.usage_in_bytes", oldVal, newVal);
 267         }
 268 
 269         //TCP Memory
 270         oldVal = metrics.getTcpMemoryFailCount();
 271         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.failcnt");
 272         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 273             fail(Controller.MEMORY, "memory.kmem.tcp.failcnt", oldVal, newVal);
 274         }
 275 
 276         oldVal = metrics.getTcpMemoryLimit();
 277         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes");
 278         newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED: newVal;
 279         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 280             fail(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes", oldVal, newVal);
 281         }
 282 
 283         oldVal = metrics.getTcpMemoryMaxUsage();
 284         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes");
 285         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 286             fail(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes", oldVal, newVal);
 287         }
 288 
 289         oldVal = metrics.getTcpMemoryUsage();
 290         newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes");
 291         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 292             fail(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes", oldVal, newVal);
 293         }
 294 
 295         //  Memory and Swap
 296         oldVal = metrics.getMemoryAndSwapFailCount();
 297         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.failcnt");
 298         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 299             fail(Controller.MEMORY, "memory.memsw.failcnt", oldVal, newVal);
 300         }
 301 
 302         oldVal = metrics.getMemoryAndSwapLimit();
 303         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.limit_in_bytes");
 304         newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
 305         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 306             fail(Controller.MEMORY, "memory.memsw.limit_in_bytes", oldVal, newVal);
 307         }
 308 
 309         oldVal = metrics.getMemoryAndSwapMaxUsage();
 310         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.max_usage_in_bytes");
 311         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 312             fail(Controller.MEMORY, "memory.memsw.max_usage_in_bytes", oldVal, newVal);
 313         }
 314 
 315         oldVal = metrics.getMemoryAndSwapUsage();
 316         newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.usage_in_bytes");
 317         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 318             fail(Controller.MEMORY, "memory.memsw.usage_in_bytes", oldVal, newVal);
 319         }
 320 
 321         oldVal = metrics.getMemorySoftLimit();
 322         newVal = getLongValueFromFile(Controller.MEMORY, "memory.soft_limit_in_bytes");
 323         newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
 324         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 325             fail(Controller.MEMORY, "memory.soft_limit_in_bytes", oldVal, newVal);
 326         }
 327 
 328         boolean oomKillEnabled = metrics.isMemoryOOMKillEnabled();
 329         boolean newOomKillEnabled = getLongValueFromFile(Controller.MEMORY,
 330                 "memory.oom_control", "oom_kill_disable") == 0L ? true : false;
 331         if (oomKillEnabled != newOomKillEnabled) {
 332             throw new RuntimeException("Test failed for - " + Controller.MEMORY.value + ":"
 333                     + "memory.oom_control:oom_kill_disable" + ", expected ["
 334                     + oomKillEnabled + "], got [" + newOomKillEnabled + "]");
 335         }
 336     }
 337 
 338     public void testCpuAccounting() {
 339         CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
 340         long oldVal = metrics.getCpuUsage();
 341         long newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.usage");
 342 
 343         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 344             warn(Controller.CPUACCT, "cpuacct.usage", oldVal, newVal);
 345         }
 346 
 347         String newValsStr = getFileContents(Controller.CPUACCT, "cpuacct.usage_percpu");
 348         Long[] newVals = null;
 349         if (newValsStr != null) {
 350             newVals = Stream.of(newValsStr
 351                 .split("\\s+"))
 352                 .map(Long::parseLong)
 353                 .toArray(Long[]::new);
 354         }
 355         Long[] oldVals = boxedArrayOrNull(metrics.getPerCpuUsage());
 356         if (oldVals != null) {

 357             for (int i = 0; i < oldVals.length; i++) {
 358                 if (!CgroupMetricsTester.compareWithErrorMargin(oldVals[i], newVals[i])) {
 359                     warn(Controller.CPUACCT, "cpuacct.usage_percpu", oldVals[i], newVals[i]);
 360                 }
 361             }
 362         } else {
 363             Asserts.assertNull(newVals, Controller.CPUACCT.value() + "cpuacct.usage_percpu not both null");
 364         }
 365 
 366         oldVal = metrics.getCpuUserUsage();
 367         newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "user");
 368         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 369             warn(Controller.CPUACCT, "cpuacct.usage - user", oldVal, newVal);
 370         }
 371 
 372         oldVal = metrics.getCpuSystemUsage();
 373         newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "system");
 374         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 375             warn(Controller.CPUACCT, "cpuacct.usage - system", oldVal, newVal);
 376         }
 377     }
 378 
 379     public void testCpuSchedulingMetrics() {
 380         CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
 381         long oldVal = metrics.getCpuPeriod();
 382         long newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.cfs_period_us");
 383         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 384             fail(Controller.CPUACCT, "cpu.cfs_period_us", oldVal, newVal);


 401         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_periods");
 402         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 403             fail(Controller.CPUACCT, "cpu.stat - nr_periods", oldVal, newVal);
 404         }
 405 
 406         oldVal = metrics.getCpuNumThrottled();
 407         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_throttled");
 408         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 409             fail(Controller.CPUACCT, "cpu.stat - nr_throttled", oldVal, newVal);
 410         }
 411 
 412         oldVal = metrics.getCpuThrottledTime();
 413         newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "throttled_time");
 414         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 415             fail(Controller.CPUACCT, "cpu.stat - throttled_time", oldVal, newVal);
 416         }
 417     }
 418 
 419     public void testCpuSets() {
 420         CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
 421         Integer[] oldVal = CgroupMetricsTester.boxedArrayOrNull(metrics.getCpuSetCpus());
 422         oldVal = CgroupMetricsTester.sortAllowNull(oldVal);
 423 
 424         String cpusstr = getFileContents(Controller.CPUSET, "cpuset.cpus");
 425         // Parse range string in the format 1,2-6,7
 426         Integer[] newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 427         newVal = CgroupMetricsTester.sortAllowNull(newVal);
 428         if (Arrays.compare(oldVal, newVal) != 0) {
 429             fail(Controller.CPUSET, "cpuset.cpus", Arrays.toString(oldVal),
 430                 Arrays.toString(newVal));
 431         }
 432 
 433         int [] cpuSets = metrics.getEffectiveCpuSetCpus();
 434 
 435         oldVal = CgroupMetricsTester.boxedArrayOrNull(cpuSets);
 436         oldVal = CgroupMetricsTester.sortAllowNull(oldVal);


 437         cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_cpus");
 438         newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 439         newVal = CgroupMetricsTester.sortAllowNull(newVal);
 440         if (Arrays.compare(oldVal, newVal) != 0) {
 441             fail(Controller.CPUSET, "cpuset.effective_cpus", Arrays.toString(oldVal),
 442                     Arrays.toString(newVal));
 443         }

 444 
 445         oldVal = CgroupMetricsTester.boxedArrayOrNull(metrics.getCpuSetMems());
 446         oldVal = CgroupMetricsTester.sortAllowNull(oldVal);
 447         cpusstr = getFileContents(Controller.CPUSET, "cpuset.mems");
 448         newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 449         newVal = CgroupMetricsTester.sortAllowNull(newVal);
 450         if (Arrays.compare(oldVal, newVal) != 0) {
 451             fail(Controller.CPUSET, "cpuset.mems", Arrays.toString(oldVal),
 452                     Arrays.toString(newVal));
 453         }
 454 
 455         int [] cpuSetMems = metrics.getEffectiveCpuSetMems();
 456 
 457         oldVal = CgroupMetricsTester.boxedArrayOrNull(cpuSetMems);
 458         oldVal = CgroupMetricsTester.sortAllowNull(oldVal);


 459         cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_mems");
 460         newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
 461         newVal = CgroupMetricsTester.sortAllowNull(newVal);
 462         if (Arrays.compare(oldVal, newVal) != 0) {
 463             fail(Controller.CPUSET, "cpuset.effective_mems", Arrays.toString(oldVal),
 464                     Arrays.toString(newVal));
 465         }

 466 
 467         double oldValue = metrics.getCpuSetMemoryPressure();
 468         double newValue = getDoubleValueFromFile(Controller.CPUSET, "cpuset.memory_pressure");
 469         if (!CgroupMetricsTester.compareWithErrorMargin(oldValue, newValue)) {
 470             fail(Controller.CPUSET, "cpuset.memory_pressure", oldValue, newValue);
 471         }
 472 
 473         boolean oldV = metrics.isCpuSetMemoryPressureEnabled();
 474         boolean newV = getLongValueFromFile(Controller.CPUSET,
 475                 "cpuset.memory_pressure_enabled") == 1 ? true : false;
 476         if (oldV != newV) {
 477             fail(Controller.CPUSET, "cpuset.memory_pressure_enabled", oldV, newV);
 478         }
 479     }
 480 
 481     private void testBlkIO() {
 482         CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
 483             long oldVal = metrics.getBlkIOServiceCount();
 484         long newVal = getLongValueFromFile(Controller.BLKIO,
 485                 "blkio.throttle.io_service_bytes", "Total");
 486         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 487             fail(Controller.BLKIO, "blkio.throttle.io_service_bytes - Total",
 488                     oldVal, newVal);
 489         }
 490 
 491         oldVal = metrics.getBlkIOServiced();
 492         newVal = getLongValueFromFile(Controller.BLKIO, "blkio.throttle.io_serviced", "Total");
 493         if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
 494             fail(Controller.BLKIO, "blkio.throttle.io_serviced - Total", oldVal, newVal);
 495         }
 496     }
 497 
 498     public void testCpuConsumption() throws IOException, InterruptedException {
 499         CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
 500         // make system call
 501         long newSysVal = metrics.getCpuSystemUsage();
 502         long newUserVal = metrics.getCpuUserUsage();
 503         long newUsage = metrics.getCpuUsage();
 504         long[] newPerCpu = metrics.getPerCpuUsage();



 505 
 506         // system/user CPU usage counters may be slowly increasing.
 507         // allow for equal values for a pass
 508         if (newSysVal < startSysVal) {
 509             fail(Controller.CPU, "getCpuSystemUsage", newSysVal, startSysVal);
 510         }
 511 
 512         // system/user CPU usage counters may be slowly increasing.
 513         // allow for equal values for a pass
 514         if (newUserVal < startUserVal) {
 515             fail(Controller.CPU, "getCpuUserUsage", newUserVal, startUserVal);
 516         }
 517 
 518         if (newUsage <= startUsage) {
 519             fail(Controller.CPU, "getCpuUsage", newUsage, startUsage);
 520         }
 521 
 522         if (startPerCpu != null) {
 523             boolean success = false;
 524             for (int i = 0; i < startPerCpu.length; i++) {
 525                 if (newPerCpu[i] > startPerCpu[i]) {
 526                     success = true;
 527                     break;
 528                 }
 529             }
 530             if (!success) {
 531                 fail(Controller.CPU, "getPerCpuUsage", Arrays.toString(newPerCpu),
 532                                                        Arrays.toString(startPerCpu));
 533             }
 534         } else {
 535             Asserts.assertNull(newPerCpu, Controller.CPU.value() + " getPerCpuUsage not both null");
 536         }
 537 
 538     }
 539 
 540     public void testMemoryUsage() throws Exception {
 541         CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
 542         long memoryMaxUsage = metrics.getMemoryMaxUsage();
 543         long memoryUsage = metrics.getMemoryUsage();
 544         long newMemoryMaxUsage = 0, newMemoryUsage = 0;
 545 
 546         // allocate memory in a loop and check more than once for new values
 547         // otherwise we might see seldom the effect of decreasing new memory values
 548         // e.g. because the system could free up memory
 549         byte[][] bytes = new byte[32][];
 550         for (int i = 0; i < 32; i++) {
 551             bytes[i] = new byte[8*1024*1024];
 552             newMemoryUsage = metrics.getMemoryUsage();
 553             if (newMemoryUsage > memoryUsage) {
 554                 break;
 555             }
 556         }
 557         newMemoryMaxUsage = metrics.getMemoryMaxUsage();
< prev index next >