diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index d3eb9b4c42d3..850f4dc9fe8c 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -19,6 +19,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-47647) Add `--color[=WHEN]` option to color the output WHEN ('always', 'never', or 'auto'). This API option supersedes the experimental option `-H:+BuildOutputColorful`. * (GR-43920) Add support for executing native image bundles as jar files with extra options `--with-native-image-agent` and `--container`. * (GR-43920) Add `,container[=]`, `,dockerfile=` and `,dry-run` options to `--bundle-create`and `--bundle-apply`. +* (GR-46420) Switch to directly using cgroup support from the JDK. ## GraalVM for JDK 17 and GraalVM for JDK 20 (Internal Version 23.0.0) * (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` allows turning the error into a warning. diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 919a17a20ca6..9f06d5300dca 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1304,6 +1304,9 @@ def _native_image_launcher_extra_jvm_args(): # URLClassLoader causes considerable increase of the libgraal image size and should be excluded. '-H:ReportAnalysisForbiddenType=java.net.URLClassLoader', + + # No need for container support in libgraal as HotSpot already takes care of it + '-H:-UseContainerSupport', ] + ([ # Force page size to support libgraal on AArch64 machines with a page size up to 64K. '-H:PageSize=64K' diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 988c62813b69..7b7f63da910c 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -271,6 +271,7 @@ "jdk.internal.misc", "jdk.internal.module", "jdk.internal.perf", + "jdk.internal.platform", "jdk.internal.ref", "jdk.internal.reflect", "jdk.internal.vm", @@ -306,21 +307,6 @@ "jacoco" : "exclude", }, - "com.oracle.svm.core.containers": { - "subDir": "src", - "sourceDirs": ["src"], - "dependencies": ["com.oracle.svm.core"], - "javaCompliance" : "17+", - "annotationProcessors": [ - "compiler:GRAAL_PROCESSOR", - "SVM_PROCESSOR", - ], - "workingSets": "SVM", - "spotbugs": "false", - "jacoco" : "exclude", - }, - - "com.oracle.svm.core.genscavenge": { "subDir": "src", "sourceDirs": [ @@ -1386,7 +1372,6 @@ "com.oracle.svm.core.posix", "com.oracle.svm.core.windows", "com.oracle.svm.core.genscavenge", - "com.oracle.svm.core.containers", ], "distDependencies": [ "sdk:NATIVEIMAGE", diff --git a/substratevm/src/com.oracle.svm.core.containers/eclipse-settings/org.eclipse.jdt.core.prefs b/substratevm/src/com.oracle.svm.core.containers/eclipse-settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 74334878208d..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/eclipse-settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,3 +0,0 @@ -org.eclipse.jdt.core.compiler.doc.comment.support=disabled -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled -org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupInfo.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupInfo.java deleted file mode 100644 index c1619f3338d3..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupInfo.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2020, Red Hat Inc. - * 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers; - -import com.oracle.svm.core.SubstrateUtil; - -/** - * Data structure to hold info from /proc/self/cgroup - * - * man 7 cgroups - * - * @see CgroupSubsystemFactory - */ -class CgroupInfo { - - private final String name; - private final int hierarchyId; - private final boolean enabled; - - private CgroupInfo(String name, int hierarchyId, boolean enabled) { - this.name = name; - this.hierarchyId = hierarchyId; - this.enabled = enabled; - } - - String getName() { - return name; - } - - int getHierarchyId() { - return hierarchyId; - } - - boolean isEnabled() { - return enabled; - } - - static CgroupInfo fromCgroupsLine(String line) { - String[] tokens = SubstrateUtil.split(line, "\t"); - if (tokens.length != 4) { - return null; - } - // discard 3'rd field, num_cgroups - return new CgroupInfo(tokens[0] /* name */, - Integer.parseInt(tokens[1]) /* hierarchyId */, - (Integer.parseInt(tokens[3]) == 1) /* enabled */); - } - -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupMetrics.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupMetrics.java deleted file mode 100644 index 5a5713d6ced2..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupMetrics.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2020, Red Hat Inc. - * 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers; - -import java.util.Objects; - -public class CgroupMetrics implements Metrics { - - private final CgroupSubsystem subsystem; - - CgroupMetrics(CgroupSubsystem subsystem) { - this.subsystem = Objects.requireNonNull(subsystem); - } - - @Override - public String getProvider() { - return subsystem.getProvider(); - } - - @Override - public long getCpuUsage() { - return subsystem.getCpuUsage(); - } - - @Override - public long[] getPerCpuUsage() { - return subsystem.getPerCpuUsage(); - } - - @Override - public long getCpuUserUsage() { - return subsystem.getCpuUserUsage(); - } - - @Override - public long getCpuSystemUsage() { - return subsystem.getCpuSystemUsage(); - } - - @Override - public long getCpuPeriod() { - return subsystem.getCpuPeriod(); - } - - @Override - public long getCpuQuota() { - return subsystem.getCpuQuota(); - } - - @Override - public long getCpuShares() { - return subsystem.getCpuShares(); - } - - @Override - public long getCpuNumPeriods() { - return subsystem.getCpuNumPeriods(); - } - - @Override - public long getCpuNumThrottled() { - return subsystem.getCpuNumThrottled(); - } - - @Override - public long getCpuThrottledTime() { - return subsystem.getCpuThrottledTime(); - } - - @Override - public long getEffectiveCpuCount() { - return subsystem.getEffectiveCpuCount(); - } - - @Override - public int[] getCpuSetCpus() { - return subsystem.getCpuSetCpus(); - } - - @Override - public int[] getEffectiveCpuSetCpus() { - return subsystem.getEffectiveCpuSetCpus(); - } - - @Override - public int[] getCpuSetMems() { - return subsystem.getCpuSetMems(); - } - - @Override - public int[] getEffectiveCpuSetMems() { - return subsystem.getEffectiveCpuSetMems(); - } - - public long getMemoryFailCount() { - return subsystem.getMemoryFailCount(); - } - - @Override - public long getMemoryLimit() { - return subsystem.getMemoryLimit(); - } - - @Override - public long getMemoryUsage() { - return subsystem.getMemoryUsage(); - } - - @Override - public long getTcpMemoryUsage() { - return subsystem.getTcpMemoryUsage(); - } - - @Override - public long getMemoryAndSwapLimit() { - return subsystem.getMemoryAndSwapLimit(); - } - - @Override - public long getMemoryAndSwapUsage() { - return subsystem.getMemoryAndSwapUsage(); - } - - @Override - public long getMemorySoftLimit() { - return subsystem.getMemorySoftLimit(); - } - - @Override - public long getBlkIOServiceCount() { - return subsystem.getBlkIOServiceCount(); - } - - @Override - public long getBlkIOServiced() { - return subsystem.getBlkIOServiced(); - } - - public static Metrics getInstance() { - return CgroupSubsystemFactory.create(); - } - -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystemController.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystemController.java deleted file mode 100644 index f73a251211a7..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystemController.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2020, Red Hat Inc. 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers; - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; - -import com.oracle.svm.core.SubstrateUtil; - -/** - * Cgroup version agnostic controller logic - * - */ -public interface CgroupSubsystemController { - - public static final String EMPTY_STR = ""; - - public String path(); - - /** - * getStringValue - * - * Return the first line of the file "param" argument from the controller. - * - * TODO: Consider using weak references for caching BufferedReader object. - * - * @param controller - * @param param - * @return Returns the contents of the file specified by param or null if - * an error occurs. - */ - public static String getStringValue(CgroupSubsystemController controller, String param) { - if (controller == null) return null; - - try { - return CgroupUtil.readStringValue(controller, param); - } - catch (IOException e) { - return null; - } - - } - - /** - * Get an entry from file "param" within the "controller" directory path - * which matches string "match". Applies "conversion" to the matching line. - * - * @param controller - * @param param - * @param match - * @param conversion - * @param defaultRetval - * @return The long value as derived by applying "conversion" to the matching - * line or "defaultRetval" if there was an error or no match found. - */ - public static long getLongValueMatchingLine(CgroupSubsystemController controller, - String param, - String match, - Function conversion, - long defaultRetval) { - long retval = defaultRetval; - if (controller == null) { - return retval; - } - try { - Path filePath = Paths.get(controller.path(), param); - List lines = CgroupUtil.readAllLinesPrivileged(filePath); - for (String line : lines) { - if (line.startsWith(match)) { - retval = conversion.apply(line); - break; - } - } - } catch (IOException e) { - // Ignore. Default is unlimited. - } - return retval; - } - - /** - * Get a long value from directory "controller" and file "param", by - * applying "conversion" to the string value within the file. - * - * @param controller - * @param param - * @param conversion - * @param defaultRetval - * @return The converted long value or "defaultRetval" if there was an - * error. - */ - public static long getLongValue(CgroupSubsystemController controller, - String param, - Function conversion, - long defaultRetval) { - String strval = getStringValue(controller, param); - if (strval == null) return defaultRetval; - return conversion.apply(strval); - } - - /** - * Get a double value from file "param" within "controller". - * - * @param controller - * @param param - * @param defaultRetval - * @return The double value or "defaultRetval" if there was an error. - */ - public static double getDoubleValue(CgroupSubsystemController controller, String param, double defaultRetval) { - String strval = getStringValue(controller, param); - - if (strval == null) return defaultRetval; - - double retval = Double.parseDouble(strval); - - return retval; - } - - /** - * getLongEntry - * - * Return the long value from the line containing the string "entryname" - * within file "param" in the "controller". - * - * TODO: Consider using weak references for caching BufferedReader object. - * - * @param controller - * @param param - * @param entryname - * @return long value or "defaultRetval" if there was an error or no match - * was found. - */ - public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname, long defaultRetval) { - if (controller == null) return defaultRetval; - - try { - Optional result = Optional.empty(); - for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get(controller.path(), param))) { - String[] tokens = SubstrateUtil.split(line, " "); - if (tokens.length == 2 && tokens[0].equals(entryname)) { - result = Optional.of(tokens[1]); - break; - } - } - - return result.isPresent() ? Long.parseLong(result.get()) : defaultRetval; - } - catch (IOException e) { - return defaultRetval; - } - } - - /** - * 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 numbers as represented by - * the string range. Returns null if there was an error or the input - * was an empty string. - */ - public static int[] stringRangeToIntArray(String range) { - if (range == null || EMPTY_STR.equals(range)) return null; - - ArrayList results = new ArrayList<>(); - String strs[] = SubstrateUtil.split(range, ","); - for (String str : strs) { - if (str.contains("-")) { - String lohi[] = SubstrateUtil.split(str, "-"); - // 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 - int[] ints = new int[results.size()]; - int i = 0; - for (Integer n : results) { - ints[i++] = n; - } - - return ints; - } - - /** - * Convert a number from its string representation to a long. - * - * @param strval - * @param overflowRetval - * @param defaultRetval - * @return The converted long value. "overflowRetval" is returned if the - * string representation exceeds the range of type long. - * "defaultRetval" is returned if another type of error occurred - * during conversion. - */ - public static long convertStringToLong(String strval, long overflowRetval, long defaultRetval) { - long retval = defaultRetval; - if (strval == null) return retval; - - try { - retval = Long.parseLong(strval); - } catch (NumberFormatException e) { - // For some properties (e.g. memory.limit_in_bytes, cgroups v1) we may overflow - // the range of signed long. In this case, return overflowRetval - if (strval.length() > 0 && strval.charAt(0) != '-') { - return overflowRetval; - } - } - return retval; - } - -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystemFactory.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystemFactory.java deleted file mode 100644 index 2cbce1f09514..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystemFactory.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2020, Red Hat Inc. - * 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers; - -import java.io.IOException; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import com.oracle.svm.core.containers.cgroupv1.CgroupV1Subsystem; -import com.oracle.svm.core.containers.cgroupv2.CgroupV2Subsystem; - -public class CgroupSubsystemFactory { - - private static final String CPU_CTRL = "cpu"; - private static final String CPUACCT_CTRL = "cpuacct"; - private static final String CPUSET_CTRL = "cpuset"; - private static final String BLKIO_CTRL = "blkio"; - private static final String MEMORY_CTRL = "memory"; - - static CgroupMetrics create() { - Optional optResult = null; - try { - optResult = determineType("/proc/self/mountinfo", "/proc/cgroups"); - } catch (IOException e) { - return null; - } - - if (!optResult.isPresent()) { - return null; - } - CgroupTypeResult result = optResult.get(); - - // If no controller is enabled, return no metrics. - if (!result.isAnyControllersEnabled()) { - return null; - } - - // Warn about mixed cgroups v1 and cgroups v2 controllers. The code is - // not ready to deal with that on a per-controller basis. Return no metrics - // in that case - if (result.isAnyCgroupV1Controllers() && result.isAnyCgroupV2Controllers()) { - // java.lang.System.Logger logger = System.getLogger("jdk.internal.platform"); - // logger.log(java.lang.System.Logger.Level.DEBUG, "Mixed cgroupv1 and cgroupv2 not supported. Metrics disabled."); - return null; - } - - if (result.isCgroupV2()) { - CgroupSubsystem subsystem = CgroupV2Subsystem.getInstance(); - return subsystem != null ? new CgroupMetrics(subsystem) : null; - } else { - CgroupV1Subsystem subsystem = CgroupV1Subsystem.getInstance(); - return subsystem != null ? new CgroupV1MetricsImpl(subsystem) : null; - } - } - - public static Optional determineType(String mountInfo, String cgroups) throws IOException { - Map infos = new HashMap<>(); - List lines = CgroupUtil.readAllLinesPrivileged(Paths.get(cgroups)); - for (String line : lines) { - if (line.startsWith("#")) { - continue; - } - CgroupInfo info = CgroupInfo.fromCgroupsLine(line); - switch (info.getName()) { - case CPU_CTRL: infos.put(CPU_CTRL, info); break; - case CPUACCT_CTRL: infos.put(CPUACCT_CTRL, info); break; - case CPUSET_CTRL: infos.put(CPUSET_CTRL, info); break; - case MEMORY_CTRL: infos.put(MEMORY_CTRL, info); break; - case BLKIO_CTRL: infos.put(BLKIO_CTRL, info); break; - } - } - - // For cgroups v2 all controllers need to have zero hierarchy id - // and /proc/self/mountinfo needs to have at least one cgroup filesystem - // mounted. Note that hybrid hierarchy has controllers mounted via - // cgroup v1. In that case hierarchy id's will be non-zero. - boolean isCgroupsV2 = true; - boolean anyControllersEnabled = false; - boolean anyCgroupsV2Controller = false; - boolean anyCgroupsV1Controller = false; - for (CgroupInfo info: infos.values()) { - anyCgroupsV1Controller = anyCgroupsV1Controller || info.getHierarchyId() != 0; - anyCgroupsV2Controller = anyCgroupsV2Controller || info.getHierarchyId() == 0; - isCgroupsV2 = isCgroupsV2 && info.getHierarchyId() == 0; - anyControllersEnabled = anyControllersEnabled || info.isEnabled(); - } - - // If there are no mounted controllers in mountinfo, but we've only - // seen 0 hierarchy IDs in /proc/cgroups, we are on a cgroups v1 system. - // However, continuing in that case does not make sense as we'd need - // information from mountinfo for the mounted controller paths anyway. - if (isCgroupsV2) { - boolean anyCgroupMounted = false; - for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get(mountInfo))) { - if (line.contains("cgroup")) { - anyCgroupMounted = true; - break; - } - } - if (!anyCgroupMounted) { - return Optional.empty(); - } - } - CgroupTypeResult result = new CgroupTypeResult(isCgroupsV2, anyControllersEnabled, anyCgroupsV2Controller, anyCgroupsV1Controller); - return Optional.of(result); - } - - public static final class CgroupTypeResult { - private final boolean isCgroupV2; - private final boolean anyControllersEnabled; - private final boolean anyCgroupV2Controllers; - private final boolean anyCgroupV1Controllers; - - private CgroupTypeResult(boolean isCgroupV2, - boolean anyControllersEnabled, - boolean anyCgroupV2Controllers, - boolean anyCgroupV1Controllers) { - this.isCgroupV2 = isCgroupV2; - this.anyControllersEnabled = anyControllersEnabled; - this.anyCgroupV1Controllers = anyCgroupV1Controllers; - this.anyCgroupV2Controllers = anyCgroupV2Controllers; - } - - public boolean isCgroupV2() { - return isCgroupV2; - } - - public boolean isAnyControllersEnabled() { - return anyControllersEnabled; - } - - public boolean isAnyCgroupV2Controllers() { - return anyCgroupV2Controllers; - } - - public boolean isAnyCgroupV1Controllers() { - return anyCgroupV1Controllers; - } - } -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupUtil.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupUtil.java deleted file mode 100644 index 30cfe6cceefe..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupUtil.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2020, Red Hat Inc. - * 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers; - -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.List; - -public final class CgroupUtil { - - static void unwrapIOExceptionAndRethrow(PrivilegedActionException pae) throws IOException { - Throwable x = pae.getCause(); - if (x instanceof IOException) - throw (IOException) x; - if (x instanceof RuntimeException) - throw (RuntimeException) x; - if (x instanceof Error) - throw (Error) x; - } - - @SuppressWarnings({"deprecation"}) // doPrivileged is deprecated on JDK 17 - static String readStringValue(CgroupSubsystemController controller, String param) throws IOException { - PrivilegedExceptionAction pea = () -> - new BufferedReader(new InputStreamReader(new FileInputStream(Paths.get(controller.path(), param).toString()), StandardCharsets.UTF_8)); - try (BufferedReader bufferedReader = - AccessController.doPrivileged(pea)) { - return bufferedReader.readLine(); - } catch (PrivilegedActionException e) { - unwrapIOExceptionAndRethrow(e); - throw new InternalError(e.getCause()); - } - } - - @SuppressWarnings({"deprecation"}) // doPrivileged is deprecated on JDK 17 - public static List readAllLinesPrivileged(Path path) throws IOException { - PrivilegedExceptionAction pea = () -> - new BufferedReader(new InputStreamReader(new FileInputStream(path.toString()), StandardCharsets.UTF_8)); - try (BufferedReader bufferedReader = - AccessController.doPrivileged(pea)) { - String line; - List lines = new ArrayList<>(); - while ((line = bufferedReader.readLine()) != null) { - lines.add(line); - } - return lines; - } catch (PrivilegedActionException e) { - unwrapIOExceptionAndRethrow(e); - throw new InternalError(e.getCause()); - } - } -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupV1Metrics.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupV1Metrics.java deleted file mode 100644 index f64564ba110f..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupV1Metrics.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2018, 2020, 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers; - -/** - * - * Cgroup v1 extensions to the Metrics interface. Linux, only. - * - */ -public interface CgroupV1Metrics extends Metrics { - - /** - * 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 -1 if this - * metric is not available. Returns -2 if this metric is not - * supported. - * - */ - public long getMemoryMaxUsage(); - - /** - * 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 -1 if 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 - * there is no limit set. - * - */ - 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 -1 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 -1 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 -1 if the 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 - * there is no limit. - * - */ - 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 -1 if this - * metric is not available. - * - */ - public long getTcpMemoryMaxUsage(); - - /** - * 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 -1 if the metric - * is not available. - * - */ - public long getMemoryAndSwapFailCount(); - - /** - * 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 -1 if this - * metric is not available. - * - */ - public long getMemoryAndSwapMaxUsage(); - - /** - * 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. null will be returned if this - * capability is not available on the current operating system. - * - */ - public Boolean isMemoryOOMKillEnabled(); - - /** - * 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 - * determine if this support is enabled. - * - * @return Memory pressure or 0 if not enabled or -1 if metric is not - * available. - * - */ - public double getCpuSetMemoryPressure(); - - /** - * Returns the state of the memory pressure detection support. - * - * @return true if support is available and enabled. false otherwise. - * - */ - public Boolean isCpuSetMemoryPressureEnabled(); -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupV1MetricsImpl.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupV1MetricsImpl.java deleted file mode 100644 index d5d12ba72ec3..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupV1MetricsImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2020, Red Hat Inc. - * 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers; - -/** - * Cgroup v1 Metrics extensions - * - */ -public class CgroupV1MetricsImpl extends CgroupMetrics implements CgroupV1Metrics { - - private final CgroupV1Metrics metrics; - - CgroupV1MetricsImpl(CgroupV1Metrics metrics) { - super((CgroupSubsystem)metrics); - this.metrics = metrics; - } - - @Override - public long getMemoryMaxUsage() { - return metrics.getMemoryMaxUsage(); - } - - @Override - public long getKernelMemoryFailCount() { - return metrics.getKernelMemoryFailCount(); - } - - @Override - public long getKernelMemoryLimit() { - return metrics.getKernelMemoryLimit(); - } - - @Override - public long getKernelMemoryMaxUsage() { - return metrics.getKernelMemoryMaxUsage(); - } - - @Override - public long getKernelMemoryUsage() { - return metrics.getKernelMemoryUsage(); - } - - @Override - public long getTcpMemoryFailCount() { - return metrics.getTcpMemoryFailCount(); - } - - @Override - public long getTcpMemoryLimit() { - return metrics.getTcpMemoryLimit(); - } - - @Override - public long getTcpMemoryMaxUsage() { - return metrics.getTcpMemoryMaxUsage(); - } - - @Override - public long getMemoryAndSwapFailCount() { - return metrics.getMemoryAndSwapFailCount(); - } - - @Override - public long getMemoryAndSwapMaxUsage() { - return metrics.getMemoryAndSwapMaxUsage(); - } - - @Override - public Boolean isMemoryOOMKillEnabled() { - return metrics.isMemoryOOMKillEnabled(); - } - - @Override - public double getCpuSetMemoryPressure() { - return metrics.getCpuSetMemoryPressure(); - } - - @Override - public Boolean isCpuSetMemoryPressureEnabled() { - return metrics.isCpuSetMemoryPressureEnabled(); - } - -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/Metrics.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/Metrics.java deleted file mode 100644 index b4a969b55d38..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/Metrics.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (c) 2018, 2020, 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. - */ -// @formatter:off -package com.oracle.svm.core.containers; - -import java.lang.reflect.Method; - -/** - * Operating System Metrics class - * - * Implementation note: - * 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: - * - *
    - *
  1. All processes, including the current process within a container. - * - *
  2. All processes, including the current process running together - * isolated from other non-isolated processes. - * - *
  3. All processes running on a host when that there is no isolation - * in effect. - *
