/* * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2023, 2024, 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. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test id=Default * @summary Test JVM large page setup (default options) * @library /test/lib * @requires os.family == "linux" * @modules java.base/jdk.internal.misc * java.management * @run driver TestHugePageDecisionsAtVMStartup */ /* * @test id=LP_enabled * @summary Test JVM large page setup (+LP) * @library /test/lib * @requires os.family == "linux" * @modules java.base/jdk.internal.misc * java.management * @run driver TestHugePageDecisionsAtVMStartup -XX:+UseLargePages */ /* * @test id=THP_enabled * @summary Test JVM large page setup (+THP) * @library /test/lib * @requires os.family == "linux" * @modules java.base/jdk.internal.misc * java.management * @run driver TestHugePageDecisionsAtVMStartup -XX:+UseTransparentHugePages */ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; public class TestHugePageDecisionsAtVMStartup { // End user warnings, printing with Xlog:pagesize at warning level, should be unconditional static final String warningNoTHP = "[warning][pagesize] UseTransparentHugePages disabled, transparent huge pages are not supported by the operating system."; static final String warningNoLP = "[warning][pagesize] UseLargePages disabled, no large pages configured and available on the system."; static final String buildSizeString(long l) { String units[] = { "K", "M", "G" }; long factor = 1024 * 1024 * 1024; for (int i = 2; i >= 0; i--) { if (l >= factor) { return Long.toString(l / factor) + units[i]; } factor /= 1024; } return Long.toString(l) + "B"; } static void testOutput(boolean useLP, boolean useTHP, OutputAnalyzer out, HugePageConfiguration configuration) { // Note: If something goes wrong, the JVM warns but continues, so we should never see an exit value != 0 out.shouldHaveExitValue(0); // Explicit hugepages: // Let X = the default hugepage size of the system (the one in /proc/meminfo). // The JVM will cycle through page sizes, starting at X, down to the smallest hugepage size. // // Example 1: a system with 1GB and 2MB pages, the default hugepage size is 1GB (can only be done // via kernel parameter). the JVM should first attempt to use 1GB pages, failing that should try 2MB, failing // that give up and disable -UseLargePages. // // Example 1: same system, but the default hugepage size is 2MB. The JVM should not attempt to use 1GB pages. // // This picture gets more complex with -XX:LargePageSizeInBytes, which overrides the default // large page size; but we ignore this for now (feel free to extend the test to cover LBSiB too). boolean haveUsableExplicitHugePages = false; if (configuration.supportsExplicitHugePages()) { long defaultLargePageSize = configuration.getExplicitDefaultHugePageSize(); Set configs = configuration.getExplicitHugePageConfigurations(); for (HugePageConfiguration.ExplicitHugePageConfig config: configs) { if (config.pageSize <= defaultLargePageSize) { if (config.nr_hugepages > 0 || config.nr_overcommit_hugepages > 0) { haveUsableExplicitHugePages = true; break; } } } } if (useTHP && !useLP) { useLP = true; // its implicit } if (!useLP) { out.shouldContain("[info][pagesize] Large page support disabled"); } else if (useLP && !useTHP && (!configuration.supportsExplicitHugePages() || !haveUsableExplicitHugePages)) { out.shouldContain(warningNoLP); } else if (useLP && useTHP && !configuration.supportsTHP()) { out.shouldContain(warningNoTHP); } else if (useLP && !useTHP && configuration.supportsExplicitHugePages() && haveUsableExplicitHugePages) { out.shouldContain("[info][pagesize] Using the default large page size: " + buildSizeString(configuration.getExplicitDefaultHugePageSize())); out.shouldContain("[info][pagesize] UseLargePages=1, UseTransparentHugePages=0"); out.shouldContain("[info][pagesize] Large page support enabled"); } else if (useLP && useTHP && configuration.supportsTHP()) { long thpPageSize = configuration.getThpPageSizeOrFallback(); String thpPageSizeString = buildSizeString(thpPageSize); // We expect to see exactly two "Usable page sizes" : the system page size and the THP page size. The system // page size differs, but its always in KB). out.shouldContain("[info][pagesize] UseLargePages=1, UseTransparentHugePages=1"); out.shouldMatch(".*\\[info]\\[pagesize] Large page support enabled. Usable page sizes: \\d+[kK], " + thpPageSizeString + ". Default large page size: " + thpPageSizeString + ".*"); } } public static void main(String[] extraOptions) throws Exception { List allOptions = new ArrayList(); if (extraOptions != null) { allOptions.addAll(Arrays.asList(extraOptions)); } allOptions.add("-Xmx128m"); allOptions.add("-Xlog:pagesize"); allOptions.add("-version"); boolean useLP = allOptions.contains("-XX:+UseLargePages"); boolean useTHP = allOptions.contains("-XX:+UseTransparentHugePages"); System.out.println("useLP: " + useLP + " useTHP: " + useTHP); ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(allOptions.toArray(new String[0])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.reportDiagnosticSummary(); HugePageConfiguration configuration = HugePageConfiguration.readFromOS(); System.out.println("configuration read from OS:" + configuration); testOutput(useLP, useTHP, output, configuration); } }