1 /*
2  * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package gc.g1;
25 
26 /*
27  * @test TestLargePageUseForHeap.java
28  * @summary Test that Java heap is allocated using large pages of the appropriate size if available.
29  * @bug 8221517
30  * @modules java.base/jdk.internal.misc
31  * @library /test/lib
32  * @requires vm.gc.G1
33  * @build sun.hotspot.WhiteBox
34  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
35  * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
36         -XX:+IgnoreUnrecognizedVMOptions -XX:+UseLargePages gc.g1.TestLargePageUseForHeap
37  */
38 
39 import jdk.test.lib.process.OutputAnalyzer;
40 import jdk.test.lib.process.ProcessTools;
41 import jtreg.SkippedException;
42 import sun.hotspot.WhiteBox;
43 
44 public class TestLargePageUseForHeap {
45     static long largePageSize;
46     static long smallPageSize;
47 
checkSize(OutputAnalyzer output, long expectedSize, String pattern)48     static void checkSize(OutputAnalyzer output, long expectedSize, String pattern) {
49         String pageSizeStr = output.firstMatch(pattern, 1);
50 
51         if (pageSizeStr == null) {
52             output.reportDiagnosticSummary();
53             throw new RuntimeException("Match from '" + pattern + "' got 'null' expected: " + expectedSize);
54         }
55 
56         long size = parseMemoryString(pageSizeStr);
57         if (size != expectedSize) {
58             output.reportDiagnosticSummary();
59             throw new RuntimeException("Match from '" + pattern + "' got " + size + " expected: " + expectedSize);
60         }
61     }
62 
checkLargePageEnabled(OutputAnalyzer output)63     static boolean checkLargePageEnabled(OutputAnalyzer output) {
64         // This message is printed when tried to reserve a memory with large page but it failed.
65         String errorStr = "Reserve regular memory without large pages";
66         String heapPattern = ".*Heap: ";
67         // If errorStr is printed just before heap page log, reservation for Java Heap is failed.
68         String result = output.firstMatch(errorStr + "\n" +
69                                           "(?:.*Heap address: .*\n)?" // Heap address: 0x00000000f8000000, size: 128 MB, Compressed Oops mode: 32-bit
70                                           + heapPattern);
71         if (result != null) {
72             return false;
73         }
74         return true;
75     }
76 
checkHeap(OutputAnalyzer output, long expectedPageSize)77     static void checkHeap(OutputAnalyzer output, long expectedPageSize) throws Exception {
78         checkSize(output, expectedPageSize, "Heap: .*page_size=([^ ]+)");
79     }
80 
testVM(long regionSize)81     static void testVM(long regionSize) throws Exception {
82         ProcessBuilder pb;
83         // Test with large page enabled.
84         pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
85                                                    "-XX:G1HeapRegionSize=" + regionSize,
86                                                    "-Xmx128m",
87                                                    "-Xlog:pagesize,gc+heap+coops=debug",
88                                                    "-XX:+UseLargePages",
89                                                    "-version");
90 
91         OutputAnalyzer output = new OutputAnalyzer(pb.start());
92         boolean largePageEnabled = checkLargePageEnabled(output);
93         checkHeap(output, largePageEnabled ? largePageSize : smallPageSize);
94         output.shouldHaveExitValue(0);
95 
96         // Test with large page disabled.
97         pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
98                                                    "-XX:G1HeapRegionSize=" + regionSize,
99                                                    "-Xmx128m",
100                                                    "-Xlog:pagesize,gc+heap+coops=debug",
101                                                    "-XX:-UseLargePages",
102                                                    "-version");
103 
104         output = new OutputAnalyzer(pb.start());
105         checkHeap(output, smallPageSize);
106         output.shouldHaveExitValue(0);
107     }
108 
main(String[] args)109     public static void main(String[] args) throws Exception {
110         WhiteBox wb = WhiteBox.getWhiteBox();
111         smallPageSize = wb.getVMPageSize();
112         largePageSize = wb.getVMLargePageSize();
113 
114         if (largePageSize == 0) {
115             throw new SkippedException("Large page support does not seem to be available on this platform.");
116         }
117         if (largePageSize == smallPageSize) {
118             throw new SkippedException("Large page support does not seem to be available on this platform."
119                     + "Small and large page size are the same.");
120         }
121 
122         // G1HeapRegionSize=1MB
123         testVM(1 * 1024 * 1024);
124 
125         // G1HeapRegionSize=2MB
126         testVM(2 * 1024 * 1024);
127 
128         // G1HeapRegionSize=8MB
129         testVM(8 * 1024 * 1024);
130     }
131 
parseMemoryString(String value)132     public static long parseMemoryString(String value) {
133         long multiplier = 1;
134 
135         if (value.endsWith("B")) {
136             multiplier = 1;
137         } else if (value.endsWith("K")) {
138             multiplier = 1024;
139         } else if (value.endsWith("M")) {
140             multiplier = 1024 * 1024;
141         } else if (value.endsWith("G")) {
142             multiplier = 1024 * 1024 * 1024;
143         } else {
144             throw new IllegalArgumentException("Expected memory string '" + value + "'to end with either of: B, K, M, G");
145         }
146 
147         long longValue = Long.parseUnsignedLong(value.substring(0, value.length() - 1));
148 
149         return longValue * multiplier;
150     }
151 }
152