8203357: Container Metrics
authorbobv
Tue, 12 Jun 2018 18:51:45 -0400
changeset 50545 292a4a87c321
parent 50544 5f20bf95c052
child 50546 52b866a1a63a
8203357: Container Metrics Reviewed-by: mchung, dholmes, mseledtsov, rehn
src/java.base/linux/classes/jdk/internal/platform/cgroupv1/Metrics.java
src/java.base/linux/classes/jdk/internal/platform/cgroupv1/SubSystem.java
src/java.base/share/classes/jdk/internal/platform/Container.java
src/java.base/share/classes/jdk/internal/platform/Metrics.java
src/java.base/share/classes/sun/launcher/LauncherHelper.java
src/java.base/share/classes/sun/launcher/resources/launcher.properties
test/hotspot/jtreg/runtime/containers/docker/CPUSetsReader.java
test/hotspot/jtreg/runtime/containers/docker/Common.java
test/hotspot/jtreg/runtime/containers/docker/TestCPUAwareness.java
test/hotspot/jtreg/runtime/containers/docker/TestCPUSets.java
test/hotspot/jtreg/runtime/containers/docker/TestMemoryAwareness.java
test/hotspot/jtreg/runtime/containers/docker/TestMisc.java
test/jdk/TEST.ROOT
test/jdk/jdk/internal/platform/cgroup/TestCgroupMetrics.java
test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest
test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-aarch64
test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-ppc64le
test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-s390x
test/jdk/jdk/internal/platform/docker/MetricsCpuTester.java
test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java
test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java
test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java
test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java
test/jdk/tools/launcher/Settings.java
test/lib/jdk/test/lib/containers/cgroup/CPUSetsReader.java
test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java
test/lib/jdk/test/lib/containers/docker/Common.java
test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java
test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/Metrics.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.platform.cgroupv1;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+public class Metrics implements jdk.internal.platform.Metrics {
+    private SubSystem memory;
+    private SubSystem cpu;
+    private SubSystem cpuacct;
+    private SubSystem cpuset;
+    private SubSystem blkio;
+    private boolean activeSubSystems;
+
+    // Values returned larger than this number are unlimited.
+    static long unlimited_minimum = 0x7FFFFFFFFF000000L;
+
+    private static final Metrics INSTANCE = initContainerSubSystems();
+
+    private static final String PROVIDER_NAME = "cgroupv1";
+
+    private Metrics() {
+        activeSubSystems = false;
+    }
+
+    public static Metrics getInstance() {
+        return INSTANCE;
+    }
+
+    private static Metrics initContainerSubSystems() {
+        Metrics metrics = new Metrics();
+
+        /**
+         * Find the cgroup mount points for subsystems
+         * by reading /proc/self/mountinfo
+         *
+         * Example for docker MemorySubSystem subsystem:
+         * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/MemorySubSystem ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,MemorySubSystem
+         *
+         * Example for host:
+         * 34 28 0:29 / /sys/fs/cgroup/MemorySubSystem rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,MemorySubSystem
+         */
+        try (Stream<String> lines =
+             Files.lines(Paths.get("/proc/self/mountinfo"))) {
+
+            lines.filter(line -> line.contains(" - cgroup "))
+                 .map(line -> line.split(" "))
+                 .forEach(entry -> createSubSystem(metrics, entry));
+
+        } catch (IOException e) {
+            return null;
+        }
+
+        /**
+         * Read /proc/self/cgroup and map host mount point to
+         * local one via /proc/self/mountinfo content above
+         *
+         * Docker example:
+         * 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb044
+         *
+         * Host example:
+         * 5:memory:/user.slice
+         *
+         * Construct a path to the process specific memory and cpuset
+         * cgroup directory.
+         *
+         * For a container running under Docker from memory example above
+         * the paths would be:
+         *
+         * /sys/fs/cgroup/memory
+         *
+         * For a Host from memory example above the path would be:
+         *
+         * /sys/fs/cgroup/memory/user.slice
+         *
+         */
+        try (Stream<String> lines =
+             Files.lines(Paths.get("/proc/self/cgroup"))) {
+
+            lines.map(line -> line.split(":"))
+                 .filter(line -> (line.length >= 3))
+                 .forEach(line -> setSubSystemPath(metrics, line));
+
+        } catch (IOException e) {
+            return null;
+        }
+
+        // Return Metrics object if we found any subsystems.
+        if (metrics.activeSubSystems()) {
+            return metrics;
+        }
+
+        return null;
+    }
+
+    /**
+     * createSubSystem objects and initialize mount points
+     */
+    private static void createSubSystem(Metrics metric, String [] mountentry) {
+        if (mountentry.length < 5) return;
+
+        Path p = Paths.get(mountentry[4]);
+        String subsystemName = p.getFileName().toString();
+
+        if (subsystemName != null) {
+            switch (subsystemName) {
+                case "memory":
+                    metric.setMemorySubSystem(new SubSystem(mountentry[3], mountentry[4]));
+                    break;
+                case "cpuset":
+                    metric.setCpuSetSubSystem(new SubSystem(mountentry[3], mountentry[4]));
+                    break;
+                case "cpu,cpuacct":
+                case "cpuacct,cpu":
+                    metric.setCpuSubSystem(new SubSystem(mountentry[3], mountentry[4]));
+                    metric.setCpuAcctSubSystem(new SubSystem(mountentry[3], mountentry[4]));
+                    break;
+                case "cpuacct":
+                    metric.setCpuAcctSubSystem(new SubSystem(mountentry[3], mountentry[4]));
+                    break;
+                case "cpu":
+                    metric.setCpuSubSystem(new SubSystem(mountentry[3], mountentry[4]));
+                    break;
+                case "blkio":
+                    metric.setBlkIOSubSystem(new SubSystem(mountentry[3], mountentry[4]));
+                    break;
+                default:
+                    // Ignore subsystems that we don't support
+                    break;
+            }
+        }
+    }
+
+    /**
+     * setSubSystemPath based on the contents of /proc/self/cgroup
+     */
+    private static void setSubSystemPath(Metrics metric, String [] entry) {
+        String controller;
+        String base;
+        SubSystem subsystem = null;
+        SubSystem subsystem2 = null;
+
+        controller = entry[1];
+        base = entry[2];
+        if (controller != null && base != null) {
+            switch (controller) {
+                case "memory":
+                    subsystem = metric.MemorySubSystem();
+                    break;
+                case "cpuset":
+                    subsystem = metric.CpuSetSubSystem();
+                    break;
+                case "cpu,cpuacct":
+                case "cpuacct,cpu":
+                    subsystem = metric.CpuSubSystem();
+                    subsystem2 = metric.CpuAcctSubSystem();
+                    break;
+                case "cpuacct":
+                    subsystem = metric.CpuAcctSubSystem();
+                    break;
+                case "cpu":
+                    subsystem = metric.CpuSubSystem();
+                    break;
+                case "blkio":
+                    subsystem = metric.BlkIOSubSystem();
+                    break;
+                // Ignore subsystems that we don't support
+                default:
+                    break;
+            }
+        }
+
+        if (subsystem != null) {
+            subsystem.setPath(base);
+            metric.setActiveSubSystems();
+        }
+        if (subsystem2 != null) {
+            subsystem2.setPath(base);
+        }
+    }
+
+
+    private void setActiveSubSystems() {
+        activeSubSystems = true;
+    }
+
+    private boolean activeSubSystems() {
+        return activeSubSystems;
+    }
+
+    private void setMemorySubSystem(SubSystem memory) {
+        this.memory = memory;
+    }
+
+    private void setCpuSubSystem(SubSystem cpu) {
+        this.cpu = cpu;
+    }
+
+    private void setCpuAcctSubSystem(SubSystem cpuacct) {
+        this.cpuacct = cpuacct;
+    }
+
+    private void setCpuSetSubSystem(SubSystem cpuset) {
+        this.cpuset = cpuset;
+    }
+
+    private void setBlkIOSubSystem(SubSystem blkio) {
+        this.blkio = blkio;
+    }
+
+    private SubSystem MemorySubSystem() {
+        return memory;
+    }
+
+    private SubSystem CpuSubSystem() {
+        return cpu;
+    }
+
+    private SubSystem CpuAcctSubSystem() {
+        return cpuacct;
+    }
+
+    private SubSystem CpuSetSubSystem() {
+        return cpuset;
+    }
+
+    private SubSystem BlkIOSubSystem() {
+        return blkio;
+    }
+
+    public String getProvider() {
+        return PROVIDER_NAME;
+    }
+
+    /*****************************************************************
+     * CPU Accounting Subsystem
+     ****************************************************************/
+
+
+    public long getCpuUsage() {
+        return SubSystem.getLongValue(cpuacct, "cpuacct.usage");
+    }
+
+    public long[] getPerCpuUsage() {
+        String usagelist = SubSystem.getStringValue(cpuacct, "cpuacct.usage_percpu");
+        if (usagelist == null) {
+            return new long[0];
+        }
+
+        String list[] = usagelist.split(" ");
+        long percpu[] = new long[list.length];
+        for (int i = 0; i < list.length; i++) {
+            percpu[i] = Long.parseLong(list[i]);
+        }
+        return percpu;
+    }
+
+    public long getCpuUserUsage() {
+        return SubSystem.getLongEntry(cpuacct, "cpuacct.stat", "user");
+    }
+
+    public long getCpuSystemUsage() {
+        return SubSystem.getLongEntry(cpuacct, "cpuacct.stat", "system");
+    }
+
+
+    /*****************************************************************
+     * CPU Subsystem
+     ****************************************************************/
+
+
+    public long getCpuPeriod() {
+        return SubSystem.getLongValue(cpuacct, "cpu.cfs_period_us");
+    }
+
+    public long getCpuQuota() {
+        return SubSystem.getLongValue(cpuacct, "cpu.cfs_quota_us");
+    }
+
+    public long getCpuShares() {
+        long retval = SubSystem.getLongValue(cpuacct, "cpu.shares");
+        if (retval == 0 || retval == 1024)
+            return -1;
+        else
+            return retval;
+    }
+
+    public long getCpuNumPeriods() {
+        return SubSystem.getLongEntry(cpuacct, "cpu.stat", "nr_periods");
+    }
+
+    public long getCpuNumThrottled() {
+        return SubSystem.getLongEntry(cpuacct, "cpu.stat", "nr_throttled");
+    }
+
+    public long getCpuThrottledTime() {
+        return SubSystem.getLongEntry(cpuacct, "cpu.stat", "throttled_time");
+    }
+
+    public long getEffectiveCpuCount() {
+        return Runtime.getRuntime().availableProcessors();
+    }
+
+
+    /*****************************************************************
+     * CPUSet Subsystem
+     ****************************************************************/
+
+    public int[] getCpuSetCpus() {
+        return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.cpus"));
+    }
+
+    public int[] getEffectiveCpuSetCpus() {
+        return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.effective_cpus"));
+    }
+
+    public int[] getCpuSetMems() {
+        return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.mems"));
+    }
+
+    public int[] getEffectiveCpuSetMems() {
+        return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.effective_mems"));
+    }
+
+    public double getCpuSetMemoryPressure() {
+        return SubSystem.getDoubleValue(cpuset, "cpuset.memory_pressure");
+    }
+
+    public boolean isCpuSetMemoryPressureEnabled() {
+        long val = SubSystem.getLongValue(cpuset, "cpuset.memory_pressure_enabled");
+        return (val == 1);
+    }
+
+
+    /*****************************************************************
+     * Memory Subsystem
+     ****************************************************************/
+
+
+    public long getMemoryFailCount() {
+        return SubSystem.getLongValue(memory, "memory.failcnt");
+    }
+
+    public long getMemoryLimit() {
+        long retval = SubSystem.getLongValue(memory, "memory.limit_in_bytes");
+        return retval > unlimited_minimum ? -1L : retval;
+    }
+
+    public long getMemoryMaxUsage() {
+        return SubSystem.getLongValue(memory, "memory.max_usage_in_bytes");
+    }
+
+    public long getMemoryUsage() {
+        return SubSystem.getLongValue(memory, "memory.usage_in_bytes");
+    }
+
+    public long getKernelMemoryFailCount() {
+        return SubSystem.getLongValue(memory, "memory.kmem.failcnt");
+    }
+
+    public long getKernelMemoryLimit() {
+        long retval = SubSystem.getLongValue(memory, "memory.kmem.limit_in_bytes");
+        return retval > unlimited_minimum ? -1L : retval;
+    }
+
+    public long getKernelMemoryMaxUsage() {
+        return SubSystem.getLongValue(memory, "memory.kmem.max_usage_in_bytes");
+    }
+
+    public long getKernelMemoryUsage() {
+        return SubSystem.getLongValue(memory, "memory.kmem.usage_in_bytes");
+    }
+
+    public long getTcpMemoryFailCount() {
+        return SubSystem.getLongValue(memory, "memory.kmem.tcp.failcnt");
+    }
+
+    public long getTcpMemoryLimit() {
+        long retval =  SubSystem.getLongValue(memory, "memory.kmem.tcp.limit_in_bytes");
+        return retval > unlimited_minimum ? -1L : retval;
+    }
+
+    public long getTcpMemoryMaxUsage() {
+        return SubSystem.getLongValue(memory, "memory.kmem.tcp.max_usage_in_bytes");
+    }
+
+    public long getTcpMemoryUsage() {
+        return SubSystem.getLongValue(memory, "memory.kmem.tcp.usage_in_bytes");
+    }
+
+    public long getMemoryAndSwapFailCount() {
+        return SubSystem.getLongValue(memory, "memory.memsw.failcnt");
+    }
+
+    public long getMemoryAndSwapLimit() {
+        long retval = SubSystem.getLongValue(memory, "memory.memsw.limit_in_bytes");
+        return retval > unlimited_minimum ? -1L : retval;
+    }
+
+    public long getMemoryAndSwapMaxUsage() {
+        return SubSystem.getLongValue(memory, "memory.memsw.max_usage_in_bytes");
+    }
+
+    public long getMemoryAndSwapUsage() {
+        return SubSystem.getLongValue(memory, "memory.memsw.usage_in_bytes");
+    }
+
+    public boolean isMemoryOOMKillEnabled() {
+        long val = SubSystem.getLongEntry(memory, "memory.oom_control", "oom_kill_disable");
+        return (val == 0);
+    }
+
+    public long getMemorySoftLimit() {
+        long retval = SubSystem.getLongValue(memory, "memory.soft_limit_in_bytes");
+        return retval > unlimited_minimum ? -1L : retval;
+    }
+
+
+    /*****************************************************************
+     * BlKIO Subsystem
+     ****************************************************************/
+
+
+    public long getBlkIOServiceCount() {
+        return SubSystem.getLongEntry(blkio, "blkio.throttle.io_service_bytes", "Total");
+    }
+
+    public long getBlkIOServiced() {
+        return SubSystem.getLongEntry(blkio, "blkio.throttle.io_serviced", "Total");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/SubSystem.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.platform.cgroupv1;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class SubSystem {
+    String root;
+    String mountPoint;
+    String path;
+
+    public SubSystem(String root, String mountPoint) {
+        this.root = root;
+        this.mountPoint = mountPoint;
+    }
+
+    public void setPath(String cgroupPath) {
+        if (root != null && cgroupPath != null) {
+            if (root.equals("/")) {
+                if (cgroupPath.equals("/")) {
+                    path = mountPoint + cgroupPath;
+                }
+                else {
+                    path = mountPoint;
+                }
+            }
+            else {
+                if (root.equals(cgroupPath)) {
+                    path = mountPoint;
+                }
+                else {
+                    if (root.indexOf(cgroupPath) == 0) {
+                        if (cgroupPath.length() > root.length()) {
+                            String cgroupSubstr = cgroupPath.substring(root.length());
+                            path = mountPoint + cgroupSubstr;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public String path() {
+        return path;
+    }
+
+    /**
+     * getSubSystemStringValue
+     *
+     * Return the first line of the file "parm" argument from the subsystem.
+     *
+     * TODO:  Consider using weak references for caching BufferedReader object.
+     *
+     * @param subsystem
+     * @param parm
+     * @return Returns the contents of the file specified by param.
+     */
+    public static String getStringValue(SubSystem subsystem, String parm) {
+        if (subsystem == null) return null;
+
+        try(BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(subsystem.path(), parm))) {
+            String line = bufferedReader.readLine();
+            return line;
+        }
+        catch (IOException e) {
+            return null;
+        }
+
+    }
+
+    public static long getLongValue(SubSystem subsystem, String parm) {
+        String strval = getStringValue(subsystem, parm);
+
+        if (strval == null) return 0L;
+
+        long retval = Long.parseLong(strval);
+
+        return retval;
+    }
+
+    public static double getDoubleValue(SubSystem subsystem, String parm) {
+        String strval = getStringValue(subsystem, parm);
+
+        if (strval == null) return 0L;
+
+        double retval = Double.parseDouble(strval);
+
+        return retval;
+    }
+
+    /**
+     * getSubSystemlongEntry
+     *
+     * Return the long value from the line containing the string "entryname"
+     * within file "parm" in the "subsystem".
+     *
+     * TODO:  Consider using weak references for caching BufferedReader object.
+     *
+     * @param subsystem
+     * @param parm
+     * @param entryname
+     * @return long value
+     */
+    public static long getLongEntry(SubSystem subsystem, String parm, String entryname) {
+        String val = null;
+
+        if (subsystem == null) return 0L;
+
+        try (Stream<String> lines = Files.lines(Paths.get(subsystem.path(), parm))) {
+
+            Optional<String> result = lines.map(line -> line.split(" "))
+                                           .filter(line -> (line.length == 2 &&
+                                                   line[0].equals(entryname)))
+                                           .map(line -> line[1])
+                                           .findFirst();
+
+            return result.isPresent() ? Long.parseLong(result.get()) : 0L;
+        }
+        catch (IOException e) {
+            return 0L;
+        }
+    }
+
+    public static int getIntValue(SubSystem subsystem, String parm) {
+        String val = getStringValue(subsystem, parm);
+
+        if (val == null) return 0;
+
+        return Integer.parseInt(val);
+    }
+
+    /**
+     * StringRangeToIntArray
+     *
+     * Convert a string in the form of  1,3-4,6 to an array of
+     * integers containing all the numbers in the range.
+     *
+     * @param range
+     * @return int[] containing a sorted list of processors or memory nodes
+     */
+    public static int[] StringRangeToIntArray(String range) {
+        int[] ints = new int[0];
+
+        if (range == null) return ints;
+
+        ArrayList<Integer> results = new ArrayList<>();
+        String strs[] = range.split(",");
+        for (String str : strs) {
+            if (str.contains("-")) {
+                String lohi[] = str.split("-");
+                // validate format
+                if (lohi.length != 2) {
+                    continue;
+                }
+                int lo = Integer.parseInt(lohi[0]);
+                int hi = Integer.parseInt(lohi[1]);
+                for (int i = lo; i <= hi; i++) {
+                    results.add(i);
+                }
+            }
+            else {
+                results.add(Integer.parseInt(str));
+            }
+        }
+
+        // sort results
+        results.sort(null);
+
+        // convert ArrayList to primitive int array
+        ints = new int[results.size()];
+        int i = 0;
+        for (Integer n : results) {
+            ints[i++] = n;
+        }
+
+        return ints;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/platform/Container.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.platform;
+
+/*
+ * @author bobv
+ * @since 11
+ */
+
+public class Container {
+
+    private Container() { }
+
+    /**
+     * Returns the platform specific Container Metrics class or
+     * null if not supported on this platform.
+     *
+     * @return Metrics instance or null if not supported
+     */
+    public static Metrics metrics() {
+        return Metrics.systemMetrics();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/platform/Metrics.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.platform;
+
+import java.lang.reflect.Method;
+
+/**
+ * Operating System Metrics class
+ *
+ * @implNote Some of the APIs within this class return metrics for an
+ * "Isolation Group" or "Container".  When the term "Isolation Group"
+ * is used in the API description, this refers to either:
+ *
+ *<ol>
+ *<li> All processes, including the current process within a container.
+ *
+ *<li> All processes, including the current process running together
+ *    isolated from other non-isolated processes.
+ *
+ *<li> All processes running on a host when that there is no isolation
+ *     in effect.
+ *</ol>
+ *
+ * @author bobv
+ * @since 11
+ */
+
+public interface Metrics {
+
+    /**
+     * Returns an instance of the Metrics class.
+     *
+     * @return Metrics object or null if not supported on this platform.
+     */
+    public static Metrics systemMetrics() {
+        try {
+            // We currently only support cgroupv1
+            Class<?> c = Class.forName("jdk.internal.platform.cgroupv1.Metrics");
+            @SuppressWarnings("unchecked")
+            Method m = c.getMethod("getInstance");
+            return (Metrics) m.invoke(null);
+        } catch (ClassNotFoundException e) {
+            return null;
+        } catch (ReflectiveOperationException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns the interface responsible for providing the
+     * platform metrics.
+     *
+     * @implNote
+     * Metrics are currently only supported Linux.
+     * The provider for Linux is cgroupsv1.
+     *
+     * @return The name of the provider.
+     *
+     */
+    public String getProvider();
+
+
+    /*****************************************************************
+     * CPU Accounting Subsystem
+     ****************************************************************/
+
+    /**
+     * Returns the aggregate time, in nanoseconds, consumed by all
+     * tasks in the Isolation Group.
+     *
+     * @return Time in nanoseconds or 0L if metric is not available.
+     *
+     */
+    public long getCpuUsage();
+
+    /**
+     * Returns the aggregate time, in nanoseconds, consumed by all tasks in
+     * the Isolation Group, separated by CPU. If the current process
+     * is running within a container, the reported time will only be
+     * valid for processes running within the same container.  The values
+     * are returned in an array, one entry for each physical processor
+     * on the system.  Time values for processors unavailable to this
+     * Group are undefined.
+     *
+     * @return long array of time values.  The size of the array is equal
+     *         to the total number of physical processors in the system. If
+     *         this metric is not available, a zero length array will be
+     *         returned.
+     *
+     */
+    public long[] getPerCpuUsage();
+
+    /**
+     * Returns the aggregate user time, in nanoseconds, consumed by all
+     * tasks in the Isolation Group.
+     *
+     * @return User time in nanoseconds or 0L if metric is not available.
+     *
+     */
+    public long getCpuUserUsage();
+
+    /**
+     * Returns the aggregate system time, in nanoseconds, consumed by
+     * all tasks in the Isolation Group.
+     *
+     * @return System time in nanoseconds or 0L if metric is not available.
+     *
+     */
+    public long getCpuSystemUsage();
+
+    /*****************************************************************
+     * CPU Scheduling Metrics
+     ****************************************************************/
+
+    /**
+     * Returns the length of the scheduling period, in
+     * microseconds, for processes within the Isolation Group.
+     *
+     * @return time in microseconds or 0L if metric is not available.
+     *
+     */
+    public long getCpuPeriod();
+
+    /**
+     * Returns the total available run-time allowed, in microseconds,
+     * during each scheduling period for all tasks in the Isolation
+     * Group.
+     *
+     * @return time in microseconds or -1 if the quota is unlimited.
+     *
+     */
+    public long getCpuQuota();
+
+
+    /**
+     * Returns the relative weighting of processes with the Isolation
+     * Group used for prioritizing the scheduling of processes across
+     * all Isolation Groups running on a host.
+     *
+     * @implNote
+     * Popular container orchestration systems have standardized shares
+     * to be multiples of 1024, where 1024 is interpreted as 1 CPU share
+     * of execution.  Users can distribute CPU resources to multiple
+     * Isolation Groups by specifying the CPU share weighting needed by
+     * each process.  To request 2 CPUS worth of execution time, CPU shares
+     * would be set to 2048.
+     *
+     * @return shares value or -1 if no share set.
+     *
+     */
+    public long getCpuShares();
+
+    /**
+     * Returns the number of time-slice periods that have elapsed if
+     * a CPU quota has been setup for the Isolation Group; otherwise
+     * returns 0.
+     *
+     * @return count of elapsed periods or 0 if the quota is unlimited.
+     *
+     */
+    public long getCpuNumPeriods();
+
+    /**
+     * Returns the number of time-slice periods that the group has
+     * been throttled or limited due to the group exceeding its quota
+     * if a CPU quota has been setup for the Isolation Group.
+     *
+     * @return count of throttled periods or 0 if the quota is unlimited.
+     *
+     */
+    public long getCpuNumThrottled();
+
+    /**
+     * Returns the total time duration, in nanoseconds, that the
+     * group has been throttled or limited due to the group exceeding
+     * its quota if a CPU quota has been setup for the Isolation Group.
+     *
+     * @return Throttled time in nanoseconds or 0 if the quota is unlimited.
+     *
+     */
+    public long getCpuThrottledTime();
+
+
+    /**
+     * Returns the number of effective processors that this Isolation
+     * group has available to it.  This effective processor count is
+     * computed based on the number of dedicated CPUs, CPU shares and
+     * CPU quotas in effect for this isolation group.
+     *
+     * This method returns the same value as
+     * {@link java.lang.Runtime#availableProcessors()}.
+     *
+     * @return The number of effective CPUs.
+     *
+     */
+    public long getEffectiveCpuCount();
+
+    /*****************************************************************
+     * CPU Sets
+     ****************************************************************/
+
+    /**
+     * Returns the CPUS that are available for execution of processes
+     * in the current Isolation Group. The size of the array is equal
+     * to the total number of CPUs and the elements in the array are the
+     * physical CPU numbers that are available.  Some of the CPUs returned
+     * may be offline.  To get the current online CPUs, use
+     * {@link getEffectiveCpuSetCpus()}.
+     *
+     * @return An array of available CPUs or a zero length array
+     *         if the metric is not available.
+     *
+     */
+    public int[] getCpuSetCpus();
+
+    /**
+     * Returns the CPUS that are available and online for execution of
+     * processes within the current Isolation Group. The size of the
+     * array is equal to the total number of CPUs and the elements in
+     * the array are the physical CPU numbers.
+     *
+     * @return An array of available and online CPUs or a zero length
+     *         array if the metric is not available.
+     *
+     */
+    public int[] getEffectiveCpuSetCpus();
+
+    /**
+     * Returns the memory nodes that are available for use by processes
+     * in the current Isolation Group. The size of the array is equal
+     * to the total number of nodes and the elements in the array are the
+     * physical node numbers that are available.  Some of the nodes returned
+     * may be offline.  To get the current online memory nodes, use
+     * {@link getEffectiveCpuSetMems()}.
+     *
+     * @return An array of available memory nodes or a zero length array
+     *         if the metric is not available.
+     *
+     */
+    public int[] getCpuSetMems();
+
+    /**
+     * Returns the memory nodes that are available and online for use by
+     * processes within the current Isolation Group. The size of the
+     * array is equal to the total number of nodes and the elements in
+     * the array are the physical node numbers.
+     *
+     * @return An array of available and online nodes or a zero length
+     *         array if the metric is not available.
+     *
+     */
+    public int[] getEffectiveCpuSetMems();
+
+    /**
+     * Returns the (attempts per second * 1000), if enabled, that the
+     * operating system tries to satisfy a memory request for any
+     * process in the current Isolation Group when no free memory is
+     * readily available.  Use {@link #isCpuSetMemoryPressureEnabled()} to
+     * to determine if this support is enabled.
+     *
+     * @return Memory pressure or 0 if not enabled or metric is not
+     *         available.
+     *
+     */
+    public double getCpuSetMemoryPressure();
+
+    /**
+     * Returns the state of the memory pressure detection support.
+     *
+     * @return true if the support is available and enabled, otherwise false.
+     *
+     */
+    public boolean isCpuSetMemoryPressureEnabled();
+
+    /*****************************************************************
+     * Memory Subsystem
+     ****************************************************************/
+
+    /**
+     * Returns the number of times that user memory requests in the
+     * Isolation Group have exceeded the memory limit.
+     *
+     * @return The number of exceeded requests or 0 if none or metric
+     *         is not available.
+     *
+     */
+    public long getMemoryFailCount();
+
+    /**
+     * Returns the maximum amount of physical memory, in bytes, that
+     * can be allocated in the Isolation Group.
+     *
+     * @return The maximum amount of memory in bytes or -1 if either
+     *         there is no limit set or this metric is not available.
+     *
+     */
+    public long getMemoryLimit();
+
+    /**
+     * Returns the largest amount of physical memory, in bytes, that
+     * have been allocated in the Isolation Group.
+     *
+     * @return The largest amount of memory in bytes or or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getMemoryMaxUsage();
+
+    /**
+     * Returns the amount of physical memory, in bytes, that is currently
+     * allocated in the current Isolation Group.
+     *
+     * @return The amount of memory in bytes allocated or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getMemoryUsage();
+
+    /**
+     * Returns the number of times that kernel memory requests in the
+     * Isolation Group have exceeded the kernel memory limit.
+     *
+     * @return The number of exceeded requests or 0 if none or metric
+     *         is not available.
+     *
+     */
+    public long getKernelMemoryFailCount();
+
+    /**
+     * Returns the maximum amount of kernel physical memory, in bytes, that
+     * can be allocated in the Isolation Group.
+     *
+     * @return The maximum amount of memory in bytes or -1 if either
+     *         there is no limit set or this metric is not available.
+     *
+     */
+    public long getKernelMemoryLimit();
+
+    /**
+     * Returns the largest amount of kernel physical memory, in bytes, that
+     * have been allocated in the Isolation Group.
+     *
+     * @return The largest amount of memory in bytes or or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getKernelMemoryMaxUsage();
+
+    /**
+     * Returns the amount of kernel physical memory, in bytes, that
+     * is currently allocated in the current Isolation Group.
+     *
+     * @return The amount of memory in bytes allocated or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getKernelMemoryUsage();
+
+    /**
+     * Returns the number of times that networking memory requests in the
+     * Isolation Group have exceeded the kernel memory limit.
+     *
+     * @return The number of exceeded requests or 0 if none or metric
+     *         is not available.
+     *
+     */
+    public long getTcpMemoryFailCount();
+
+    /**
+     * Returns the maximum amount of networking physical memory, in bytes,
+     * that can be allocated in the Isolation Group.
+     *
+     * @return The maximum amount of memory in bytes or -1 if either
+     *         there is no limit set or this metric is not available.
+     *
+     */
+    public long getTcpMemoryLimit();
+
+    /**
+     * Returns the largest amount of networking physical memory, in bytes,
+     * that have been allocated in the Isolation Group.
+     *
+     * @return The largest amount of memory in bytes or or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getTcpMemoryMaxUsage();
+
+    /**
+     * Returns the amount of networking physical memory, in bytes, that
+     * is currently allocated in the current Isolation Group.
+     *
+     * @return The amount of memory in bytes allocated or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getTcpMemoryUsage();
+
+    /**
+     * Returns the number of times that user memory requests in the
+     * Isolation Group have exceeded the memory + swap limit.
+     *
+     * @return The number of exceeded requests or 0 if none or metric
+     *         is not available.
+     *
+     */
+    public long getMemoryAndSwapFailCount();
+
+    /**
+     * Returns the maximum amount of physical memory and swap space,
+     * in bytes, that can be allocated in the Isolation Group.
+     *
+     * @return The maximum amount of memory in bytes or -1 if either
+     *         there is no limit set or this metric is not available.
+     *
+     */
+    public long getMemoryAndSwapLimit();
+
+    /**
+     * Returns the largest amount of physical memory and swap space,
+     * in bytes, that have been allocated in the Isolation Group.
+     *
+     * @return The largest amount of memory in bytes or or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getMemoryAndSwapMaxUsage();
+
+    /**
+     * Returns the amount of physical memory and swap space, in bytes,
+     * that is currently allocated in the current Isolation Group.
+     *
+     * @return The amount of memory in bytes allocated or 0 if this
+     *         metric is not available.
+     *
+     */
+    public long getMemoryAndSwapUsage();
+
+    /**
+     * Returns the state of the Operating System Out of Memory termination
+     * policy.
+     *
+     * @return Returns true if operating system will terminate processes
+     *         in the Isolation Group that exceed the amount of available
+     *         memory, otherwise false.  Flase will be returned if this
+     *         capability is not available on the current operating system.
+     *
+     */
+    public boolean isMemoryOOMKillEnabled();
+
+    /**
+     * Returns the hint to the operating system that allows groups
+     * to specify the minimum amount of physical memory that they need to
+     * achieve reasonable performance in low memory systems.  This allows
+     * host systems to provide greater sharing of memory.
+     *
+     * @return The minimum amount of physical memory, in bytes, that the
+     *         operating system will try to maintain under low memory
+     *         conditions.  If this metric is not available, 0 will be
+     *         returned.
+     *
+     */
+    public long getMemorySoftLimit();
+
+    /*****************************************************************
+     * BlKIO Subsystem
+     ****************************************************************/
+
+    /**
+     * Returns the number of block I/O requests to the disk that have been
+     * issued by the Isolation Group.
+     *
+     * @return The count of requests or 0 if this metric is not available.
+     *
+     */
+    public long getBlkIOServiceCount();
+
+    /**
+     * Returns the number of block I/O bytes that have been transferred
+     * to/from the disk by the Isolation Group.
+     *
+     * @return The number of bytes transferred or 0 if this metric is not available.
+     *
+     */
+    public long getBlkIOServiced();
+}
--- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Tue Jun 12 18:51:45 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -91,6 +91,9 @@
 import jdk.internal.misc.VM;
 import jdk.internal.module.ModuleBootstrap;
 import jdk.internal.module.Modules;
+import jdk.internal.platform.Container;
+import jdk.internal.platform.Metrics;
+
 
 public final class LauncherHelper {
 
@@ -151,6 +154,7 @@
      *    this code determine this value, using a suitable method or omit the
      *    line entirely.
      */
+    @SuppressWarnings("fallthrough")
     static void showSettings(boolean printToStderr, String optionFlag,
             long initialHeapSize, long maxHeapSize, long stackSize) {
 
@@ -169,10 +173,18 @@
             case "locale":
                 printLocale();
                 break;
+            case "system":
+                if (System.getProperty("os.name").contains("Linux")) {
+                    printSystemMetrics();
+                    break;
+                }
             default:
                 printVmSettings(initialHeapSize, maxHeapSize, stackSize);
                 printProperties();
                 printLocale();
+                if (System.getProperty("os.name").contains("Linux")) {
+                    printSystemMetrics();
+                }
                 break;
         }
     }
@@ -307,6 +319,101 @@
         }
     }
 
+    public static void printSystemMetrics() {
+        Metrics c = Container.metrics();
+
+        ostream.println("Operating System Metrics:");
+
+        if (c == null) {
+            ostream.println(INDENT + "No metrics available for this platform");
+            return;
+        }
+
+        ostream.println(INDENT + "Provider: " + c.getProvider());
+        ostream.println(INDENT + "Effective CPU Count: " + c.getEffectiveCpuCount());
+        ostream.println(INDENT + "CPU Period: " + c.getCpuPeriod() +
+               (c.getCpuPeriod() == -1 ? "" : "us"));
+        ostream.println(INDENT + "CPU Quota: " + c.getCpuQuota() +
+               (c.getCpuQuota() == -1 ? "" : "us"));
+        ostream.println(INDENT + "CPU Shares: " + c.getCpuShares());
+
+        int cpus[] = c.getCpuSetCpus();
+        ostream.println(INDENT + "List of Processors, "
+                + cpus.length + " total: ");
+
+        ostream.print(INDENT);
+        for (int i = 0; i < cpus.length; i++) {
+            ostream.print(cpus[i] + " ");
+        }
+        if (cpus.length > 0) {
+            ostream.println("");
+        }
+
+        cpus = c.getEffectiveCpuSetCpus();
+        ostream.println(INDENT + "List of Effective Processors, "
+                + cpus.length + " total: ");
+
+        ostream.print(INDENT);
+        for (int i = 0; i < cpus.length; i++) {
+            ostream.print(cpus[i] + " ");
+        }
+        if (cpus.length > 0) {
+            ostream.println("");
+        }
+
+        int mems[] = c.getCpuSetMems();
+        ostream.println(INDENT + "List of Memory Nodes, "
+                + mems.length + " total: ");
+
+        ostream.print(INDENT);
+        for (int i = 0; i < mems.length; i++) {
+            ostream.print(mems[i] + " ");
+        }
+        if (mems.length > 0) {
+            ostream.println("");
+        }
+
+        mems = c.getEffectiveCpuSetMems();
+        ostream.println(INDENT + "List of Available Memory Nodes, "
+                + mems.length + " total: ");
+
+        ostream.print(INDENT);
+        for (int i = 0; i < mems.length; i++) {
+            ostream.print(mems[i] + " ");
+        }
+        if (mems.length > 0) {
+            ostream.println("");
+        }
+
+        ostream.println(INDENT + "CPUSet Memory Pressure Enabled: "
+                + c.isCpuSetMemoryPressureEnabled());
+
+        long limit = c.getMemoryLimit();
+        ostream.println(INDENT + "Memory Limit: " +
+                ((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
+
+        limit = c.getMemorySoftLimit();
+        ostream.println(INDENT + "Memory Soft Limit: " +
+                ((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
+
+        limit = c.getMemoryAndSwapLimit();
+        ostream.println(INDENT + "Memory & Swap Limit: " +
+                ((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
+
+        limit = c.getKernelMemoryLimit();
+        ostream.println(INDENT + "Kernel Memory Limit: " +
+                ((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
+
+        limit = c.getTcpMemoryLimit();
+        ostream.println(INDENT + "TCP Memory Limit: " +
+                ((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
+
+        ostream.println(INDENT + "Out Of Memory Killer Enabled: "
+                + c.isMemoryOOMKillEnabled());
+
+        ostream.println("");
+    }
+
     private enum SizePrefix {
 
         KILO(1024, "K"),
--- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Tue Jun 12 18:44:01 2018 -0400
+++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Tue Jun 12 18:51:45 2018 -0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -150,7 +150,11 @@
 \                      show all locale related settings and continue\n\
 \    -XshowSettings:properties\n\
 \                      show all property settings and continue\n\
-\    -XshowSettings:vm show all vm related settings and continue\n\
+\    -XshowSettings:vm\n\
+\                      show all vm related settings and continue\n\
+\    -XshowSettings:system\n\
+\                      (Linux Only) show host system or container\n\
+\                      configuration and continue\n\
 \    -Xss<size>        set java thread stack size\n\
 \    -Xverify          sets the mode of the bytecode verifier\n\
 \    --add-reads <module>=<target-module>(,<target-module>)*\n\
--- a/test/hotspot/jtreg/runtime/containers/docker/CPUSetsReader.java	Tue Jun 12 18:44:01 2018 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.io.FileReader;
-import java.util.ArrayList;
-import java.util.Optional;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import jdk.test.lib.Asserts;
-
-
-// A simple CPU sets reader and parser
-public class CPUSetsReader {
-    public static String PROC_SELF_STATUS_PATH="/proc/self/status";
-
-    // Test the parser
-    public static void test() {
-        assertParse("0-7", "0,1,2,3,4,5,6,7");
-        assertParse("1,3,6", "1,3,6");
-        assertParse("0,2-4,6,10-11", "0,2,3,4,6,10,11");
-        assertParse("0", "0");
-    }
-
-
-    private static void assertParse(String cpuSet, String expectedResult) {
-        Asserts.assertEquals(listToString(parseCpuSet(cpuSet)), expectedResult);
-    }
-
-
-    public static String readFromProcStatus(String setType) {
-        String path = PROC_SELF_STATUS_PATH;
-        Optional<String> o = Optional.empty();
-
-        System.out.println("readFromProcStatus() entering for: " + setType);
-
-        try (Stream<String> stream = Files.lines(Paths.get(path))) {
-            o = stream
-                .filter(line -> line.contains(setType))
-                .findFirst();
-        } catch (IOException e) {
-            return null;
-        }
-
-        if (!o.isPresent()) {
-            return null;    // entry not found
-        }
-
-        String[] parts = o.get().replaceAll("\\s","").split(":");
-
-        // Should be 2 parts, before and after ":"
-        Asserts.assertEquals(parts.length, 2);
-
-        String result = parts[1];
-        System.out.println("readFromProcStatus() returning: " + result);
-        return result;
-    }
-
-
-    public static List<Integer> parseCpuSet(String value) {
-        ArrayList<Integer> result = new ArrayList<Integer>();
-
-        try {
-            String[] commaSeparated = value.split(",");
-
-            for (String item : commaSeparated) {
-                if (item.contains("-")) {
-                    addRange(result, item);
-                } else {
-                    result.add(Integer.parseInt(item));
-                }
-            }
-        } catch (Exception e) {
-            System.err.println("Exception in getMaxCpuSets(): " + e);
-            return null;
-        }
-
-        return result;
-    }
-
-
-    private static void addRange(ArrayList<Integer> list, String s) {
-        String[] range = s.split("-");
-        if ( range.length != 2 ) {
-            throw new RuntimeException("Range should only contain two items, but contains "
-                                       + range.length + " items");
-        }
-
-        int min = Integer.parseInt(range[0]);
-        int max = Integer.parseInt(range[1]);
-
-        if (min >= max) {
-            String msg = String.format("min is greater or equals to max, min = %d, max = %d",
-                                       min, max);
-            throw new RuntimeException(msg);
-        }
-
-        for (int i = min; i <= max; i++) {
-            list.add(i);
-        }
-    }
-
-
-    // Convert list of integers to string with comma-separated values
-    public static String listToString(List<Integer> list) {
-        return listToString(list, Integer.MAX_VALUE);
-    }
-
-    // Convert list of integers to a string with comma-separated values;
-    // include up to maxCount.
-    public static String listToString(List<Integer> list, int maxCount) {
-        return list.stream()
-            .limit(maxCount)
-            .map(Object::toString)
-            .collect(Collectors.joining(","));
-    }
-}
--- a/test/hotspot/jtreg/runtime/containers/docker/Common.java	Tue Jun 12 18:44:01 2018 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-/*
- * Methods and definitions common to docker tests container in this directory
- */
-
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import jdk.test.lib.containers.docker.DockerRunOptions;
-import jdk.test.lib.containers.docker.DockerTestUtils;
-import jdk.test.lib.Utils;
-import jdk.test.lib.process.OutputAnalyzer;
-
-
-public class Common {
-    public static final String imageNameAndTag = "jdk-internal:test";
-
-    public static String imageName(String suffix) {
-        return imageNameAndTag + "-" + suffix;
-    }
-
-
-    public static void prepareWhiteBox() throws Exception {
-        Files.copy(Paths.get(ClassFileInstaller.getJarPath("whitebox.jar")),
-                   Paths.get(Utils.TEST_CLASSES, "whitebox.jar"));
-    }
-
-
-    // create simple commonly used options
-    public static DockerRunOptions newOpts(String imageNameAndTag) {
-        return new DockerRunOptions(imageNameAndTag, "/jdk/bin/java", "-version")
-            .addJavaOpts("-Xlog:os+container=trace");
-    }
-
-
-    // create commonly used options with class to be launched inside container
-    public static DockerRunOptions newOpts(String imageNameAndTag, String testClass) {
-        DockerRunOptions opts =
-            new DockerRunOptions(imageNameAndTag, "/jdk/bin/java", testClass);
-        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
-        opts.addJavaOpts("-Xlog:os+container=trace", "-cp", "/test-classes/");
-        return opts;
-    }
-
-
-    public static DockerRunOptions addWhiteBoxOpts(DockerRunOptions opts) {
-        opts.addJavaOpts("-Xbootclasspath/a:/test-classes/whitebox.jar",
-                         "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI");
-        return opts;
-    }
-
-
-    // most common type of run and checks
-    public static OutputAnalyzer run(DockerRunOptions opts) throws Exception {
-        return DockerTestUtils.dockerRunJava(opts)
-            .shouldHaveExitValue(0).shouldContain("Initializing Container Support");
-    }
-
-
-    // log beginning of a test case
-    public static void logNewTestCase(String msg) {
-        System.out.println("========== NEW TEST CASE:      " + msg);
-    }
-
-}
--- a/test/hotspot/jtreg/runtime/containers/docker/TestCPUAwareness.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/hotspot/jtreg/runtime/containers/docker/TestCPUAwareness.java	Tue Jun 12 18:51:45 2018 -0400
@@ -30,13 +30,13 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @build Common
  * @run driver TestCPUAwareness
  */
 import java.util.List;
+import jdk.test.lib.containers.docker.Common;
 import jdk.test.lib.containers.docker.DockerRunOptions;
 import jdk.test.lib.containers.docker.DockerTestUtils;
-
+import jdk.test.lib.containers.cgroup.CPUSetsReader;
 
 public class TestCPUAwareness {
     private static final String imageName = Common.imageName("cpu");
--- a/test/hotspot/jtreg/runtime/containers/docker/TestCPUSets.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/hotspot/jtreg/runtime/containers/docker/TestCPUSets.java	Tue Jun 12 18:51:45 2018 -0400
@@ -31,13 +31,15 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @build Common AttemptOOM CPUSetsReader sun.hotspot.WhiteBox PrintContainerInfo
+ * @build AttemptOOM sun.hotspot.WhiteBox PrintContainerInfo
  * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run driver TestCPUSets
  */
 import java.util.List;
+import jdk.test.lib.containers.docker.Common;
 import jdk.test.lib.containers.docker.DockerRunOptions;
 import jdk.test.lib.containers.docker.DockerTestUtils;
+import jdk.test.lib.containers.cgroup.CPUSetsReader;
 import jdk.test.lib.Asserts;
 import jdk.test.lib.Platform;
 import jdk.test.lib.Utils;
--- a/test/hotspot/jtreg/runtime/containers/docker/TestMemoryAwareness.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/hotspot/jtreg/runtime/containers/docker/TestMemoryAwareness.java	Tue Jun 12 18:51:45 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,10 +30,11 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @build Common AttemptOOM sun.hotspot.WhiteBox PrintContainerInfo
+ * @build AttemptOOM sun.hotspot.WhiteBox PrintContainerInfo
  * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run driver TestMemoryAwareness
  */
+import jdk.test.lib.containers.docker.Common;
 import jdk.test.lib.containers.docker.DockerRunOptions;
 import jdk.test.lib.containers.docker.DockerTestUtils;
 
--- a/test/hotspot/jtreg/runtime/containers/docker/TestMisc.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/hotspot/jtreg/runtime/containers/docker/TestMisc.java	Tue Jun 12 18:51:45 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,12 +30,13 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @build Common CheckContainerized sun.hotspot.WhiteBox PrintContainerInfo
+ * @build CheckContainerized sun.hotspot.WhiteBox PrintContainerInfo
  * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run driver TestMisc
  */
+import jdk.test.lib.containers.docker.Common;
+import jdk.test.lib.containers.docker.DockerTestUtils;
 import jdk.test.lib.containers.docker.DockerRunOptions;
-import jdk.test.lib.containers.docker.DockerTestUtils;
 import jdk.test.lib.process.OutputAnalyzer;
 import jdk.test.lib.process.ProcessTools;
 
--- a/test/jdk/TEST.ROOT	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/jdk/TEST.ROOT	Tue Jun 12 18:51:45 2018 -0400
@@ -38,7 +38,8 @@
     sun.arch.data.model \
     java.runtime.name \
     vm.graal.enabled \
-    vm.cds
+    vm.cds \
+    docker.support
 
 # Minimum jtreg version
 requiredVersion=4.2 b12
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/cgroup/TestCgroupMetrics.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires os.family == "linux"
+ * @modules java.base/jdk.internal.platform
+ * @library /test/lib
+ * @run main TestCgroupMetrics
+ */
+
+import jdk.test.lib.containers.cgroup.MetricsTester;
+import jdk.internal.platform.Metrics;
+
+public class TestCgroupMetrics {
+
+    public static void main(String[] args) throws Exception {
+        // If cgroups is not configured, report success.
+        Metrics metrics = Metrics.systemMetrics();
+        if (metrics == null) {
+            System.out.println("TEST PASSED!!!");
+            return;
+        }
+
+        MetricsTester metricsTester = new MetricsTester();
+        metricsTester.setup();
+        metricsTester.testCpuAccounting();
+        metricsTester.testCpuSchedulingMetrics();
+        metricsTester.testCpuSets();
+        metricsTester.testMemorySubsystem();
+        metricsTester.testBlkIO();
+        metricsTester.testCpuConsumption();
+        metricsTester.testMemoryUsage();
+        System.out.println("TEST PASSED!!!");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,8 @@
+FROM oraclelinux:7.2
+MAINTAINER mikhailo.seledtsov@oracle.com
+
+COPY /jdk /jdk
+
+ENV JAVA_HOME=/jdk
+
+CMD ["/bin/bash"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-aarch64	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,8 @@
+# Use generic ubuntu Linux on AArch64
+FROM aarch64/ubuntu
+
+COPY /jdk /jdk
+
+ENV JAVA_HOME=/jdk
+
+CMD ["/bin/bash"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-ppc64le	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,10 @@
+# test on x86_64 uses Oracle Linux but we do not have this for ppc64le
+# so use some other Linux where OpenJDK works 
+# FROM oraclelinux:7.2
+FROM ppc64le/ubuntu
+
+COPY /jdk /jdk
+
+ENV JAVA_HOME=/jdk
+
+CMD ["/bin/bash"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-s390x	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,7 @@
+FROM s390x/ubuntu
+
+COPY /jdk /jdk
+
+ENV JAVA_HOME=/jdk
+
+CMD ["/bin/bash"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/MetricsCpuTester.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Arrays;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import jdk.internal.platform.Metrics;
+
+public class MetricsCpuTester {
+    public static void main(String[] args) {
+        System.out.println(Arrays.toString(args));
+        switch (args[0]) {
+            case "cpusets":
+                testCpuSets(args[1]);
+                break;
+            case "cpuquota":
+                testCpuQuotaAndPeriod(Long.parseLong(args[1]), Long.parseLong(args[2]));
+                break;
+            case "cpushares":
+                testCpuShares(Long.parseLong(args[1]));
+                break;
+            case "cpus":
+                testCpuThrottling();
+                break;
+            case "cpumems":
+                testCpuSetMemNodes(args[1]);
+                break;
+            case "combo":
+                testCombo(args[1], Long.parseLong(args[2]), Long.parseLong(args[3]), Long.parseLong(args[4]));
+                break;
+        }
+    }
+
+    private static void testCpuQuotaAndPeriod(long quota, long period) {
+        Metrics metrics = Metrics.systemMetrics();
+        long newQuota = metrics.getCpuQuota();
+        long newPeriod = metrics.getCpuPeriod();
+        if (quota != newQuota || period != newPeriod) {
+            throw new RuntimeException("CPU quota or period not equal, expected : ["
+                    + quota + "," + period + "]" + ", got : " + "[" + newQuota
+                    + "," + newPeriod + "]");
+        }
+
+        long cpuNumPeriods = metrics.getCpuNumPeriods();
+        long current = System.currentTimeMillis();
+        while (System.currentTimeMillis() - current < 1000) ;    // 1sec
+        long newCpuNumPeriods = metrics.getCpuNumPeriods();
+        if (newCpuNumPeriods <= cpuNumPeriods) {
+            throw new RuntimeException("CPU shares failed, expected : ["
+                    + cpuNumPeriods + "]" + ", got : " + "["
+                    + newCpuNumPeriods + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testCpuSets(String cpuset) {
+        int[] ipCpuSet;
+        String[] tokens = cpuset.split("-");
+        if (tokens.length > 1) { // we are given range of CPUs
+            ipCpuSet = IntStream.rangeClosed(Integer.parseInt(tokens[0]),
+                    Integer.parseInt(tokens[1])).toArray();
+        } else if (cpuset.split(",").length > 1) {   // list of cpus
+            ipCpuSet = Stream.of(cpuset.split(",")).mapToInt(Integer::parseInt).toArray();
+        } else { // just a single cpu
+            ipCpuSet = new int[]{Integer.parseInt(cpuset)};
+        }
+
+        Metrics metrics = Metrics.systemMetrics();
+        int[] cpuSets = metrics.getCpuSetCpus();
+
+        int[] effectiveCpus = metrics.getEffectiveCpuSetCpus();
+
+        if (!Arrays.equals(ipCpuSet, cpuSets)) {
+            throw new RuntimeException("Cpusets not equal, expected : "
+                    + Arrays.toString(ipCpuSet) + ", got : " + Arrays.toString(cpuSets));
+        }
+
+        if (!Arrays.equals(ipCpuSet, effectiveCpus)) {
+            throw new RuntimeException("Effective Cpusets not equal, expected : "
+                    + Arrays.toString(ipCpuSet) + ", got : "
+                    + Arrays.toString(effectiveCpus));
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testCpuSetMemNodes(String cpusetMems) {
+        Metrics metrics = Metrics.systemMetrics();
+        int[] cpuSets = metrics.getCpuSetMems();
+
+        int[] ipCpuSet;
+        String[] tokens = cpusetMems.split("-");
+        if (tokens.length > 1) { // we are given range of CPUs
+            ipCpuSet = IntStream.rangeClosed(Integer.parseInt(tokens[0]),
+                    Integer.parseInt(tokens[1])).toArray();
+        } else if (cpusetMems.split(",").length > 1) {   // list of cpus
+            ipCpuSet = Stream.of(cpusetMems.split(",")).mapToInt(Integer::parseInt).toArray();
+        } else { // just a single cpu
+            ipCpuSet = new int[]{Integer.parseInt(cpusetMems)};
+        }
+
+        int[] effectiveMems = metrics.getEffectiveCpuSetMems();
+
+
+        if (!Arrays.equals(ipCpuSet, cpuSets)) {
+            throw new RuntimeException("Cpuset.mems not equal, expected : "
+                    + Arrays.toString(ipCpuSet) + ", got : "
+                    + Arrays.toString(cpuSets));
+        }
+
+        if (!Arrays.equals(ipCpuSet, effectiveMems)) {
+            throw new RuntimeException("Effective mem nodes not equal, expected : "
+                    + Arrays.toString(ipCpuSet) + ", got : "
+                    + Arrays.toString(effectiveMems));
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testCpuShares(long shares) {
+        Metrics metrics = Metrics.systemMetrics();
+        long newShares = metrics.getCpuShares();
+        if (newShares != shares) {
+            throw new RuntimeException("CPU shares not equal, expected : ["
+                    + shares + "]" + ", got : " + "[" + newShares + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testCpuThrottling() {
+        Metrics metrics = Metrics.systemMetrics();
+        long throttledTime = metrics.getCpuThrottledTime();
+        long numThrottled = metrics.getCpuNumThrottled();
+
+        long current = System.currentTimeMillis();
+
+        while (System.currentTimeMillis() - current < 2000) ;  // 2 sec
+
+        long newthrottledTime = metrics.getCpuThrottledTime();
+        long newnumThrottled = metrics.getCpuNumThrottled();
+        if (newthrottledTime <= throttledTime) {
+            throw new RuntimeException("CPU throttle failed, expected : ["
+                    + newthrottledTime + "]" + ", got : "
+                    + "[" + throttledTime + "]");
+        }
+
+        if (newnumThrottled <= numThrottled) {
+            throw new RuntimeException("CPU num throttle failed, expected : ["
+                    + newnumThrottled + "]" + ", got : " + "["
+                    + numThrottled + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testCombo(String cpuset, long quota, long period, long shares) {
+        testCpuSets(cpuset);
+        testCpuQuotaAndPeriod(quota, period);
+        testCpuShares(shares);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Arrays;
+import jdk.internal.platform.Metrics;
+
+public class MetricsMemoryTester {
+    public static void main(String[] args) {
+        System.out.println(Arrays.toString(args));
+        switch (args[0]) {
+            case "memory":
+                testMemoryLimit(args[1]);
+                break;
+            case "memoryswap":
+                testMemoryAndSwapLimit(args[1], args[2]);
+                break;
+            case "kernelmem":
+                testKernelMemoryLimit(args[1]);
+                break;
+            case "oomkill":
+                testOomKillFlag(Boolean.parseBoolean(args[2]));
+                break;
+            case "failcount":
+                testMemoryFailCount();
+                break;
+            case "softlimit":
+                testMemorySoftLimit(args[1]);
+                break;
+        }
+    }
+
+    private static void testMemoryLimit(String value) {
+        long limit = getMemoryValue(value);
+
+        if (limit != Metrics.systemMetrics().getMemoryLimit()) {
+            throw new RuntimeException("Memory limit not equal, expected : ["
+                    + limit + "]" + ", got : ["
+                    + Metrics.systemMetrics().getMemoryLimit() + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testMemoryFailCount() {
+        long count = Metrics.systemMetrics().getMemoryFailCount();
+
+        // Allocate 512M of data
+        long[][] longs = new long[64][];
+        for (int i = 1; i <= 64; i++) {
+            try {
+                longs[i] = new long[8 * 1024 * 1024];
+            } catch (Error e) { // OOM error
+                break;
+            }
+        }
+        if (Metrics.systemMetrics().getMemoryFailCount() <= count) {
+            throw new RuntimeException("Memory fail count : new : ["
+                    + Metrics.systemMetrics().getMemoryFailCount() + "]"
+                    + ", old : [" + count + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testMemorySoftLimit(String softLimit) {
+
+        long memorySoftLimit = Metrics.systemMetrics().getMemorySoftLimit();
+        long newmemorySoftLimit = getMemoryValue(softLimit);
+
+        if (newmemorySoftLimit != memorySoftLimit) {
+            throw new RuntimeException("Memory softlimit not equal, Actual : ["
+                    + newmemorySoftLimit + "]" + ", Expected : ["
+                    + memorySoftLimit + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testKernelMemoryLimit(String value) {
+        long limit = getMemoryValue(value);
+        if (limit != Metrics.systemMetrics().getKernelMemoryLimit()) {
+            throw new RuntimeException("Kernel Memory limit not equal, expected : ["
+                    + limit + "]" + ", got : ["
+                    + Metrics.systemMetrics().getKernelMemoryLimit() + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static void testMemoryAndSwapLimit(String memory, String memAndSwap) {
+        long expectedMem = getMemoryValue(memory);
+        long expectedMemAndSwap = getMemoryValue(memAndSwap);
+
+        if (expectedMem != Metrics.systemMetrics().getMemoryLimit()
+                || expectedMemAndSwap != Metrics.systemMetrics().getMemoryAndSwapLimit()) {
+            System.err.println("Memory and swap limit not equal, expected : ["
+                    + expectedMem + ", " + expectedMemAndSwap + "]"
+                    + ", got : [" + Metrics.systemMetrics().getMemoryLimit()
+                    + ", " + Metrics.systemMetrics().getMemoryAndSwapLimit() + "]");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+
+    private static long getMemoryValue(String value) {
+        long result;
+        if (value.endsWith("m")) {
+            result = Long.parseLong(value.substring(0, value.length() - 1))
+                    * 1024 * 1024;
+        } else if (value.endsWith("g")) {
+            result = Long.parseLong(value.substring(0, value.length() - 1))
+                    * 1024 * 1024 * 1024;
+        } else {
+            result = Long.parseLong(value);
+        }
+        return result;
+    }
+
+    private static void testOomKillFlag(boolean oomKillFlag) {
+        if (!(oomKillFlag ^ Metrics.systemMetrics().isMemoryOOMKillEnabled())) {
+            throw new RuntimeException("oomKillFlag error");
+        }
+        System.out.println("TEST PASSED!!!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import jdk.internal.platform.Metrics;
+import jdk.test.lib.Utils;
+import jdk.test.lib.containers.cgroup.CPUSetsReader;
+import jdk.test.lib.containers.docker.Common;
+import jdk.test.lib.containers.docker.DockerRunOptions;
+import jdk.test.lib.containers.docker.DockerTestUtils;
+
+/*
+ * @test
+ * @summary Test JDK Metrics class when running inside docker container
+ * @requires docker.support
+ * @library /test/lib
+ * @modules java.base/jdk.internal.platform
+ * @build MetricsCpuTester
+ * @run main/timeout=360 TestDockerCpuMetrics
+ */
+
+public class TestDockerCpuMetrics {
+    private static final String imageName = Common.imageName("metrics-cpu");
+
+    public static void main(String[] args) throws Exception {
+        if (!DockerTestUtils.canTestDocker()) {
+            return;
+        }
+
+        // These tests create a docker image and run this image with
+        // varying docker cpu options.  The arguments passed to the docker
+        // container include the Java test class to be run along with the
+        // resource to be examined and expected result.
+
+        DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
+
+        try {
+            int numCpus = CPUSetsReader.getNumCpus();
+            testCpuSet("0");
+            testCpuSet("0-" + (numCpus - 1));
+            if (numCpus > 2) {
+                testCpuSet("0-" + ((numCpus - 1) / 2));
+                testCpuSet((((numCpus - 1) / 2) + 1) + "-" + (numCpus - 1));
+            }
+            testCpuSet(IntStream.range(0, numCpus).mapToObj(a -> Integer.toString(a)).collect(Collectors.joining(",")));
+
+            testCpuQuota(50 * 1000, 100 * 1000);
+            testCpuQuota(100 * 1000, 100 * 1000);
+            testCpuQuota(150 * 1000, 100 * 1000);
+            testCpuQuota(400 * 1000, 100 * 1000);
+
+            testCpuShares(256);
+            testCpuShares(2048);
+            testCpuShares(4096);
+
+            testCpuThrottling(0.5);// --cpus=<value>
+
+            int[] cpuSetMems = Metrics.systemMetrics().getCpuSetMems();
+            String memNodes = null;
+            if (cpuSetMems.length > 1) {
+                int endNode = (cpuSetMems[cpuSetMems.length - 1] - cpuSetMems[0]) / 2 + cpuSetMems[0];
+                memNodes = cpuSetMems[0] + "-" + endNode;
+            } else if (cpuSetMems.length == 1) {
+                memNodes = cpuSetMems[0] + "";
+            }
+
+            if(memNodes != null)
+                testCpuSetMems(memNodes);
+
+            testComboOptions("0-" + (numCpus - 1), 200 * 1000, 100 * 1000, 4 * 1024);
+            testComboOptions("0", 200 * 1000, 100 * 1000, 1023);
+        } finally {
+            DockerTestUtils.removeDockerImage(imageName);
+        }
+    }
+
+    private static void testCpuSetMems(String value) throws Exception {
+        Common.logNewTestCase("testCpuSetMems, mem nodes = " + value);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsCpuTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+        opts.addDockerOpts("--cpuset-mems=" + value);
+        opts.addJavaOpts("-cp", "/test-classes/").addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED");
+        opts.addClassOptions("cpumems", value);
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testCpuSet(String value) throws Exception {
+        Common.logNewTestCase("testCpuSet, value = " + value);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsCpuTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+        opts.addJavaOpts("-cp", "/test-classes/");
+        opts.addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED");
+        opts.addClassOptions("cpusets", value);
+        opts.addDockerOpts("--cpuset-cpus=" + value);
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testCpuQuota(long quota, long period) throws Exception {
+        Common.logNewTestCase("testCpuQuota, quota = " + quota + ", period = " + period);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsCpuTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+        opts.addDockerOpts("--cpu-period=" + period).addDockerOpts("--cpu-quota=" + quota);
+        opts.addJavaOpts("-cp", "/test-classes/").addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED");
+        opts.addClassOptions("cpuquota", quota + "", period + "");
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testCpuShares(int shares) throws Exception {
+        Common.logNewTestCase("testCpuShares, shares = " + shares);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsCpuTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+        opts.addDockerOpts("--cpu-shares=" + shares);
+        opts.addJavaOpts("-cp", "/test-classes/").addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED");
+        opts.addClassOptions("cpushares", shares + "");
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testCpuThrottling(double cpus) throws Exception {
+        Common.logNewTestCase("testCpuThrottling, cpus = " + cpus);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsCpuTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+        opts.addDockerOpts("--cpus=" + cpus);
+        opts.addJavaOpts("-cp", "/test-classes/").addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED");
+        opts.addClassOptions("cpus", cpus + "");
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testComboOptions(String cpuset, int quota, int period, int shares) throws Exception {
+        Common.logNewTestCase("testComboOptions, shares = " + shares);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsCpuTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+        opts.addDockerOpts("--cpuset-cpus", "" + cpuset)
+                .addDockerOpts("--cpu-period=" + period)
+                .addDockerOpts("--cpu-quota=" + quota)
+                .addDockerOpts("--cpu-shares=" + shares);
+        opts.addJavaOpts("-cp", "/test-classes/").addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED");
+        opts.addClassOptions("combo", cpuset, quota + "", period + "", shares + "");
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.test.lib.Utils;
+import jdk.test.lib.containers.docker.Common;
+import jdk.test.lib.containers.docker.DockerRunOptions;
+import jdk.test.lib.containers.docker.DockerTestUtils;
+
+/*
+ * @test
+ * @summary Test JDK Metrics class when running inside docker container
+ * @requires docker.support
+ * @library /test/lib
+ * @modules java.base/jdk.internal.platform
+ * @build MetricsMemoryTester
+ * @run main/timeout=360 TestDockerMemoryMetrics
+ */
+
+public class TestDockerMemoryMetrics {
+    private static final String imageName = Common.imageName("metrics-memory");
+
+    public static void main(String[] args) throws Exception {
+        if (!DockerTestUtils.canTestDocker()) {
+            return;
+        }
+
+        // These tests create a docker image and run this image with
+        // varying docker memory options.  The arguments passed to the docker
+        // container include the Java test class to be run along with the
+        // resource to be examined and expected result.
+
+        DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
+        try {
+            testMemoryLimit("200m");
+            testMemoryLimit("1g");
+
+            testMemoryAndSwapLimit("200m", "1g");
+            testMemoryAndSwapLimit("100m", "200m");
+
+            testKernelMemoryLimit("100m");
+            testKernelMemoryLimit("1g");
+
+            testOomKillFlag("100m", false);
+            testOomKillFlag("100m", true);
+
+            testMemoryFailCount("20m");
+
+            testMemorySoftLimit("500m","200m");
+
+        } finally {
+            DockerTestUtils.removeDockerImage(imageName);
+        }
+    }
+
+    private static void testMemoryLimit(String value) throws Exception {
+        Common.logNewTestCase("testMemoryLimit, value = " + value);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsMemoryTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
+                .addDockerOpts("--memory=" + value)
+                .addJavaOpts("-cp", "/test-classes/")
+                .addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED")
+                .addClassOptions("memory", value);
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testMemoryFailCount(String value) throws Exception {
+        Common.logNewTestCase("testMemoryFailCount" + value);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsMemoryTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
+                .addDockerOpts("--memory=" + value)
+                .addJavaOpts("-cp", "/test-classes/")
+                .addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED")
+                .addClassOptions("failcount");
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testMemoryAndSwapLimit(String memory, String memandswap) throws Exception {
+        Common.logNewTestCase("testMemoryAndSwapLimit, memory = " + memory + ", memory and swap = " + memandswap);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsMemoryTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
+                .addDockerOpts("--memory=" + memory)
+                .addDockerOpts("--memory-swap=" + memandswap)
+                .addJavaOpts("-cp", "/test-classes/")
+                .addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED")
+                .addClassOptions("memoryswap", memory, memandswap);
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testKernelMemoryLimit(String value) throws Exception {
+        Common.logNewTestCase("testKernelMemoryLimit, value = " + value);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsMemoryTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
+                .addDockerOpts("--kernel-memory=" + value)
+                .addJavaOpts("-cp", "/test-classes/")
+                .addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED")
+                .addClassOptions("kernelmem", value);
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testOomKillFlag(String value, boolean oomKillFlag) throws Exception {
+        Common.logNewTestCase("testOomKillFlag, oomKillFlag = " + oomKillFlag);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsMemoryTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
+                .addDockerOpts("--memory=" + value);
+        if (!oomKillFlag) {
+            opts.addDockerOpts("--oom-kill-disable");
+        }
+        opts.addJavaOpts("-cp", "/test-classes/")
+                .addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED")
+                .addClassOptions("memory", value, oomKillFlag + "");
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+
+    private static void testMemorySoftLimit(String mem, String softLimit) throws Exception {
+        Common.logNewTestCase("testMemorySoftLimit, memory = " + mem + ", soft limit = " + softLimit);
+        DockerRunOptions opts =
+                new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsMemoryTester");
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
+                .addDockerOpts("--memory=" + mem)
+                .addDockerOpts("--memory-reservation=" + softLimit);
+        opts.addJavaOpts("-cp", "/test-classes/")
+                .addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED")
+                .addClassOptions("softlimit", softLimit);
+        DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test JDK Metrics class when running inside docker container
+ * @requires docker.support
+ * @library /test/lib
+ * @modules java.base/jdk.internal.platform
+ * @run main TestSystemMetrics
+ */
+
+import jdk.test.lib.Utils;
+import jdk.test.lib.containers.docker.Common;
+import jdk.test.lib.containers.docker.DockerRunOptions;
+import jdk.test.lib.containers.docker.DockerTestUtils;
+import jdk.test.lib.containers.cgroup.MetricsTester;
+
+public class TestSystemMetrics {
+    private static final String imageName = Common.imageName("metrics");
+
+    public static void main(String[] args) throws Exception {
+        if (!DockerTestUtils.canTestDocker()) {
+            return;
+        }
+
+        DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
+
+        try {
+            Common.logNewTestCase("Test SystemMetrics");
+            DockerRunOptions opts =
+                    new DockerRunOptions(imageName, "/jdk/bin/java", "jdk.test.lib.containers.cgroup.MetricsTester");
+            opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+            opts.addJavaOpts("-cp", "/test-classes/");
+            opts.addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED");
+            DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
+        } finally {
+            DockerTestUtils.removeDockerImage(imageName);
+        }
+    }
+}
--- a/test/jdk/tools/launcher/Settings.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/jdk/tools/launcher/Settings.java	Tue Jun 12 18:51:45 2018 -0400
@@ -67,11 +67,15 @@
     private static final String VM_SETTINGS = "VM settings:";
     private static final String PROP_SETTINGS = "Property settings:";
     private static final String LOCALE_SETTINGS = "Locale settings:";
+    private static final String SYSTEM_SETTINGS = "Operating System Metrics:";
 
     static void containsAllOptions(TestResult tr) {
         checkContains(tr, VM_SETTINGS);
         checkContains(tr, PROP_SETTINGS);
         checkContains(tr, LOCALE_SETTINGS);
+        if (System.getProperty("os.name").contains("Linux")) {
+            checkContains(tr, SYSTEM_SETTINGS);
+        }
     }
 
     static void runTestOptionDefault() throws IOException {
@@ -123,6 +127,20 @@
         checkContains(tr, LOCALE_SETTINGS);
     }
 
+    static void runTestOptionSystem() throws IOException {
+        TestResult tr = doExec(javaCmd, "-XshowSettings:system");
+        if (System.getProperty("os.name").contains("Linux")) {
+            checkNotContains(tr, VM_SETTINGS);
+            checkNotContains(tr, PROP_SETTINGS);
+            checkNotContains(tr, LOCALE_SETTINGS);
+            checkContains(tr, SYSTEM_SETTINGS);
+        } else {
+            // -XshowSettings prints all available settings when
+            // settings argument is not recognized.
+            containsAllOptions(tr);
+        }
+    }
+
     static void runTestBadOptions() throws IOException {
         TestResult tr = doExec(javaCmd, "-XshowSettingsBadOption");
         checkNotContains(tr, VM_SETTINGS);
@@ -146,6 +164,7 @@
         runTestOptionVM();
         runTestOptionProperty();
         runTestOptionLocale();
+        runTestOptionSystem();
         runTestBadOptions();
         runTest7123582();
         if (testExitValue != 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/containers/cgroup/CPUSetsReader.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.containers.cgroup;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import jdk.test.lib.Asserts;
+
+
+// A simple CPU sets reader and parser
+public class CPUSetsReader {
+    public static String PROC_SELF_STATUS_PATH = "/proc/self/status";
+
+    // Test the parser
+    public static void test() {
+        assertParse("0-7", "0,1,2,3,4,5,6,7");
+        assertParse("1,3,6", "1,3,6");
+        assertParse("0,2-4,6,10-11", "0,2,3,4,6,10,11");
+        assertParse("0", "0");
+    }
+
+
+    private static void assertParse(String cpuSet, String expectedResult) {
+        Asserts.assertEquals(listToString(parseCpuSet(cpuSet)), expectedResult);
+    }
+
+    public static int getNumCpus() {
+        String path = "/proc/cpuinfo";
+        try {
+            Stream<String> stream = Files.lines(Paths.get(path));
+            return (int) stream.filter(line -> line.startsWith("processor")).count();
+        } catch (IOException e) {
+            return 0;
+        }
+    }
+
+
+    public static String readFromProcStatus(String setType) {
+        String path = PROC_SELF_STATUS_PATH;
+        Optional<String> o = Optional.empty();
+
+        System.out.println("readFromProcStatus() entering for: " + setType);
+
+        try (Stream<String> stream = Files.lines(Paths.get(path))) {
+            o = stream
+                    .filter(line -> line.contains(setType))
+                    .findFirst();
+        } catch (IOException e) {
+            return null;
+        }
+
+        if (!o.isPresent()) {
+            return null;    // entry not found
+        }
+
+        String[] parts = o.get().replaceAll("\\s", "").split(":");
+
+        // Should be 2 parts, before and after ":"
+        Asserts.assertEquals(parts.length, 2);
+
+        String result = parts[1];
+        System.out.println("readFromProcStatus() returning: " + result);
+        return result;
+    }
+
+
+    public static List<Integer> parseCpuSet(String value) {
+        ArrayList<Integer> result = new ArrayList<Integer>();
+
+        try {
+            String[] commaSeparated = value.split(",");
+
+            for (String item : commaSeparated) {
+                if (item.contains("-")) {
+                    addRange(result, item);
+                } else {
+                    result.add(Integer.parseInt(item));
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("Exception in getMaxCpuSets(): " + e);
+            return null;
+        }
+
+        return result;
+    }
+
+    private static void addRange(ArrayList<Integer> list, String s) {
+        String[] range = s.split("-");
+        if (range.length != 2) {
+            throw new RuntimeException("Range should only contain two items, but contains "
+                    + range.length + " items");
+        }
+
+        int min = Integer.parseInt(range[0]);
+        int max = Integer.parseInt(range[1]);
+
+        if (min >= max) {
+            String msg = String.format("min is greater or equals to max, min = %d, max = %d",
+                    min, max);
+            throw new RuntimeException(msg);
+        }
+
+        for (int i = min; i <= max; i++) {
+            list.add(i);
+        }
+    }
+
+
+    // Convert list of integers to string with comma-separated values
+    public static String listToString(List<Integer> list) {
+        return listToString(list, Integer.MAX_VALUE);
+    }
+
+    // Convert list of integers to a string with comma-separated values;
+    // include up to maxCount.
+    public static String listToString(List<Integer> list, int maxCount) {
+        return list.stream()
+                .limit(maxCount)
+                .map(Object::toString)
+                .collect(Collectors.joining(","));
+    }
+
+    public static String numberToString(int num) {
+        return IntStream.range(0, num).boxed().map(Object::toString).collect(Collectors.joining(","));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.containers.cgroup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import jdk.internal.platform.Metrics;
+
+public class MetricsTester {
+
+    private static final double ERROR_MARGIN = 0.1;
+    private static long unlimited_minimum = 0x7FFFFFFFFF000000L;
+    long startSysVal;
+    long startUserVal;
+    long startUsage;
+    long startPerCpu[];
+
+    enum SubSystem {
+        MEMORY("memory"),
+        CPUSET("cpuset"),
+        CPU("cpu"),
+        CPUACCT("cpuacct"),
+        BLKIO("blkio");
+
+        private String value;
+
+        SubSystem(String value) {
+            this.value = value;
+        }
+
+        public String value() {
+            return value;
+        }
+    }
+
+    private static final Set<String> allowedSubSystems =
+            Stream.of(SubSystem.values()).map(SubSystem::value).collect(Collectors.toSet());
+
+    private static final Map<String, String[]> subSystemPaths = new HashMap<>();
+
+    private static void setPath(String[] line) {
+        String cgroupPath = line[2];
+        String[] subSystems = line[1].split(",");
+
+        for (String subSystem : subSystems) {
+            if (allowedSubSystems.contains(subSystem)) {
+                String[] paths = subSystemPaths.get(subSystem);
+                String finalPath = "";
+                String root = paths[0];
+                String mountPoint = paths[1];
+                if (root != null && cgroupPath != null) {
+                    if (root.equals("/")) {
+                        if (cgroupPath.equals("/")) {
+                            finalPath = mountPoint + cgroupPath;
+                        } else {
+                            finalPath = mountPoint;
+                        }
+                    } else {
+                        if (root.equals(cgroupPath)) {
+                            finalPath = mountPoint;
+                        } else {
+                            if (root.indexOf(cgroupPath) == 0) {
+                                if (cgroupPath.length() > root.length()) {
+                                    String cgroupSubstr = cgroupPath.substring(root.length());
+                                    finalPath = mountPoint + cgroupSubstr;
+                                }
+                            }
+                        }
+                    }
+                }
+                subSystemPaths.put(subSystem, new String[]{finalPath});
+            }
+        }
+    }
+
+    private static void createSubsystems(String[] line) {
+        if (line.length < 5) return;
+        Path p = Paths.get(line[4]);
+        String subsystemName = p.getFileName().toString();
+        if (subsystemName != null) {
+            for (String subSystem : subsystemName.split(",")) {
+                if (allowedSubSystems.contains(subSystem)) {
+                    subSystemPaths.put(subSystem, new String[]{line[3], line[4]});
+                }
+            }
+        }
+    }
+
+    public void setup() {
+        Metrics metrics = Metrics.systemMetrics();
+        // Initialize CPU usage metrics before we do any testing.
+        startSysVal = metrics.getCpuSystemUsage();
+        startUserVal = metrics.getCpuUserUsage();
+        startUsage = metrics.getCpuUsage();
+        startPerCpu = metrics.getPerCpuUsage();
+
+        try {
+            Stream<String> lines = Files.lines(Paths.get("/proc/self/mountinfo"));
+            lines.filter(line -> line.contains(" - cgroup cgroup "))
+                    .map(line -> line.split(" "))
+                    .forEach(MetricsTester::createSubsystems);
+            lines.close();
+
+            lines = Files.lines(Paths.get("/proc/self/cgroup"));
+            lines.map(line -> line.split(":"))
+                    .filter(line -> (line.length >= 3))
+                    .forEach(MetricsTester::setPath);
+            lines.close();
+        } catch (IOException e) {
+        }
+    }
+
+    private static String getFileContents(SubSystem subSystem, String fileName) {
+        String fname = subSystemPaths.get(subSystem.value())[0] + File.separator + fileName;
+        try {
+            return new Scanner(new File(fname)).useDelimiter("\\Z").next();
+        } catch (FileNotFoundException e) {
+            System.err.println("Unale to open : " + fname);
+            return "";
+        }
+    }
+
+    private static long getLongValueFromFile(SubSystem subSystem, String fileName) {
+        String data = getFileContents(subSystem, fileName);
+        return data.isEmpty() ? 0L : Long.parseLong(data);
+    }
+
+    private static long getLongValueFromFile(SubSystem subSystem, String metric, String subMetric) {
+        String stats = getFileContents(subSystem, metric);
+        String[] tokens = stats.split("[\\r\\n]+");
+        for (int i = 0; i < tokens.length; i++) {
+            if (tokens[i].startsWith(subMetric)) {
+                return Long.parseLong(tokens[i].split("\\s+")[1]);
+            }
+        }
+        return 0L;
+    }
+
+    private static double getDoubleValueFromFile(SubSystem subSystem, String fileName) {
+        String data = getFileContents(subSystem, fileName);
+        return data.isEmpty() ? 0.0 : Double.parseDouble(data);
+    }
+
+    private boolean compareWithErrorMargin(long oldVal, long newVal) {
+        return Math.abs(oldVal - newVal) <= Math.abs(oldVal * ERROR_MARGIN);
+    }
+
+    private boolean compareWithErrorMargin(double oldVal, double newVal) {
+        return Math.abs(oldVal - newVal) <= Math.abs(oldVal * ERROR_MARGIN);
+    }
+
+    private static void fail(SubSystem system, String metric, long oldVal, long testVal) {
+        throw new RuntimeException("Test failed for - " + system.value + ":"
+                + metric + ", expected [" + oldVal + "], got [" + testVal + "]");
+    }
+
+    private static void fail(SubSystem system, String metric, String oldVal, String testVal) {
+        throw new RuntimeException("Test failed for - " + system.value + ":"
+                + metric + ", expected [" + oldVal + "], got [" + testVal + "]");
+    }
+
+    private static void fail(SubSystem system, String metric, double oldVal, double testVal) {
+        throw new RuntimeException("Test failed for - " + system.value + ":"
+                + metric + ", expected [" + oldVal + "], got [" + testVal + "]");
+    }
+
+    private static void fail(SubSystem system, String metric, boolean oldVal, boolean testVal) {
+        throw new RuntimeException("Test failed for - " + system.value + ":"
+                + metric + ", expected [" + oldVal + "], got [" + testVal + "]");
+    }
+
+    private static void warn(SubSystem system, String metric, long oldVal, long testVal) {
+        System.err.println("Warning - " + system.value + ":" + metric
+                + ", expected [" + oldVal + "], got [" + testVal + "]");
+    }
+
+    public void testMemorySubsystem() {
+        Metrics metrics = Metrics.systemMetrics();
+
+        // User Memory
+        long oldVal = metrics.getMemoryFailCount();
+        long newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.failcnt");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.failcnt", oldVal, newVal);
+        }
+
+        oldVal = metrics.getMemoryLimit();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.limit_in_bytes");
+        newVal = newVal > unlimited_minimum ? -1L : newVal;
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.limit_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getMemoryMaxUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.max_usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.max_usage_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getMemoryUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.usage_in_bytes", oldVal, newVal);
+        }
+
+        // Kernel memory
+        oldVal = metrics.getKernelMemoryFailCount();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.failcnt");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.failcnt", oldVal, newVal);
+        }
+
+        oldVal = metrics.getKernelMemoryLimit();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.limit_in_bytes");
+        newVal = newVal > unlimited_minimum ? -1L : newVal;
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.limit_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getKernelMemoryMaxUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.max_usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.max_usage_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getKernelMemoryUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.usage_in_bytes", oldVal, newVal);
+        }
+
+        //TCP Memory
+        oldVal = metrics.getTcpMemoryFailCount();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.tcp.failcnt");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.tcp.failcnt", oldVal, newVal);
+        }
+
+        oldVal = metrics.getTcpMemoryLimit();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.tcp.limit_in_bytes");
+        newVal = newVal > unlimited_minimum ? -1L : newVal;
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.tcp.limit_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getTcpMemoryMaxUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.tcp.max_usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.tcp.max_usage_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getTcpMemoryUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.kmem.tcp.usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.kmem.tcp.usage_in_bytes", oldVal, newVal);
+        }
+
+        //  Memory and Swap
+        oldVal = metrics.getMemoryAndSwapFailCount();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.memsw.failcnt");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.memsw.failcnt", oldVal, newVal);
+        }
+
+        oldVal = metrics.getMemoryAndSwapLimit();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.memsw.limit_in_bytes");
+        newVal = newVal > unlimited_minimum ? -1L : newVal;
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.memsw.limit_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getMemoryAndSwapMaxUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.memsw.max_usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.memsw.max_usage_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getMemoryAndSwapUsage();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.memsw.usage_in_bytes");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.memsw.usage_in_bytes", oldVal, newVal);
+        }
+
+        oldVal = metrics.getMemorySoftLimit();
+        newVal = getLongValueFromFile(SubSystem.MEMORY, "memory.soft_limit_in_bytes");
+        newVal = newVal > unlimited_minimum ? -1L : newVal;
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.MEMORY, "memory.soft_limit_in_bytes", oldVal, newVal);
+        }
+
+        boolean oomKillEnabled = metrics.isMemoryOOMKillEnabled();
+        boolean newOomKillEnabled = getLongValueFromFile(SubSystem.MEMORY,
+                "memory.oom_control", "oom_kill_disable") == 0L ? true : false;
+        if (oomKillEnabled != newOomKillEnabled) {
+            throw new RuntimeException("Test failed for - " + SubSystem.MEMORY.value + ":"
+                    + "memory.oom_control:oom_kill_disable" + ", expected ["
+                    + oomKillEnabled + "], got [" + newOomKillEnabled + "]");
+        }
+    }
+
+    public void testCpuAccounting() {
+        Metrics metrics = Metrics.systemMetrics();
+        long oldVal = metrics.getCpuUsage();
+        long newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpuacct.usage");
+
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            warn(SubSystem.CPUACCT, "cpuacct.usage", oldVal, newVal);
+        }
+
+        Long[] newVals = Stream.of(getFileContents(SubSystem.CPUACCT, "cpuacct.usage_percpu")
+                .split("\\s+"))
+                .map(Long::parseLong)
+                .toArray(Long[]::new);
+        Long[] oldVals = LongStream.of(metrics.getPerCpuUsage()).boxed().toArray(Long[]::new);
+        for (int i = 0; i < oldVals.length; i++) {
+            if (!compareWithErrorMargin(oldVals[i], newVals[i])) {
+                warn(SubSystem.CPUACCT, "cpuacct.usage_percpu", oldVals[i], newVals[i]);
+            }
+        }
+
+        oldVal = metrics.getCpuUserUsage();
+        newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpuacct.stat", "user");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            warn(SubSystem.CPUACCT, "cpuacct.usage - user", oldVal, newVal);
+        }
+
+        oldVal = metrics.getCpuSystemUsage();
+        newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpuacct.stat", "system");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            warn(SubSystem.CPUACCT, "cpuacct.usage - system", oldVal, newVal);
+        }
+    }
+
+    public void testCpuSchedulingMetrics() {
+        Metrics metrics = Metrics.systemMetrics();
+        long oldVal = metrics.getCpuPeriod();
+        long newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpu.cfs_period_us");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.CPUACCT, "cpu.cfs_period_us", oldVal, newVal);
+        }
+
+        oldVal = metrics.getCpuQuota();
+        newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpu.cfs_quota_us");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.CPUACCT, "cpu.cfs_quota_us", oldVal, newVal);
+        }
+
+        oldVal = metrics.getCpuShares();
+        newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpu.shares");
+        if (newVal == 0 || newVal == 1024) newVal = -1;
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.CPUACCT, "cpu.shares", oldVal, newVal);
+        }
+
+        oldVal = metrics.getCpuNumPeriods();
+        newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpu.stat", "nr_periods");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.CPUACCT, "cpu.stat - nr_periods", oldVal, newVal);
+        }
+
+        oldVal = metrics.getCpuNumThrottled();
+        newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpu.stat", "nr_throttled");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.CPUACCT, "cpu.stat - nr_throttled", oldVal, newVal);
+        }
+
+        oldVal = metrics.getCpuThrottledTime();
+        newVal = getLongValueFromFile(SubSystem.CPUACCT, "cpu.stat", "throttled_time");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.CPUACCT, "cpu.stat - throttled_time", oldVal, newVal);
+        }
+    }
+
+    public void testCpuSets() {
+        Metrics metrics = Metrics.systemMetrics();
+        Integer[] oldVal = Arrays.stream(metrics.getCpuSetCpus()).boxed().toArray(Integer[]::new);
+        Arrays.sort(oldVal);
+
+        String cpusstr = getFileContents(SubSystem.CPUSET, "cpuset.cpus");
+        // Parse range string in the format 1,2-6,7
+        Integer[] newVal = Stream.of(cpusstr.split(",")).flatMap(a -> {
+            if (a.contains("-")) {
+                String[] range = a.split("-");
+                return IntStream.rangeClosed(Integer.parseInt(range[0]),
+                        Integer.parseInt(range[1])).boxed();
+            } else {
+                return Stream.of(Integer.parseInt(a));
+            }
+        }).toArray(Integer[]::new);
+        Arrays.sort(newVal);
+        if (Arrays.compare(oldVal, newVal) != 0) {
+            fail(SubSystem.CPUSET, "cpuset.cpus", Arrays.toString(oldVal),
+                Arrays.toString(newVal));
+        }
+
+
+        oldVal = Arrays.stream(metrics.getEffectiveCpuSetCpus()).boxed().toArray(Integer[]::new);
+        Arrays.sort(oldVal);
+
+        cpusstr = getFileContents(SubSystem.CPUSET, "cpuset.effective_cpus");
+        newVal = Stream.of(cpusstr.split(",")).flatMap(a -> {
+            if (a.contains("-")) {
+                String[] range = a.split("-");
+                return IntStream.rangeClosed(Integer.parseInt(range[0]),
+                        Integer.parseInt(range[1])).boxed();
+            } else {
+                return Stream.of(Integer.parseInt(a));
+            }
+        }).toArray(Integer[]::new);
+        Arrays.sort(newVal);
+        if (Arrays.compare(oldVal, newVal) != 0) {
+            fail(SubSystem.CPUSET, "cpuset.effective_cpus", Arrays.toString(oldVal),
+                    Arrays.toString(newVal));
+        }
+
+        oldVal = Arrays.stream(metrics.getCpuSetMems()).boxed().toArray(Integer[]::new);
+        Arrays.sort(oldVal);
+        cpusstr = getFileContents(SubSystem.CPUSET, "cpuset.mems");
+        newVal = Stream.of(cpusstr.split(",")).flatMap(a -> {
+            if (a.contains("-")) {
+                String[] range = a.split("-");
+                return IntStream.rangeClosed(Integer.parseInt(range[0]),
+                        Integer.parseInt(range[1])).boxed();
+            } else {
+                return Stream.of(Integer.parseInt(a));
+            }
+        }).toArray(Integer[]::new);
+        Arrays.sort(newVal);
+        if (Arrays.compare(oldVal, newVal) != 0) {
+            fail(SubSystem.CPUSET, "cpuset.mems", Arrays.toString(oldVal),
+                    Arrays.toString(newVal));
+        }
+
+        oldVal = Arrays.stream(metrics.getEffectiveCpuSetMems()).boxed().toArray(Integer[]::new);
+        Arrays.sort(oldVal);
+        cpusstr = getFileContents(SubSystem.CPUSET, "cpuset.effective_mems");
+        newVal = Stream.of(cpusstr.split(",")).flatMap(a -> {
+            if (a.contains("-")) {
+                String[] range = a.split("-");
+                return IntStream.rangeClosed(Integer.parseInt(range[0]),
+                        Integer.parseInt(range[1])).boxed();
+            } else {
+                return Stream.of(Integer.parseInt(a));
+            }
+        }).toArray(Integer[]::new);
+        Arrays.sort(newVal);
+        if (Arrays.compare(oldVal, newVal) != 0) {
+            fail(SubSystem.CPUSET, "cpuset.effective_mems", Arrays.toString(oldVal),
+                    Arrays.toString(newVal));
+        }
+
+        double oldValue = metrics.getCpuSetMemoryPressure();
+        double newValue = getDoubleValueFromFile(SubSystem.CPUSET, "cpuset.memory_pressure");
+        if (!compareWithErrorMargin(oldValue, newValue)) {
+            fail(SubSystem.CPUSET, "cpuset.memory_pressure", oldValue, newValue);
+        }
+
+        boolean oldV = metrics.isCpuSetMemoryPressureEnabled();
+        boolean newV = getLongValueFromFile(SubSystem.CPUSET,
+                "cpuset.memory_pressure_enabled") == 1 ? true : false;
+        if (oldV != newV) {
+            fail(SubSystem.CPUSET, "cpuset.memory_pressure_enabled", oldV, newV);
+        }
+    }
+
+    public void testBlkIO() {
+        Metrics metrics = Metrics.systemMetrics();
+            long oldVal = metrics.getBlkIOServiceCount();
+        long newVal = getLongValueFromFile(SubSystem.BLKIO,
+                "blkio.throttle.io_service_bytes", "Total");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.BLKIO, "blkio.throttle.io_service_bytes - Total",
+                    oldVal, newVal);
+        }
+
+        oldVal = metrics.getBlkIOServiced();
+        newVal = getLongValueFromFile(SubSystem.BLKIO, "blkio.throttle.io_serviced", "Total");
+        if (!compareWithErrorMargin(oldVal, newVal)) {
+            fail(SubSystem.BLKIO, "blkio.throttle.io_serviced - Total", oldVal, newVal);
+        }
+    }
+
+    public void testCpuConsumption() throws IOException, InterruptedException {
+        Metrics metrics = Metrics.systemMetrics();
+        // make system call
+        long newSysVal = metrics.getCpuSystemUsage();
+        long newUserVal = metrics.getCpuUserUsage();
+        long newUsage = metrics.getCpuUsage();
+        long[] newPerCpu = metrics.getPerCpuUsage();
+
+        if (newSysVal <= startSysVal) {
+            fail(SubSystem.CPU, "getCpuSystemUsage", newSysVal, startSysVal);
+        }
+
+        if (newUserVal <= startUserVal) {
+            fail(SubSystem.CPU, "getCpuUserUsage", newUserVal, startUserVal);
+        }
+
+        if (newUsage <= startUsage) {
+            fail(SubSystem.CPU, "getCpuUserUsage", newUsage, startUsage);
+        }
+
+        boolean success = false;
+        for (int i = 0; i < startPerCpu.length; i++) {
+            if (newPerCpu[i] > startPerCpu[i]) {
+                success = true;
+                break;
+            }
+        }
+
+        if(!success) fail(SubSystem.CPU, "getPerCpuUsage", Arrays.toString(newPerCpu),
+                Arrays.toString(startPerCpu));
+    }
+
+    public void testMemoryUsage() throws Exception {
+        Metrics metrics = Metrics.systemMetrics();
+        long memoryMaxUsage = metrics.getMemoryMaxUsage();
+        long memoryUsage = metrics.getMemoryUsage();
+
+        long[] ll = new long[64*1024*1024]; // 64M
+
+        long newMemoryMaxUsage = metrics.getMemoryMaxUsage();
+        long newMemoryUsage = metrics.getMemoryUsage();
+
+        if(newMemoryMaxUsage < memoryMaxUsage) {
+            fail(SubSystem.MEMORY, "getMemoryMaxUsage", newMemoryMaxUsage,
+                    memoryMaxUsage);
+        }
+
+        if(newMemoryUsage < memoryUsage) {
+            fail(SubSystem.MEMORY, "getMemoryUsage", newMemoryUsage, memoryUsage);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        // If cgroups is not configured, report success
+        Metrics metrics = Metrics.systemMetrics();
+        if (metrics == null) {
+            System.out.println("TEST PASSED!!!");
+            return;
+        }
+
+        MetricsTester metricsTester = new MetricsTester();
+        metricsTester.setup();
+        metricsTester.testCpuAccounting();
+        metricsTester.testCpuSchedulingMetrics();
+        metricsTester.testCpuSets();
+        metricsTester.testMemorySubsystem();
+        metricsTester.testBlkIO();
+        metricsTester.testCpuConsumption();
+        metricsTester.testMemoryUsage();
+        System.out.println("TEST PASSED!!!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/containers/docker/Common.java	Tue Jun 12 18:51:45 2018 -0400
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.containers.docker;
+
+/*
+ * Methods and definitions common to docker tests container in this directory
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import jdk.test.lib.containers.docker.DockerRunOptions;
+import jdk.test.lib.containers.docker.DockerTestUtils;
+import jdk.test.lib.Utils;
+import jdk.test.lib.process.OutputAnalyzer;
+
+
+public class Common {
+    public static final String imageNameAndTag = "jdk-internal:test";
+
+    public static String imageName(String suffix) {
+        return imageNameAndTag + "-" + suffix;
+    }
+
+
+    public static void prepareWhiteBox() throws Exception {
+        Files.copy(Paths.get(new File("whitebox.jar").getAbsolutePath()),
+                   Paths.get(Utils.TEST_CLASSES, "whitebox.jar"));
+    }
+
+
+    // create simple commonly used options
+    public static DockerRunOptions newOpts(String imageNameAndTag) {
+        return new DockerRunOptions(imageNameAndTag, "/jdk/bin/java", "-version")
+            .addJavaOpts("-Xlog:os+container=trace");
+    }
+
+
+    // create commonly used options with class to be launched inside container
+    public static DockerRunOptions newOpts(String imageNameAndTag, String testClass) {
+        DockerRunOptions opts =
+            new DockerRunOptions(imageNameAndTag, "/jdk/bin/java", testClass);
+        opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
+        opts.addJavaOpts("-Xlog:os+container=trace", "-cp", "/test-classes/");
+        return opts;
+    }
+
+
+    public static DockerRunOptions addWhiteBoxOpts(DockerRunOptions opts) {
+        opts.addJavaOpts("-Xbootclasspath/a:/test-classes/whitebox.jar",
+                         "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI");
+        return opts;
+    }
+
+
+    // most common type of run and checks
+    public static OutputAnalyzer run(DockerRunOptions opts) throws Exception {
+        return DockerTestUtils.dockerRunJava(opts)
+            .shouldHaveExitValue(0).shouldContain("Initializing Container Support");
+    }
+
+
+    // log beginning of a test case
+    public static void logNewTestCase(String msg) {
+        System.out.println("========== NEW TEST CASE:      " + msg);
+    }
+
+}
--- a/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java	Tue Jun 12 18:51:45 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.test.lib.containers.docker;
 
 import java.util.ArrayList;
@@ -69,4 +70,8 @@
         return this;
     }
 
+    public DockerRunOptions addClassOptions(String... opts) {
+        Collections.addAll(classParams,opts);
+        return this;
+    }
 }
--- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java	Tue Jun 12 18:44:01 2018 -0400
+++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java	Tue Jun 12 18:51:45 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.test.lib.containers.docker;
 
 import java.io.File;