- * - * @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 { - Class c = Class.forName("com.oracle.svm.core.containers.CgroupMetrics"); - 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. - * - * Implementation note: - * Metrics are currently only supported Linux. - * The provider for Linux is cgroups (version 1 or 2). - * - * @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, -1 if unknown or - * -2 if the metric is not supported. - * - */ - 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 supported or not available, null 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, -1 if the metric is not available or - * -2 if the metric is not supported. - * - */ - public long getCpuUserUsage(); - - /** - * Returns the aggregate system time, in nanoseconds, consumed by - * all tasks in the Isolation Group. - * - * @return System time in nanoseconds, -1 if the metric is not available or - * -2 if the metric is not supported. - * - */ - 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, -1 if the metric is not available or - * -2 if the metric is not supported. - * - */ - 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, -1 if the quota is unlimited or - * -2 if not supported. - * - */ - 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. - * - * Implementation note: - * 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, -1 if the metric is not available or - * -2 if cpu shares are not supported. - * - */ - public long getCpuShares(); - - /** - * Returns the number of time-slice periods that have elapsed if - * a CPU quota has been setup for the Isolation Group - * - * @return count of elapsed periods, -1 if the metric is not available - * or -2 if the metric is not supported. - * - */ - 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, -1 if the metric is not available or - * -2 if it is not supported. - * - */ - 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, -1 if the metric is not available - * or -2 if it is not supported. - * - */ - 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 Metrics#getEffectiveCpuSetCpus()} }. - * - * @return An array of available CPUs. Returns null if the metric is not - * available or the metric is not supported. - * - */ - 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. Returns null - * if the metric is not available or the metric is not supported. - * - */ - 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 Metrics#getEffectiveCpuSetMems()}. - * - * @return An array of available memory nodes or null - * if the metric is not available or is not supported. - * - */ - 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 null - * if the metric is not available or is not supported. - * - */ - public int[] getEffectiveCpuSetMems(); - - /***************************************************************** - * 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 -1 if the metric - * is not available. Returns -2 if the metric is not - * supported. - * - */ - 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 - * there is no limit or -2 if this metric is not supported. - * - */ - public long getMemoryLimit(); - - /** - * 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 -1 if - * the metric is not available or -2 if the metric is not - * supported. - * - */ - public long getMemoryUsage(); - - /** - * 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 -1 if the metric - * is not available. Returns -2 if this metric is not supported. - * - */ - public long getTcpMemoryUsage(); - - /** - * 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 - * there is no limit set or -2 if this metric is not supported. - * - */ - public long getMemoryAndSwapLimit(); - - /** - * 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 -1 if - * the metric is not available. Returns -2 if this metric is not - * supported. - * - */ - public long getMemoryAndSwapUsage(); - - /** - * 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, -1 will be - * returned. Returns -2 if the metric is not supported. - * - */ - 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 -1 if the metric is not available. - * Returns -2 if this metric is not supported. - * - */ - 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 -1 if the metric is not - * available. Returns -2 if this metric is not supported. - * - */ - public long getBlkIOServiced(); -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1Subsystem.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1Subsystem.java deleted file mode 100644 index 8b03999b40ec..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1Subsystem.java +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright (c) 2018, 2020, 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers.cgroupv1; - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; - -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.containers.CgroupSubsystem; -import com.oracle.svm.core.containers.CgroupSubsystemController; -import com.oracle.svm.core.containers.CgroupUtil; -import com.oracle.svm.core.containers.CgroupV1Metrics; - -public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics { - private CgroupV1MemorySubSystemController memory; - private CgroupV1SubsystemController cpu; - private CgroupV1SubsystemController cpuacct; - private CgroupV1SubsystemController cpuset; - private CgroupV1SubsystemController blkio; - private boolean activeSubSystems; - - private static final CgroupV1Subsystem INSTANCE = initSubSystem(); - - private static final String PROVIDER_NAME = "cgroupv1"; - - private CgroupV1Subsystem() { - activeSubSystems = false; - } - - public static CgroupV1Subsystem getInstance() { - return INSTANCE; - } - - private static CgroupV1Subsystem initSubSystem() { - CgroupV1Subsystem subsystem = new CgroupV1Subsystem(); - - /** - * 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 { - for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/self/mountinfo"))) { - if (line.contains(" - cgroup ")) { - String[] tokens = SubstrateUtil.split(line, " "); - createSubSystemController(subsystem, tokens); - } - } - - } 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 { - for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/self/cgroup"))) { - String[] tokens = SubstrateUtil.split(line, ":"); - if (tokens.length >= 3) { - setSubSystemControllerPath(subsystem, tokens); - } - } - - } catch (IOException e) { - return null; - } - - // Return Metrics object if we found any subsystems. - if (subsystem.activeSubSystems()) { - return subsystem; - } - - return null; - } - - /** - * createSubSystem objects and initialize mount points - */ - private static void createSubSystemController(CgroupV1Subsystem subsystem, String[] mountentry) { - if (mountentry.length < 5) return; - - Path p = Paths.get(mountentry[4]); - String[] subsystemNames = SubstrateUtil.split(p.getFileName().toString(), ","); - - for (String subsystemName: subsystemNames) { - switch (subsystemName) { - case "memory": - subsystem.setMemorySubSystem(new CgroupV1MemorySubSystemController(mountentry[3], mountentry[4])); - break; - case "cpuset": - subsystem.setCpuSetController(new CgroupV1SubsystemController(mountentry[3], mountentry[4])); - break; - case "cpuacct": - subsystem.setCpuAcctController(new CgroupV1SubsystemController(mountentry[3], mountentry[4])); - break; - case "cpu": - subsystem.setCpuController(new CgroupV1SubsystemController(mountentry[3], mountentry[4])); - break; - case "blkio": - subsystem.setBlkIOController(new CgroupV1SubsystemController(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 setSubSystemControllerPath(CgroupV1Subsystem subsystem, String[] entry) { - String controllerName; - String base; - CgroupV1SubsystemController controller = null; - CgroupV1SubsystemController controller2 = null; - - controllerName = entry[1]; - base = entry[2]; - if (controllerName != null && base != null) { - switch (controllerName) { - case "memory": - controller = subsystem.memoryController(); - break; - case "cpuset": - controller = subsystem.cpuSetController(); - break; - case "cpu,cpuacct": - case "cpuacct,cpu": - controller = subsystem.cpuController(); - controller2 = subsystem.cpuAcctController(); - break; - case "cpuacct": - controller = subsystem.cpuAcctController(); - break; - case "cpu": - controller = subsystem.cpuController(); - break; - case "blkio": - controller = subsystem.blkIOController(); - break; - // Ignore subsystems that we don't support - default: - break; - } - } - - if (controller != null) { - controller.setPath(base); - if (controller instanceof CgroupV1MemorySubSystemController) { - CgroupV1MemorySubSystemController memorySubSystem = (CgroupV1MemorySubSystemController)controller; - boolean isHierarchial = getHierarchical(memorySubSystem); - memorySubSystem.setHierarchical(isHierarchial); - } - subsystem.setActiveSubSystems(); - } - if (controller2 != null) { - controller2.setPath(base); - } - } - - - private static boolean getHierarchical(CgroupV1MemorySubSystemController controller) { - long hierarchical = getLongValue(controller, "memory.use_hierarchy"); - return hierarchical > 0; - } - - private void setActiveSubSystems() { - activeSubSystems = true; - } - - private boolean activeSubSystems() { - return activeSubSystems; - } - - private void setMemorySubSystem(CgroupV1MemorySubSystemController memory) { - this.memory = memory; - } - - private void setCpuController(CgroupV1SubsystemController cpu) { - this.cpu = cpu; - } - - private void setCpuAcctController(CgroupV1SubsystemController cpuacct) { - this.cpuacct = cpuacct; - } - - private void setCpuSetController(CgroupV1SubsystemController cpuset) { - this.cpuset = cpuset; - } - - private void setBlkIOController(CgroupV1SubsystemController blkio) { - this.blkio = blkio; - } - - private CgroupV1SubsystemController memoryController() { - return memory; - } - - private CgroupV1SubsystemController cpuController() { - return cpu; - } - - private CgroupV1SubsystemController cpuAcctController() { - return cpuacct; - } - - private CgroupV1SubsystemController cpuSetController() { - return cpuset; - } - - private CgroupV1SubsystemController blkIOController() { - return blkio; - } - - private static long getLongValue(CgroupSubsystemController controller, - String parm) { - return CgroupSubsystemController.getLongValue(controller, - parm, - CgroupV1SubsystemController::convertStringToLong, - CgroupSubsystem.LONG_RETVAL_UNLIMITED); - } - - public String getProvider() { - return PROVIDER_NAME; - } - - /***************************************************************** - * CPU Accounting Subsystem - ****************************************************************/ - - - public long getCpuUsage() { - return getLongValue(cpuacct, "cpuacct.usage"); - } - - public long[] getPerCpuUsage() { - String usagelist = CgroupSubsystemController.getStringValue(cpuacct, "cpuacct.usage_percpu"); - if (usagelist == null) { - return null; - } - - String list[] = SubstrateUtil.split(usagelist, " "); - 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 CgroupV1SubsystemController.getLongEntry(cpuacct, "cpuacct.stat", "user"); - } - - public long getCpuSystemUsage() { - return CgroupV1SubsystemController.getLongEntry(cpuacct, "cpuacct.stat", "system"); - } - - - /***************************************************************** - * CPU Subsystem - ****************************************************************/ - - - public long getCpuPeriod() { - return getLongValue(cpu, "cpu.cfs_period_us"); - } - - public long getCpuQuota() { - return getLongValue(cpu, "cpu.cfs_quota_us"); - } - - public long getCpuShares() { - long retval = getLongValue(cpu, "cpu.shares"); - if (retval == 0 || retval == 1024) - return CgroupSubsystem.LONG_RETVAL_UNLIMITED; - else - return retval; - } - - public long getCpuNumPeriods() { - return CgroupV1SubsystemController.getLongEntry(cpu, "cpu.stat", "nr_periods"); - } - - public long getCpuNumThrottled() { - return CgroupV1SubsystemController.getLongEntry(cpu, "cpu.stat", "nr_throttled"); - } - - public long getCpuThrottledTime() { - return CgroupV1SubsystemController.getLongEntry(cpu, "cpu.stat", "throttled_time"); - } - - public long getEffectiveCpuCount() { - return Runtime.getRuntime().availableProcessors(); - } - - - /***************************************************************** - * CPUSet Subsystem - ****************************************************************/ - - public int[] getCpuSetCpus() { - return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.cpus")); - } - - public int[] getEffectiveCpuSetCpus() { - return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.effective_cpus")); - } - - public int[] getCpuSetMems() { - return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.mems")); - } - - public int[] getEffectiveCpuSetMems() { - return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.effective_mems")); - } - - public double getCpuSetMemoryPressure() { - return CgroupV1SubsystemController.getDoubleValue(cpuset, "cpuset.memory_pressure"); - } - - public Boolean isCpuSetMemoryPressureEnabled() { - long val = getLongValue(cpuset, "cpuset.memory_pressure_enabled"); - return (val == 1); - } - - - /***************************************************************** - * Memory Subsystem - ****************************************************************/ - - - public long getMemoryFailCount() { - return getLongValue(memory, "memory.failcnt"); - } - - public long getMemoryLimit() { - long retval = getLongValue(memory, "memory.limit_in_bytes"); - if (retval > CgroupV1SubsystemController.UNLIMITED_MIN) { - if (memory.isHierarchical()) { - // memory.limit_in_bytes returned unlimited, attempt - // hierarchical memory limit - String match = "hierarchical_memory_limit"; - retval = CgroupV1SubsystemController.getLongValueMatchingLine(memory, - "memory.stat", - match); - } - } - return CgroupV1SubsystemController.longValOrUnlimited(retval); - } - - public long getMemoryMaxUsage() { - return getLongValue(memory, "memory.max_usage_in_bytes"); - } - - public long getMemoryUsage() { - return getLongValue(memory, "memory.usage_in_bytes"); - } - - public long getKernelMemoryFailCount() { - return getLongValue(memory, "memory.kmem.failcnt"); - } - - public long getKernelMemoryLimit() { - return CgroupV1SubsystemController.longValOrUnlimited(getLongValue(memory, "memory.kmem.limit_in_bytes")); - } - - public long getKernelMemoryMaxUsage() { - return getLongValue(memory, "memory.kmem.max_usage_in_bytes"); - } - - public long getKernelMemoryUsage() { - return getLongValue(memory, "memory.kmem.usage_in_bytes"); - } - - public long getTcpMemoryFailCount() { - return getLongValue(memory, "memory.kmem.tcp.failcnt"); - } - - public long getTcpMemoryLimit() { - return CgroupV1SubsystemController.longValOrUnlimited(getLongValue(memory, "memory.kmem.tcp.limit_in_bytes")); - } - - public long getTcpMemoryMaxUsage() { - return getLongValue(memory, "memory.kmem.tcp.max_usage_in_bytes"); - } - - public long getTcpMemoryUsage() { - return getLongValue(memory, "memory.kmem.tcp.usage_in_bytes"); - } - - public long getMemoryAndSwapFailCount() { - return getLongValue(memory, "memory.memsw.failcnt"); - } - - public long getMemoryAndSwapLimit() { - long retval = getLongValue(memory, "memory.memsw.limit_in_bytes"); - if (retval > CgroupV1SubsystemController.UNLIMITED_MIN) { - if (memory.isHierarchical()) { - // memory.memsw.limit_in_bytes returned unlimited, attempt - // hierarchical memory limit - String match = "hierarchical_memsw_limit"; - retval = CgroupV1SubsystemController.getLongValueMatchingLine(memory, - "memory.stat", - match); - } - } - return CgroupV1SubsystemController.longValOrUnlimited(retval); - } - - public long getMemoryAndSwapMaxUsage() { - return getLongValue(memory, "memory.memsw.max_usage_in_bytes"); - } - - public long getMemoryAndSwapUsage() { - return getLongValue(memory, "memory.memsw.usage_in_bytes"); - } - - public Boolean isMemoryOOMKillEnabled() { - long val = CgroupV1SubsystemController.getLongEntry(memory, "memory.oom_control", "oom_kill_disable"); - return (val == 0); - } - - public long getMemorySoftLimit() { - return CgroupV1SubsystemController.longValOrUnlimited(getLongValue(memory, "memory.soft_limit_in_bytes")); - } - - - /***************************************************************** - * BlKIO Subsystem - ****************************************************************/ - - - public long getBlkIOServiceCount() { - return CgroupV1SubsystemController.getLongEntry(blkio, "blkio.throttle.io_service_bytes", "Total"); - } - - public long getBlkIOServiced() { - return CgroupV1SubsystemController.getLongEntry(blkio, "blkio.throttle.io_serviced", "Total"); - } - -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1SubsystemController.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1SubsystemController.java deleted file mode 100644 index 65068d409565..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1SubsystemController.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2018, 2020, 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers.cgroupv1; - -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.containers.CgroupSubsystem; -import com.oracle.svm.core.containers.CgroupSubsystemController; - -public class CgroupV1SubsystemController implements CgroupSubsystemController { - - private static final double DOUBLE_RETVAL_UNLIMITED = CgroupSubsystem.LONG_RETVAL_UNLIMITED; - // Values returned larger than this number are unlimited. - static long UNLIMITED_MIN = 0x7FFFFFFFFF000000L; - String root; - String mountPoint; - String path; - - public CgroupV1SubsystemController(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 (cgroupPath.startsWith(root)) { - if (cgroupPath.length() > root.length()) { - String cgroupSubstr = cgroupPath.substring(root.length()); - path = mountPoint + cgroupSubstr; - } - } - } - } - } - } - - @Override - public String path() { - return path; - } - - public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname) { - return CgroupSubsystemController.getLongEntry(controller, - param, - entryname, - CgroupSubsystem.LONG_RETVAL_UNLIMITED /* retval on error */); - } - - public static double getDoubleValue(CgroupSubsystemController controller, String parm) { - return CgroupSubsystemController.getDoubleValue(controller, - parm, - DOUBLE_RETVAL_UNLIMITED /* retval on error */); - } - - public static long convertStringToLong(String strval) { - return CgroupSubsystemController.convertStringToLong(strval, - Long.MAX_VALUE /* overflow value */, - CgroupSubsystem.LONG_RETVAL_UNLIMITED /* retval on error */); - } - - public static long longValOrUnlimited(long value) { - return value > UNLIMITED_MIN ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : value; - } - - public static long getLongValueMatchingLine(CgroupSubsystemController controller, - String param, - String match) { - return CgroupSubsystemController.getLongValueMatchingLine(controller, - param, - match, - CgroupV1SubsystemController::convertHierachicalLimitLine, - CgroupSubsystem.LONG_RETVAL_UNLIMITED); - } - - public static long convertHierachicalLimitLine(String line) { - String[] tokens = SubstrateUtil.split(line, " "); - if (tokens.length == 2) { - String strVal = tokens[1]; - return CgroupV1SubsystemController.convertStringToLong(strVal); - } - return CgroupV1SubsystemController.UNLIMITED_MIN + 1; // unlimited - } - -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv2/CgroupV2Subsystem.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv2/CgroupV2Subsystem.java deleted file mode 100644 index 512c402a5ca7..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv2/CgroupV2Subsystem.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (c) 2020, Red Hat Inc. - * 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers.cgroupv2; - -import java.io.IOException; -import java.nio.file.Paths; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; - -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.containers.CgroupSubsystem; -import com.oracle.svm.core.containers.CgroupSubsystemController; -import com.oracle.svm.core.containers.CgroupUtil; - -public class CgroupV2Subsystem implements CgroupSubsystem { - - private static final CgroupV2Subsystem INSTANCE = initSubsystem(); - private static final long[] LONG_ARRAY_NOT_SUPPORTED = null; - private static final int[] INT_ARRAY_UNAVAILABLE = null; - private final CgroupSubsystemController unified; - private static final String PROVIDER_NAME = "cgroupv2"; - private static final int PER_CPU_SHARES = 1024; - private static final String MAX_VAL = "max"; - private static final Object EMPTY_STR = ""; - - private CgroupV2Subsystem(CgroupSubsystemController unified) { - this.unified = unified; - } - - private long getLongVal(String file) { - return CgroupSubsystemController.getLongValue(unified, - file, - CgroupV2SubsystemController::convertStringToLong, - CgroupSubsystem.LONG_RETVAL_UNLIMITED); - } - - private static CgroupV2Subsystem initSubsystem() { - // read mountinfo so as to determine root mount path - String mountPath = null; - try { - for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/self/mountinfo"))) { - if (line.contains(" - cgroup2 ")) { - String[] tokens = SubstrateUtil.split(line, " "); - mountPath = tokens[4]; - } - } - } catch (IOException e) { - return null; - } - String cgroupPath = null; - try { - List lines = CgroupUtil.readAllLinesPrivileged(Paths.get("/proc/self/cgroup")); - for (String line: lines) { - String[] tokens = SubstrateUtil.split(line, ":"); - if (tokens.length != 3) { - return null; // something is not right. - } - if (!"0".equals(tokens[0])) { - // hierarchy must be zero for cgroups v2 - return null; - } - cgroupPath = tokens[2]; - break; - } - } catch (IOException e) { - return null; - } - CgroupSubsystemController unified = new CgroupV2SubsystemController( - mountPath, - cgroupPath); - return new CgroupV2Subsystem(unified); - } - - public static CgroupSubsystem getInstance() { - return INSTANCE; - } - - @Override - public String getProvider() { - return PROVIDER_NAME; - } - - @Override - public long getCpuUsage() { - long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "usage_usec"); - if (micros < 0) { - return micros; - } - return TimeUnit.MICROSECONDS.toNanos(micros); - } - - @Override - public long[] getPerCpuUsage() { - return LONG_ARRAY_NOT_SUPPORTED; - } - - @Override - public long getCpuUserUsage() { - long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "user_usec"); - if (micros < 0) { - return micros; - } - return TimeUnit.MICROSECONDS.toNanos(micros); - } - - @Override - public long getCpuSystemUsage() { - long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "system_usec"); - if (micros < 0) { - return micros; - } - return TimeUnit.MICROSECONDS.toNanos(micros); - } - - @Override - public long getCpuPeriod() { - return getFromCpuMax(1 /* $PERIOD index */); - } - - @Override - public long getCpuQuota() { - return getFromCpuMax(0 /* $MAX index */); - } - - private long getFromCpuMax(int tokenIdx) { - String cpuMaxRaw = CgroupSubsystemController.getStringValue(unified, "cpu.max"); - if (cpuMaxRaw == null) { - // likely file not found - return CgroupSubsystem.LONG_RETVAL_UNLIMITED; - } - // $MAX $PERIOD - String[] tokens = SubstrateUtil.split(cpuMaxRaw, " "); - if (tokens.length != 2) { - return CgroupSubsystem.LONG_RETVAL_UNLIMITED; - } - String quota = tokens[tokenIdx]; - return limitFromString(quota); - } - - private long limitFromString(String strVal) { - if (strVal == null || MAX_VAL.equals(strVal)) { - return CgroupSubsystem.LONG_RETVAL_UNLIMITED; - } - return Long.parseLong(strVal); - } - - @Override - public long getCpuShares() { - long sharesRaw = getLongVal("cpu.weight"); - if (sharesRaw == 100 || sharesRaw <= 0) { - return CgroupSubsystem.LONG_RETVAL_UNLIMITED; - } - int shares = (int)sharesRaw; - // CPU shares (OCI) value needs to get translated into - // a proper Cgroups v2 value. See: - // https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller - // - // Use the inverse of (x == OCI value, y == cgroupsv2 value): - // ((262142 * y - 1)/9999) + 2 = x - // - int x = 262142 * shares - 1; - double frac = x/9999.0; - x = ((int)frac) + 2; - if ( x <= PER_CPU_SHARES ) { - return PER_CPU_SHARES; // mimic cgroups v1 - } - int f = x/PER_CPU_SHARES; - int lower_multiple = f * PER_CPU_SHARES; - int upper_multiple = (f + 1) * PER_CPU_SHARES; - int distance_lower = Math.max(lower_multiple, x) - Math.min(lower_multiple, x); - int distance_upper = Math.max(upper_multiple, x) - Math.min(upper_multiple, x); - x = distance_lower <= distance_upper ? lower_multiple : upper_multiple; - return x; - } - - @Override - public long getCpuNumPeriods() { - return CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "nr_periods"); - } - - @Override - public long getCpuNumThrottled() { - return CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "nr_throttled"); - } - - @Override - public long getCpuThrottledTime() { - long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "throttled_usec"); - if (micros < 0) { - return micros; - } - return TimeUnit.MICROSECONDS.toNanos(micros); - } - - @Override - public long getEffectiveCpuCount() { - return Runtime.getRuntime().availableProcessors(); - } - - @Override - public int[] getCpuSetCpus() { - String cpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus"); - return getCpuSet(cpuSetVal); - } - - @Override - public int[] getEffectiveCpuSetCpus() { - String effCpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus.effective"); - return getCpuSet(effCpuSetVal); - } - - @Override - public int[] getCpuSetMems() { - String cpuSetMems = CgroupSubsystemController.getStringValue(unified, "cpuset.mems"); - return getCpuSet(cpuSetMems); - } - - @Override - public int[] getEffectiveCpuSetMems() { - String effCpuSetMems = CgroupSubsystemController.getStringValue(unified, "cpuset.mems.effective"); - return getCpuSet(effCpuSetMems); - } - - private int[] getCpuSet(String cpuSetVal) { - if (cpuSetVal == null || EMPTY_STR.equals(cpuSetVal)) { - return INT_ARRAY_UNAVAILABLE; - } - return CgroupSubsystemController.stringRangeToIntArray(cpuSetVal); - } - - @Override - public long getMemoryFailCount() { - return CgroupV2SubsystemController.getLongEntry(unified, "memory.events", "max"); - } - - @Override - public long getMemoryLimit() { - String strVal = CgroupSubsystemController.getStringValue(unified, "memory.max"); - return limitFromString(strVal); - } - - @Override - public long getMemoryUsage() { - return getLongVal("memory.current"); - } - - @Override - public long getTcpMemoryUsage() { - return CgroupV2SubsystemController.getLongEntry(unified, "memory.stat", "sock"); - } - - @Override - public long getMemoryAndSwapLimit() { - String strVal = CgroupSubsystemController.getStringValue(unified, "memory.swap.max"); - return limitFromString(strVal); - } - - @Override - public long getMemoryAndSwapUsage() { - return getLongVal("memory.swap.current"); - } - - @Override - public long getMemorySoftLimit() { - String softLimitStr = CgroupSubsystemController.getStringValue(unified, "memory.high"); - return limitFromString(softLimitStr); - } - - @Override - public long getBlkIOServiceCount() { - return sumTokensIOStat(CgroupV2Subsystem::lineToRandWIOs); - } - - - @Override - public long getBlkIOServiced() { - return sumTokensIOStat(CgroupV2Subsystem::lineToRBytesAndWBytesIO); - } - - private long sumTokensIOStat(Function mapFunc) { - try { - long sum = 0L; - for (String line : CgroupUtil.readAllLinesPrivileged(Paths.get(unified.path(), "io.stat"))) { - sum += mapFunc.apply(line); - } - return sum; - } catch (IOException e) { - return CgroupSubsystem.LONG_RETVAL_UNLIMITED; - } - } - - private static String[] getRWIOMatchTokenNames() { - return new String[] { "rios", "wios" }; - } - - private static String[] getRWBytesIOMatchTokenNames() { - return new String[] { "rbytes", "wbytes" }; - } - - public static Long lineToRandWIOs(String line) { - String[] matchNames = getRWIOMatchTokenNames(); - return ioStatLineToLong(line, matchNames); - } - - public static Long lineToRBytesAndWBytesIO(String line) { - String[] matchNames = getRWBytesIOMatchTokenNames(); - return ioStatLineToLong(line, matchNames); - } - - private static Long ioStatLineToLong(String line, String[] matchNames) { - if (line == null || EMPTY_STR.equals(line)) { - return Long.valueOf(0); - } - String[] tokens = SubstrateUtil.split(line, " "); - long retval = 0; - for (String t: tokens) { - String[] valKeys = SubstrateUtil.split(t, "="); - if (valKeys.length != 2) { - // ignore device ids $MAJ:$MIN - continue; - } - for (String match: matchNames) { - if (match.equals(valKeys[0])) { - retval += longOrZero(valKeys[1]); - } - } - } - return Long.valueOf(retval); - } - - private static long longOrZero(String val) { - long lVal = 0; - try { - lVal = Long.parseLong(val); - } catch (NumberFormatException e) { - // keep at 0 - } - return lVal; - } -} diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv2/CgroupV2SubsystemController.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv2/CgroupV2SubsystemController.java deleted file mode 100644 index 05a55cde8479..000000000000 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv2/CgroupV2SubsystemController.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020, Red Hat Inc. - * 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. - */ - -// @formatter:off -package com.oracle.svm.core.containers.cgroupv2; - -import java.nio.file.Paths; - -import com.oracle.svm.core.containers.CgroupSubsystem; -import com.oracle.svm.core.containers.CgroupSubsystemController; - -public class CgroupV2SubsystemController implements CgroupSubsystemController { - - private final String path; - - public CgroupV2SubsystemController(String mountPath, String cgroupPath) { - this.path = Paths.get(mountPath, cgroupPath).toString(); - } - - @Override - public String path() { - return path; - } - - public static long convertStringToLong(String strval) { - return CgroupSubsystemController.convertStringToLong(strval, - CgroupSubsystem.LONG_RETVAL_UNLIMITED /* overflow retval */, - CgroupSubsystem.LONG_RETVAL_UNLIMITED /* default retval on error */); - } - - public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname) { - return CgroupSubsystemController.getLongEntry(controller, - param, - entryname, - CgroupSubsystem.LONG_RETVAL_UNLIMITED /* retval on error */); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java index 4b72769d0d39..6eed675e890a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java @@ -27,18 +27,15 @@ import static com.oracle.svm.core.Containers.Options.UseContainerSupport; import org.graalvm.compiler.options.Option; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.jdk.Jvm; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; +import jdk.internal.platform.Container; +import jdk.internal.platform.Metrics; + /** * Provides container awareness to the rest of the VM. * @@ -51,9 +48,6 @@ public static class Options { public static final HostedOptionKey UseContainerSupport = new HostedOptionKey<>(true); } - /** Sentinel used when the value is unknown. */ - public static final int UNKNOWN = -1; - /** * Calculates an appropriate number of active processors for the VM to use. The calculation is * based on these two inputs: @@ -85,10 +79,10 @@ public static int activeProcessorCount() { int limitCount = cpuCount; if (UseContainerSupport.getValue() && Platform.includedIn(Platform.LINUX.class)) { - ContainerInfo info = new ContainerInfo(); - if (info.isContainerized()) { - long quota = info.getCpuQuota(); - long period = info.getCpuPeriod(); + Metrics metrics = Container.metrics(); + if (metrics != null) { + long quota = metrics.getCpuQuota(); + long period = metrics.getCpuPeriod(); int quotaCount = 0; if (quota > -1 && period > 0) { @@ -110,8 +104,7 @@ public static int activeProcessorCount() { */ public static boolean isContainerized() { if (UseContainerSupport.getValue() && Platform.includedIn(Platform.LINUX.class)) { - ContainerInfo info = new ContainerInfo(); - return info.isContainerized(); + return Container.metrics() != null; } return false; } @@ -119,55 +112,20 @@ public static boolean isContainerized() { /** * Returns the limit of available memory for this process. * - * @return memory limit in bytes or {@link Containers#UNKNOWN} + * @return memory limit in bytes or -1 for unlimited */ public static long memoryLimitInBytes() { if (UseContainerSupport.getValue() && Platform.includedIn(Platform.LINUX.class)) { - ContainerInfo info = new ContainerInfo(); - if (info.isContainerized()) { - long memoryLimit = info.getMemoryLimit(); - if (memoryLimit > 0) { - return memoryLimit; - } + Metrics metrics; + try { + metrics = Container.metrics(); + } catch (StackOverflowError e) { + throw VMError.shouldNotReachHere("Could not get container metrics, likely due to using NIO in the container code of the JDK (JDK-8309191).", e); + } + if (metrics != null) { + return metrics.getMemoryLimit(); } } - return UNKNOWN; - } -} - -/** A simple wrapper around the Container Metrics API that abstracts over the used JDK. */ -@SuppressWarnings("static-method") -final class ContainerInfo { - private static final String ERROR_MSG = "JDK " + JavaVersionUtil.JAVA_SPEC + " specific overlay is missing."; - - boolean isContainerized() { - throw VMError.shouldNotReachHere(ERROR_MSG); - } - - long getCpuQuota() { - throw VMError.shouldNotReachHere(ERROR_MSG); - } - - long getCpuPeriod() { - throw VMError.shouldNotReachHere(ERROR_MSG); - } - - long getCpuShares() { - throw VMError.shouldNotReachHere(ERROR_MSG); - } - - long getMemoryLimit() { - throw VMError.shouldNotReachHere(ERROR_MSG); - } -} - -@AutomaticallyRegisteredFeature -@Platforms(Platform.LINUX.class) -class ContainersFeature implements InternalFeature { - @Override - public void duringSetup(DuringSetupAccess access) { - RuntimeClassInitializationSupport classInitSupport = ImageSingletons.lookup(RuntimeClassInitializationSupport.class); - classInitSupport.initializeAtRunTime("com.oracle.svm.core.containers.cgroupv1.CgroupV1Subsystem", "for cgroup support"); - classInitSupport.initializeAtRunTime("com.oracle.svm.core.containers.cgroupv2.CgroupV2Subsystem", "for cgroup support"); + return -1; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java index d9516fe2b2d3..ccfbf728b12e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java @@ -90,9 +90,9 @@ public static UnsignedWord size() { cachedSize = WordFactory.unsigned(memoryLimit); } else { memoryLimit = Containers.memoryLimitInBytes(); - cachedSize = memoryLimit == Containers.UNKNOWN - ? ImageSingletons.lookup(PhysicalMemorySupport.class).size() - : WordFactory.unsigned(memoryLimit); + cachedSize = memoryLimit > 0 + ? WordFactory.unsigned(memoryLimit) + : ImageSingletons.lookup(PhysicalMemorySupport.class).size(); } } finally { INITIALIZING.decrementAndGet(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKContainerSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKContainerSubstitutions.java index 1896966d38bc..2d7522f34733 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKContainerSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKContainerSubstitutions.java @@ -39,22 +39,6 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; -@TargetClass(className = "jdk.internal.platform.cgroupv1.CgroupV1Subsystem") -@Platforms(LINUX.class) -final class Target_jdk_internal_platform_cgroupv1_CgroupV1Subsystem { - @Alias // - @RecomputeFieldValue(kind = Kind.Reset) // - private static volatile Target_jdk_internal_platform_cgroupv1_CgroupV1Subsystem INSTANCE; -} - -@TargetClass(className = "jdk.internal.platform.cgroupv2.CgroupV2Subsystem") -@Platforms(LINUX.class) -final class Target_jdk_internal_platform_cgroupv2_CgroupV2Subsystem { - @Alias // - @RecomputeFieldValue(kind = Kind.Reset) // - private static volatile Target_jdk_internal_platform_cgroupv2_CgroupV2Subsystem INSTANCE; -} - @TargetClass(className = "jdk.jfr.internal.instrument.JDKEvents") @Platforms(LINUX.class) final class Target_jdk_jfr_internal_instrument_JDKEvents { diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystem.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/PlatformHasClass.java similarity index 71% rename from substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystem.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/PlatformHasClass.java index c6b27ffdaf37..458f74519940 100644 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupSubsystem.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/PlatformHasClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Red Hat Inc. + * Copyright (c) 2023, 2023, 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 @@ -22,20 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.oracle.svm.core.jdk; -// @formatter:off -package com.oracle.svm.core.containers; +import java.util.function.Predicate; -/** - * Marker interface for cgroup-based metrics - * - */ -public interface CgroupSubsystem extends Metrics { - - /** - * Returned for metrics of type long if the underlying implementation - * has determined that no limit is being imposed. - */ - public static final long LONG_RETVAL_UNLIMITED = -1; +import com.oracle.svm.util.ReflectionUtil; +/** A predicate to tell whether this platform includes the argument class. */ +final class PlatformHasClass implements Predicate { + @Override + public boolean test(String className) { + return ReflectionUtil.lookupClass(true, className) != null; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java index e7bbc43b2334..e799ceaa26d3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java @@ -405,20 +405,6 @@ private void verifyJars(URL var1, List var2) { } } -/** A predicate to tell whether this platform includes the argument class. */ -final class PlatformHasClass implements Predicate { - @Override - public boolean test(String className) { - try { - @SuppressWarnings({"unused"}) - final Class classForName = Class.forName(className); - return true; - } catch (ClassNotFoundException cnfe) { - return false; - } - } -} - final class ContainsVerifyJars implements Predicate> { @Override public boolean test(Class originalClass) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_CgroupMetrics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_CgroupMetrics.java index 89d59f167762..134d4b8a8eb5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_CgroupMetrics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_CgroupMetrics.java @@ -27,16 +27,19 @@ import static com.oracle.svm.core.Containers.Options.UseContainerSupport; import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -@Platforms(Platform.LINUX.class) -@TargetClass(className = "jdk.internal.platform.CgroupMetrics") -public final class Target_jdk_internal_platform_CgroupMetrics { +@TargetClass(className = "jdk.internal.platform.CgroupMetrics", onlyWith = PlatformHasClass.class) +final class Target_jdk_internal_platform_CgroupMetrics { @Substitute public static boolean isUseContainerSupport() { - return UseContainerSupport.getValue(); + /* + * It is important that this method can be folded to a constant before the static analysis, + * i.e., only relies on hosted options and other conditions that are constant. Inlining + * before analysis ensures that the constant is propagated out to call sites. + */ + return UseContainerSupport.getValue() && Platform.includedIn(Platform.LINUX.class); } } diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/ContainerInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_CgroupSubsystemFactory.java similarity index 56% rename from substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/ContainerInfo.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_CgroupSubsystemFactory.java index 6fb402e57326..7d43a6c4d847 100644 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/ContainerInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_CgroupSubsystemFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2023, 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 @@ -22,34 +22,27 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core; +package com.oracle.svm.core.jdk; -import static com.oracle.svm.core.Containers.UNKNOWN; +import java.util.function.Predicate; -import com.oracle.svm.core.containers.Container; -import com.oracle.svm.core.containers.Metrics; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.util.ReflectionUtil; -/** JDK 8 version of {@link ContainerInfo}. */ -final class ContainerInfo { - private final Metrics metrics = Container.metrics(); - - boolean isContainerized() { - return metrics != null; - } - - long getCpuQuota() { - return isContainerized() ? metrics.getCpuQuota() : UNKNOWN; - } - - long getCpuPeriod() { - return isContainerized() ? metrics.getCpuPeriod() : UNKNOWN; - } - - long getCpuShares() { - return isContainerized() ? metrics.getCpuShares() : UNKNOWN; +@TargetClass(className = "jdk.internal.platform.CgroupSubsystemFactory", onlyWith = PlatformHasClass.class) +final class Target_jdk_internal_platform_CgroupSubsystemFactory { + @Substitute + @TargetElement(onlyWith = HasWarnMethod.class) + static void warn(@SuppressWarnings("unused") String msg) { + /* Disable debug logging (JDK-8309191). */ } +} - long getMemoryLimit() { - return isContainerized() ? metrics.getMemoryLimit() : UNKNOWN; +final class HasWarnMethod implements Predicate> { + @Override + public boolean test(Class originalClass) { + return ReflectionUtil.lookupMethod(true, originalClass, "warn", String.class) != null; } } diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1MemorySubSystemController.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_cgroupv1_CgroupV1Subsystem.java similarity index 63% rename from substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1MemorySubSystemController.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_cgroupv1_CgroupV1Subsystem.java index fe42b922d778..816e10416c93 100644 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/cgroupv1/CgroupV1MemorySubSystemController.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_cgroupv1_CgroupV1Subsystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Red Hat Inc. + * Copyright (c) 2023, 2023, 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 @@ -22,24 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.oracle.svm.core.jdk; -// @formatter:off -package com.oracle.svm.core.containers.cgroupv1; - -public class CgroupV1MemorySubSystemController extends CgroupV1SubsystemController { - - private boolean hierarchical; - - public CgroupV1MemorySubSystemController(String root, String mountPoint) { - super(root, mountPoint); - } - - boolean isHierarchical() { - return hierarchical; - } - - void setHierarchical(boolean hierarchical) { - this.hierarchical = hierarchical; - } +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; +import com.oracle.svm.core.annotate.TargetClass; +@TargetClass(className = "jdk.internal.platform.cgroupv1.CgroupV1Subsystem", onlyWith = PlatformHasClass.class) +final class Target_jdk_internal_platform_cgroupv1_CgroupV1Subsystem { + @Alias @RecomputeFieldValue(kind = Kind.Reset) // + private static volatile Target_jdk_internal_platform_cgroupv1_CgroupV1Subsystem INSTANCE; } diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/Container.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_cgroupv2_CgroupV2Subsystem.java similarity index 63% rename from substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/Container.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_cgroupv2_CgroupV2Subsystem.java index 6a60d83bdef9..6afa00e67c55 100644 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/Container.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_platform_cgroupv2_CgroupV2Subsystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2023, 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 @@ -22,25 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -// @formatter:off -package com.oracle.svm.core.containers; +package com.oracle.svm.core.jdk; -/* - * @author bobv - * @since 11 - */ - -public class Container { - - private Container() { } +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; +import com.oracle.svm.core.annotate.TargetClass; - /** - * 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(); - } +@TargetClass(className = "jdk.internal.platform.cgroupv2.CgroupV2Subsystem", onlyWith = PlatformHasClass.class) +final class Target_jdk_internal_platform_cgroupv2_CgroupV2Subsystem { + @Alias @RecomputeFieldValue(kind = Kind.Reset) // + private static volatile Target_jdk_internal_platform_cgroupv2_CgroupV2Subsystem INSTANCE; } diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/CgroupSubsystemFactoryTest.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/CgroupSubsystemFactoryTest.java deleted file mode 100644 index 72b53e35528d..000000000000 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/CgroupSubsystemFactoryTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2022, 2022, 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 com.oracle.svm.test; - -import com.oracle.svm.core.containers.CgroupSubsystemFactory; -import com.oracle.svm.core.containers.CgroupSubsystemFactory.CgroupTypeResult; -import org.junit.Assert; -import org.junit.Test; - -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Objects; -import java.util.Optional; - -public class CgroupSubsystemFactoryTest { - - private static final String MOUNT_INFO_CG2 = "29 23 0:26 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:4 - cgroup2 cgroup2 rw,seclabel,nsdelegate,memory_recursiveprot\n" + - "23 60 0:22 / /sys rw,nosuid,nodev,noexec,relatime shared:2 - sysfs sysfs rw,seclabel\n"; - private static final String CGROUPS_CG2 = "#subsys_name hierarchy num_cgroups enabled\n" + "cpuset\t0\t142\t1\n" + "cpu\t0\t142\t1\n" + "cpuacct\t0\t142\t1\n" + "blkio\t0\t142\t1\n" + - "memory\t0\t142\t1\n" + "devices\t0\t142\t1\n" + "freezer\t0\t142\t1\n" + "net_cls\t0\t142\t1\n" + "perf_event\t0\t142\t1\n" + "net_prio\t0\t142\t1\n" + "hugetlb\t0\t142\t1\n" + - "pids\t0\t142\t1\n" + "misc\t0\t142\t1\n"; - - private static final String MOUNT_INFO_CG1 = "23 60 0:22 / /sys rw,nosuid,nodev,noexec,relatime shared:2 - sysfs sysfs rw,seclabel\n" + - "30 24 0:27 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:4 - tmpfs tmpfs ro,seclabel,size=4096k,nr_inodes=1024,mode=755,inode64\n" + - "31 30 0:28 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:5 - cgroup2 cgroup2 rw,seclabel,nsdelegate\n" + - "32 30 0:29 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:6 - cgroup cgroup rw,seclabel,xattr,name=systemd\n" + - "35 30 0:32 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:7 - cgroup cgroup rw,seclabel,cpuset\n" + - "36 30 0:33 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:8 - cgroup cgroup rw,seclabel,perf_event\n" + - "37 30 0:34 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:9 - cgroup cgroup rw,seclabel,freezer\n" + - "38 30 0:35 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,seclabel,net_cls,net_prio\n" + - "39 30 0:36 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,seclabel,pids\n" + - "40 30 0:37 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,seclabel,blkio\n" + - "41 30 0:38 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,seclabel,hugetlb\n" + - "42 30 0:39 / /sys/fs/cgroup/misc rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,seclabel,misc\n" + - "43 30 0:40 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,seclabel,cpu,cpuacct\n" + - "44 30 0:41 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,seclabel,devices\n" + - "45 30 0:42 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,seclabel,memory\n"; - private static final String CGROUPS_CG1 = "#subsys_name hierarchy num_cgroups enabled\n" + "cpuset\t2\t9\t1\n" + "cpu\t10\t21\t1\n" + "cpuacct\t10\t21\t1\n" + "blkio\t7\t16\t1\n" + - "memory\t12\t98\t1\n" + "devices\t11\t87\t1\n" + "freezer\t4\t4\t1\n" + "net_cls\t5\t4\t1\n" + "perf_event\t3\t4\t1\n" + "net_prio\t5\t4\t1\n" + "hugetlb\t8\t1\t1\n" + - "pids\t6\t90\t1\n" + "misc\t9\t1\t1\n"; - - private static final String MOUNT_INFO_NO_CGFS = "23 60 0:22 / /sys rw,nosuid,nodev,noexec,relatime shared:2 - sysfs sysfs rw,seclabel\n"; - - @Test - public void determineTypeCgroupsV2() { - try (CgroupMountInfoStub fixture = new CgroupMountInfoStub(MOUNT_INFO_CG2, CGROUPS_CG2)) { - Path cgroups = fixture.createCgroups(); - Path mountinfo = fixture.createMountInfo(); - Optional result = CgroupSubsystemFactory.determineType(mountinfo.toString(), cgroups.toString()); - Assert.assertTrue("Expected a non-empty result", result.isPresent()); - CgroupTypeResult actual = result.get(); - Assert.assertNotNull(actual); - Assert.assertTrue("Expected cgroup v2", actual.isCgroupV2()); - } catch (IOException e) { - fail("Unexpected failure " + e.getMessage()); - } - } - - @Test - public void determineTypeCgroupsV1() { - try (CgroupMountInfoStub fixture = new CgroupMountInfoStub(MOUNT_INFO_CG1, CGROUPS_CG1)) { - Path cgroups = fixture.createCgroups(); - Path mountinfo = fixture.createMountInfo(); - Optional result = CgroupSubsystemFactory.determineType(mountinfo.toString(), cgroups.toString()); - Assert.assertTrue("Expected a non-empty result", result.isPresent()); - CgroupTypeResult actual = result.get(); - Assert.assertNotNull(actual); - Assert.assertTrue("Expected cgroup v1", !actual.isCgroupV2()); - } catch (IOException e) { - fail("Unexpected failure " + e.getMessage()); - } - } - - @Test - public void determineTypeCgroupsV1NoCgroupMount() { - try (CgroupMountInfoStub fixture = new CgroupMountInfoStub(MOUNT_INFO_NO_CGFS, CGROUPS_CG2)) { - Path cgroups = fixture.createCgroups(); - Path mountinfo = fixture.createMountInfo(); - Optional result = CgroupSubsystemFactory.determineType(mountinfo.toString(), cgroups.toString()); - Assert.assertFalse("Expected a empty result", result.isPresent()); - } catch (IOException e) { - fail("Unexpected failure " + e.getMessage()); - } - } - - public static class CgroupMountInfoStub implements AutoCloseable { - - private final String mountInfoContent; - private final String cgroupsContent; - private final Path tmpDir; - private Path mountInfo; - private Path cgroups; - - public CgroupMountInfoStub(String mountInfoContent, String cgroupsContent) throws IOException { - this.mountInfoContent = mountInfoContent; - this.cgroupsContent = cgroupsContent; - this.tmpDir = Files.createTempDirectory(CgroupSubsystemFactoryTest.class.getSimpleName()); - } - - synchronized Path createMountInfo() throws IOException { - if (mountInfo == null) { - mountInfo = writeTmpFile(tmpDir, "proc-self-mountinfo", mountInfoContent); - } - return mountInfo; - } - - synchronized Path createCgroups() throws IOException { - if (cgroups == null) { - cgroups = writeTmpFile(tmpDir, "proc-cgroups", cgroupsContent); - } - return cgroups; - } - - private static Path writeTmpFile(Path parent, String name, String content) throws IOException { - Path file = Objects.requireNonNull(parent).resolve(name); - Files.writeString(file, content); - return file; - } - - @Override - public void close() throws IOException { - // Recursively delete the temporary directory of stub files - Files.walkFileTree(tmpDir, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - - }); - - } - } -} diff --git a/truffle/external_repos/simplelanguage/native/make_native.sh b/truffle/external_repos/simplelanguage/native/make_native.sh index 50ff38d3e24d..76a6e47aa5f7 100755 --- a/truffle/external_repos/simplelanguage/native/make_native.sh +++ b/truffle/external_repos/simplelanguage/native/make_native.sh @@ -48,4 +48,5 @@ fi --macro:truffle --no-fallback --initialize-at-build-time \ -cp ../language/target/simplelanguage.jar:../language/target/jars/antlr-runtime.jar:../launcher/target/sl-launcher.jar \ com.oracle.truffle.sl.launcher.SLMain \ - slnative + slnative \ + -H:-UseContainerSupport