8203357: Container Metrics
Reviewed-by: mchung, dholmes, mseledtsov, rehn
This commit is contained in:
parent
2fa6eac464
commit
38646663d9
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
508
src/java.base/share/classes/jdk/internal/platform/Metrics.java
Normal file
508
src/java.base/share/classes/jdk/internal/platform/Metrics.java
Normal file
@ -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();
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -91,6 +91,9 @@ import java.util.stream.Stream;
|
|||||||
import jdk.internal.misc.VM;
|
import jdk.internal.misc.VM;
|
||||||
import jdk.internal.module.ModuleBootstrap;
|
import jdk.internal.module.ModuleBootstrap;
|
||||||
import jdk.internal.module.Modules;
|
import jdk.internal.module.Modules;
|
||||||
|
import jdk.internal.platform.Container;
|
||||||
|
import jdk.internal.platform.Metrics;
|
||||||
|
|
||||||
|
|
||||||
public final class LauncherHelper {
|
public final class LauncherHelper {
|
||||||
|
|
||||||
@ -151,6 +154,7 @@ public final class LauncherHelper {
|
|||||||
* this code determine this value, using a suitable method or omit the
|
* this code determine this value, using a suitable method or omit the
|
||||||
* line entirely.
|
* line entirely.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("fallthrough")
|
||||||
static void showSettings(boolean printToStderr, String optionFlag,
|
static void showSettings(boolean printToStderr, String optionFlag,
|
||||||
long initialHeapSize, long maxHeapSize, long stackSize) {
|
long initialHeapSize, long maxHeapSize, long stackSize) {
|
||||||
|
|
||||||
@ -169,10 +173,18 @@ public final class LauncherHelper {
|
|||||||
case "locale":
|
case "locale":
|
||||||
printLocale();
|
printLocale();
|
||||||
break;
|
break;
|
||||||
|
case "system":
|
||||||
|
if (System.getProperty("os.name").contains("Linux")) {
|
||||||
|
printSystemMetrics();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
printVmSettings(initialHeapSize, maxHeapSize, stackSize);
|
printVmSettings(initialHeapSize, maxHeapSize, stackSize);
|
||||||
printProperties();
|
printProperties();
|
||||||
printLocale();
|
printLocale();
|
||||||
|
if (System.getProperty("os.name").contains("Linux")) {
|
||||||
|
printSystemMetrics();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,6 +319,101 @@ public final class LauncherHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
private enum SizePrefix {
|
||||||
|
|
||||||
KILO(1024, "K"),
|
KILO(1024, "K"),
|
||||||
|
@ -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.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -150,7 +150,11 @@ java.launcher.X.usage=\n\
|
|||||||
\ show all locale related settings and continue\n\
|
\ show all locale related settings and continue\n\
|
||||||
\ -XshowSettings:properties\n\
|
\ -XshowSettings:properties\n\
|
||||||
\ show all property settings and continue\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\
|
\ -Xss<size> set java thread stack size\n\
|
||||||
\ -Xverify sets the mode of the bytecode verifier\n\
|
\ -Xverify sets the mode of the bytecode verifier\n\
|
||||||
\ --add-reads <module>=<target-module>(,<target-module>)*\n\
|
\ --add-reads <module>=<target-module>(,<target-module>)*\n\
|
||||||
|
@ -30,13 +30,13 @@
|
|||||||
* @modules java.base/jdk.internal.misc
|
* @modules java.base/jdk.internal.misc
|
||||||
* java.management
|
* java.management
|
||||||
* jdk.jartool/sun.tools.jar
|
* jdk.jartool/sun.tools.jar
|
||||||
* @build Common
|
|
||||||
* @run driver TestCPUAwareness
|
* @run driver TestCPUAwareness
|
||||||
*/
|
*/
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import jdk.test.lib.containers.docker.Common;
|
||||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||||
import jdk.test.lib.containers.docker.DockerTestUtils;
|
import jdk.test.lib.containers.docker.DockerTestUtils;
|
||||||
|
import jdk.test.lib.containers.cgroup.CPUSetsReader;
|
||||||
|
|
||||||
public class TestCPUAwareness {
|
public class TestCPUAwareness {
|
||||||
private static final String imageName = Common.imageName("cpu");
|
private static final String imageName = Common.imageName("cpu");
|
||||||
|
@ -31,13 +31,15 @@
|
|||||||
* @modules java.base/jdk.internal.misc
|
* @modules java.base/jdk.internal.misc
|
||||||
* java.management
|
* java.management
|
||||||
* jdk.jartool/sun.tools.jar
|
* 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 ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
* @run driver TestCPUSets
|
* @run driver TestCPUSets
|
||||||
*/
|
*/
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import jdk.test.lib.containers.docker.Common;
|
||||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||||
import jdk.test.lib.containers.docker.DockerTestUtils;
|
import jdk.test.lib.containers.docker.DockerTestUtils;
|
||||||
|
import jdk.test.lib.containers.cgroup.CPUSetsReader;
|
||||||
import jdk.test.lib.Asserts;
|
import jdk.test.lib.Asserts;
|
||||||
import jdk.test.lib.Platform;
|
import jdk.test.lib.Platform;
|
||||||
import jdk.test.lib.Utils;
|
import jdk.test.lib.Utils;
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,10 +30,11 @@
|
|||||||
* @modules java.base/jdk.internal.misc
|
* @modules java.base/jdk.internal.misc
|
||||||
* java.management
|
* java.management
|
||||||
* jdk.jartool/sun.tools.jar
|
* 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 ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
* @run driver TestMemoryAwareness
|
* @run driver TestMemoryAwareness
|
||||||
*/
|
*/
|
||||||
|
import jdk.test.lib.containers.docker.Common;
|
||||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||||
import jdk.test.lib.containers.docker.DockerTestUtils;
|
import jdk.test.lib.containers.docker.DockerTestUtils;
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,12 +30,13 @@
|
|||||||
* @modules java.base/jdk.internal.misc
|
* @modules java.base/jdk.internal.misc
|
||||||
* java.management
|
* java.management
|
||||||
* jdk.jartool/sun.tools.jar
|
* 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 ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
* @run driver TestMisc
|
* @run driver TestMisc
|
||||||
*/
|
*/
|
||||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
import jdk.test.lib.containers.docker.Common;
|
||||||
import jdk.test.lib.containers.docker.DockerTestUtils;
|
import jdk.test.lib.containers.docker.DockerTestUtils;
|
||||||
|
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||||
import jdk.test.lib.process.OutputAnalyzer;
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
import jdk.test.lib.process.ProcessTools;
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
|
||||||
|
@ -38,7 +38,8 @@ requires.properties= \
|
|||||||
sun.arch.data.model \
|
sun.arch.data.model \
|
||||||
java.runtime.name \
|
java.runtime.name \
|
||||||
vm.graal.enabled \
|
vm.graal.enabled \
|
||||||
vm.cds
|
vm.cds \
|
||||||
|
docker.support
|
||||||
|
|
||||||
# Minimum jtreg version
|
# Minimum jtreg version
|
||||||
requiredVersion=4.2 b12
|
requiredVersion=4.2 b12
|
||||||
|
57
test/jdk/jdk/internal/platform/cgroup/TestCgroupMetrics.java
Normal file
57
test/jdk/jdk/internal/platform/cgroup/TestCgroupMetrics.java
Normal file
@ -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!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
FROM oraclelinux:7.2
|
||||||
|
MAINTAINER mikhailo.seledtsov@oracle.com
|
||||||
|
|
||||||
|
COPY /jdk /jdk
|
||||||
|
|
||||||
|
ENV JAVA_HOME=/jdk
|
||||||
|
|
||||||
|
CMD ["/bin/bash"]
|
@ -0,0 +1,8 @@
|
|||||||
|
# Use generic ubuntu Linux on AArch64
|
||||||
|
FROM aarch64/ubuntu
|
||||||
|
|
||||||
|
COPY /jdk /jdk
|
||||||
|
|
||||||
|
ENV JAVA_HOME=/jdk
|
||||||
|
|
||||||
|
CMD ["/bin/bash"]
|
@ -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"]
|
@ -0,0 +1,7 @@
|
|||||||
|
FROM s390x/ubuntu
|
||||||
|
|
||||||
|
COPY /jdk /jdk
|
||||||
|
|
||||||
|
ENV JAVA_HOME=/jdk
|
||||||
|
|
||||||
|
CMD ["/bin/bash"]
|
178
test/jdk/jdk/internal/platform/docker/MetricsCpuTester.java
Normal file
178
test/jdk/jdk/internal/platform/docker/MetricsCpuTester.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
140
test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java
Normal file
140
test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java
Normal file
@ -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!!!");
|
||||||
|
}
|
||||||
|
}
|
167
test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java
Normal file
167
test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java
Normal file
@ -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!!!");
|
||||||
|
}
|
||||||
|
}
|
@ -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!!!");
|
||||||
|
}
|
||||||
|
}
|
61
test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java
Normal file
61
test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -67,11 +67,15 @@ public class Settings extends TestHelper {
|
|||||||
private static final String VM_SETTINGS = "VM settings:";
|
private static final String VM_SETTINGS = "VM settings:";
|
||||||
private static final String PROP_SETTINGS = "Property settings:";
|
private static final String PROP_SETTINGS = "Property settings:";
|
||||||
private static final String LOCALE_SETTINGS = "Locale settings:";
|
private static final String LOCALE_SETTINGS = "Locale settings:";
|
||||||
|
private static final String SYSTEM_SETTINGS = "Operating System Metrics:";
|
||||||
|
|
||||||
static void containsAllOptions(TestResult tr) {
|
static void containsAllOptions(TestResult tr) {
|
||||||
checkContains(tr, VM_SETTINGS);
|
checkContains(tr, VM_SETTINGS);
|
||||||
checkContains(tr, PROP_SETTINGS);
|
checkContains(tr, PROP_SETTINGS);
|
||||||
checkContains(tr, LOCALE_SETTINGS);
|
checkContains(tr, LOCALE_SETTINGS);
|
||||||
|
if (System.getProperty("os.name").contains("Linux")) {
|
||||||
|
checkContains(tr, SYSTEM_SETTINGS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runTestOptionDefault() throws IOException {
|
static void runTestOptionDefault() throws IOException {
|
||||||
@ -123,6 +127,20 @@ public class Settings extends TestHelper {
|
|||||||
checkContains(tr, LOCALE_SETTINGS);
|
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 {
|
static void runTestBadOptions() throws IOException {
|
||||||
TestResult tr = doExec(javaCmd, "-XshowSettingsBadOption");
|
TestResult tr = doExec(javaCmd, "-XshowSettingsBadOption");
|
||||||
checkNotContains(tr, VM_SETTINGS);
|
checkNotContains(tr, VM_SETTINGS);
|
||||||
@ -146,6 +164,7 @@ public class Settings extends TestHelper {
|
|||||||
runTestOptionVM();
|
runTestOptionVM();
|
||||||
runTestOptionProperty();
|
runTestOptionProperty();
|
||||||
runTestOptionLocale();
|
runTestOptionLocale();
|
||||||
|
runTestOptionSystem();
|
||||||
runTestBadOptions();
|
runTestBadOptions();
|
||||||
runTest7123582();
|
runTest7123582();
|
||||||
if (testExitValue != 0) {
|
if (testExitValue != 0) {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -20,23 +20,24 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
package jdk.test.lib.containers.cgroup;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import jdk.test.lib.Asserts;
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
|
||||||
// A simple CPU sets reader and parser
|
// A simple CPU sets reader and parser
|
||||||
public class CPUSetsReader {
|
public class CPUSetsReader {
|
||||||
public static String PROC_SELF_STATUS_PATH="/proc/self/status";
|
public static String PROC_SELF_STATUS_PATH = "/proc/self/status";
|
||||||
|
|
||||||
// Test the parser
|
// Test the parser
|
||||||
public static void test() {
|
public static void test() {
|
||||||
@ -51,6 +52,16 @@ public class CPUSetsReader {
|
|||||||
Asserts.assertEquals(listToString(parseCpuSet(cpuSet)), 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) {
|
public static String readFromProcStatus(String setType) {
|
||||||
String path = PROC_SELF_STATUS_PATH;
|
String path = PROC_SELF_STATUS_PATH;
|
||||||
@ -60,8 +71,8 @@ public class CPUSetsReader {
|
|||||||
|
|
||||||
try (Stream<String> stream = Files.lines(Paths.get(path))) {
|
try (Stream<String> stream = Files.lines(Paths.get(path))) {
|
||||||
o = stream
|
o = stream
|
||||||
.filter(line -> line.contains(setType))
|
.filter(line -> line.contains(setType))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -70,7 +81,7 @@ public class CPUSetsReader {
|
|||||||
return null; // entry not found
|
return null; // entry not found
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] parts = o.get().replaceAll("\\s","").split(":");
|
String[] parts = o.get().replaceAll("\\s", "").split(":");
|
||||||
|
|
||||||
// Should be 2 parts, before and after ":"
|
// Should be 2 parts, before and after ":"
|
||||||
Asserts.assertEquals(parts.length, 2);
|
Asserts.assertEquals(parts.length, 2);
|
||||||
@ -102,12 +113,11 @@ public class CPUSetsReader {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void addRange(ArrayList<Integer> list, String s) {
|
private static void addRange(ArrayList<Integer> list, String s) {
|
||||||
String[] range = s.split("-");
|
String[] range = s.split("-");
|
||||||
if ( range.length != 2 ) {
|
if (range.length != 2) {
|
||||||
throw new RuntimeException("Range should only contain two items, but contains "
|
throw new RuntimeException("Range should only contain two items, but contains "
|
||||||
+ range.length + " items");
|
+ range.length + " items");
|
||||||
}
|
}
|
||||||
|
|
||||||
int min = Integer.parseInt(range[0]);
|
int min = Integer.parseInt(range[0]);
|
||||||
@ -115,7 +125,7 @@ public class CPUSetsReader {
|
|||||||
|
|
||||||
if (min >= max) {
|
if (min >= max) {
|
||||||
String msg = String.format("min is greater or equals to max, min = %d, max = %d",
|
String msg = String.format("min is greater or equals to max, min = %d, max = %d",
|
||||||
min, max);
|
min, max);
|
||||||
throw new RuntimeException(msg);
|
throw new RuntimeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +144,12 @@ public class CPUSetsReader {
|
|||||||
// include up to maxCount.
|
// include up to maxCount.
|
||||||
public static String listToString(List<Integer> list, int maxCount) {
|
public static String listToString(List<Integer> list, int maxCount) {
|
||||||
return list.stream()
|
return list.stream()
|
||||||
.limit(maxCount)
|
.limit(maxCount)
|
||||||
.map(Object::toString)
|
.map(Object::toString)
|
||||||
.collect(Collectors.joining(","));
|
.collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String numberToString(int num) {
|
||||||
|
return IntStream.range(0, num).boxed().map(Object::toString).collect(Collectors.joining(","));
|
||||||
}
|
}
|
||||||
}
|
}
|
589
test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java
Normal file
589
test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java
Normal file
@ -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!!!");
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,11 +21,13 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package jdk.test.lib.containers.docker;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Methods and definitions common to docker tests container in this directory
|
* Methods and definitions common to docker tests container in this directory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||||
@ -43,7 +45,7 @@ public class Common {
|
|||||||
|
|
||||||
|
|
||||||
public static void prepareWhiteBox() throws Exception {
|
public static void prepareWhiteBox() throws Exception {
|
||||||
Files.copy(Paths.get(ClassFileInstaller.getJarPath("whitebox.jar")),
|
Files.copy(Paths.get(new File("whitebox.jar").getAbsolutePath()),
|
||||||
Paths.get(Utils.TEST_CLASSES, "whitebox.jar"));
|
Paths.get(Utils.TEST_CLASSES, "whitebox.jar"));
|
||||||
}
|
}
|
||||||
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.test.lib.containers.docker;
|
package jdk.test.lib.containers.docker;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -69,4 +70,8 @@ public class DockerRunOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DockerRunOptions addClassOptions(String... opts) {
|
||||||
|
Collections.addAll(classParams,opts);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.test.lib.containers.docker;
|
package jdk.test.lib.containers.docker;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user