104104*/
105105
106106import java .io .File ;
107- import java .nio .file .Files ;
108- import java .nio .file .Path ;
109- import java .nio .file .Paths ;
110- import java .nio .file .StandardCopyOption ;
111- import java .util .LinkedList ;
112107import java .util .Scanner ;
113108import java .util .regex .Matcher ;
114109import java .util .regex .Pattern ;
115110import jdk .test .lib .Platform ;
111+ import jdk .test .lib .SmapsParser ;
112+ import jdk .test .lib .SmapsParser .RangeWithPageSize ;
116113import jtreg .SkippedException ;
117114
118115// Check that page sizes logged match what is recorded in /proc/self/smaps.
119116// For transparent huge pages the matching is best effort since we can't
120117// know for sure what the underlying page size is.
121118public class TestTracePageSizes {
122- // Store address ranges with known page size.
123- private static LinkedList <RangeWithPageSize > ranges = new LinkedList <>();
124119 private static boolean debug ;
125120 private static int run ;
126121
127- // Copy smaps locally
128- // (To minimize chances of concurrent modification when parsing, as well as helping with error analysis)
129- private static Path copySmaps () throws Exception {
130- Path p1 = Paths .get ("/proc/self/smaps" );
131- Path p2 = Paths .get ("smaps-copy-" + ProcessHandle .current ().pid () + "-" + (run ++) + ".txt" );
132- Files .copy (p1 , p2 , StandardCopyOption .REPLACE_EXISTING );
133- debug ("Copied " + p1 + " to " + p2 + "..." );
134- return p2 ;
135- }
136-
137- // Parse /proc/self/smaps.
138- private static void parseSmaps () throws Exception {
139- // We can override the smaps file to parse to pass in a pre-fetched one
140- String smapsFileToParse = System .getProperty ("smaps-file" );
141- if (smapsFileToParse != null ) {
142- parseSmaps (Paths .get (smapsFileToParse ));
143- } else {
144- Path smapsCopy = copySmaps ();
145- parseSmaps (smapsCopy );
146- }
147- }
148-
149- static class SmapsParser {
150- // This is a simple smaps parser; it will recognize smaps section start lines
151- // (e.g. "40fa00000-439b80000 rw-p 00000000 00:00 0 ") and look for keywords inside the section.
152- // Section will be finished and written into a RangeWithPageSize when either the next section is found
153- // or the end of file is encountered.
154- static final Pattern SECTION_START_PATT = Pattern .compile ("^([a-f0-9]+)-([a-f0-9]+) [\\ -rwpsx]{4}.*" );
155- static final Pattern KERNEL_PAGESIZE_PATT = Pattern .compile ("^KernelPageSize:\\ s*(\\ d*) kB" );
156- static final Pattern THP_ELIGIBLE_PATT = Pattern .compile ("^THPeligible:\\ s+(\\ d*)" );
157- static final Pattern VMFLAGS_PATT = Pattern .compile ("^VmFlags: ([\\ w\\ ? ]*)" );
158- String start ;
159- String end ;
160- String ps ;
161- String thpEligible ;
162- String vmFlags ;
163- int lineno ;
164-
165- void reset () {
166- start = null ;
167- end = null ;
168- ps = null ;
169- thpEligible = null ;
170- vmFlags = null ;
171- }
172-
173- public void finish () {
174- if (start != null ) {
175- RangeWithPageSize range = new RangeWithPageSize (start , end , ps , thpEligible , vmFlags );
176- ranges .add (range );
177- debug ("Added range: " + range );
178- reset ();
179- }
180- }
181-
182- void eatNext (String line ) {
183- // For better debugging experience call finish here before the debug() call.
184- Matcher matSectionStart = SECTION_START_PATT .matcher (line );
185- if (matSectionStart .matches ()) {
186- finish ();
187- }
188-
189- debug ("" + (lineno ++) + " " + line );
190-
191- if (matSectionStart .matches ()) {
192- start = matSectionStart .group (1 );
193- end = matSectionStart .group (2 );
194- ps = null ;
195- vmFlags = null ;
196- return ;
197- } else {
198- Matcher matKernelPageSize = KERNEL_PAGESIZE_PATT .matcher (line );
199- if (matKernelPageSize .matches ()) {
200- ps = matKernelPageSize .group (1 );
201- return ;
202- }
203- Matcher matTHPEligible = THP_ELIGIBLE_PATT .matcher (line );
204- if (matTHPEligible .matches ()) {
205- thpEligible = matTHPEligible .group (1 );
206- return ;
207- }
208- Matcher matVmFlags = VMFLAGS_PATT .matcher (line );
209- if (matVmFlags .matches ()) {
210- vmFlags = matVmFlags .group (1 );
211- return ;
212- }
213- }
214- }
215- }
216-
217- // Parse /proc/self/smaps
218- private static void parseSmaps (Path smapsFileToParse ) throws Exception {
219- debug ("Parsing: " + smapsFileToParse .getFileName () + "..." );
220- SmapsParser parser = new SmapsParser ();
221- Files .lines (smapsFileToParse ).forEach (parser ::eatNext );
222- parser .finish ();
223- }
224-
225- // Search for a range including the given address.
226- private static RangeWithPageSize getRange (String addr ) {
227- long laddr = Long .decode (addr );
228- for (RangeWithPageSize range : ranges ) {
229- if (range .includes (laddr )) {
230- return range ;
231- }
232- }
233- return null ;
234- }
235-
236122 // Helper to get the page size in KB given a page size parsed
237123 // from log_info(pagesize) output.
238124 private static long pageSizeInKB (String pageSize ) {
@@ -272,7 +158,8 @@ public static void main(String args[]) throws Exception {
272158 }
273159
274160 // Parse /proc/self/smaps to compare with values logged in the VM.
275- parseSmaps ();
161+ SmapsParser smapsParser = new SmapsParser ();
162+ smapsParser .parse ("-" + (run ++));
276163
277164 // Setup patters for the JVM page size logging.
278165 String traceLinePatternString = ".*base=(0x[0-9A-Fa-f]*).* page_size=(\\ d+[BKMG]).*" ;
@@ -289,7 +176,7 @@ public static void main(String args[]) throws Exception {
289176 String address = trace .group (1 );
290177 String pageSize = trace .group (2 );
291178
292- RangeWithPageSize range = getRange (address );
179+ RangeWithPageSize range = smapsParser . getRange (address );
293180 if (range == null ) {
294181 debug ("Could not find range for: " + line );
295182 throw new AssertionError ("No memory range found for address: " + address );
@@ -325,75 +212,3 @@ private static void debug(String str) {
325212 }
326213 }
327214}
328-
329- // Class used to store information about memory ranges parsed
330- // from /proc/self/smaps. The file contain a lot of information
331- // about the different mappings done by an application, but the
332- // lines we care about are:
333- // 700000000-73ea00000 rw-p 00000000 00:00 0
334- // ...
335- // KernelPageSize: 4 kB
336- // ...
337- // VmFlags: rd wr mr mw me ac sd
338- //
339- // We use the VmFlags to know what kind of huge pages are used.
340- // For transparent huge pages the KernelPageSize field will not
341- // report the large page size.
342- class RangeWithPageSize {
343- private long start ;
344- private long end ;
345- private long pageSize ;
346- private boolean thpEligible ;
347- private boolean vmFlagHG ;
348- private boolean vmFlagHT ;
349- private boolean isTHP ;
350-
351- public RangeWithPageSize (String start , String end , String pageSize , String thpEligible , String vmFlags ) {
352- // Note: since we insist on kernels >= 3.8, all the following information should be present
353- // (none of the input strings be null).
354- this .start = Long .parseUnsignedLong (start , 16 );
355- this .end = Long .parseUnsignedLong (end , 16 );
356- this .pageSize = Long .parseLong (pageSize );
357- this .thpEligible = thpEligible == null ? false : (Integer .parseInt (thpEligible ) == 1 );
358-
359- vmFlagHG = false ;
360- vmFlagHT = false ;
361- // Check if the vmFlags line include:
362- // * ht - Meaning the range is mapped using explicit huge pages.
363- // * hg - Meaning the range is madvised huge.
364- for (String flag : vmFlags .split (" " )) {
365- if (flag .equals ("ht" )) {
366- vmFlagHT = true ;
367- } else if (flag .equals ("hg" )) {
368- vmFlagHG = true ;
369- }
370- }
371-
372- // When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false,
373- // therefore also check thpEligible. If this is still causing problems in the future,
374- // we might have to check the AnonHugePages field.
375-
376- isTHP = vmFlagHG || this .thpEligible ;
377- }
378-
379- public long getPageSize () {
380- return pageSize ;
381- }
382-
383- public boolean isTransparentHuge () {
384- return isTHP ;
385- }
386-
387- public boolean isExplicitHuge () {
388- return vmFlagHT ;
389- }
390-
391- public boolean includes (long addr ) {
392- return start <= addr && addr < end ;
393- }
394-
395- public String toString () {
396- return "[" + Long .toHexString (start ) + ", " + Long .toHexString (end ) + ") " +
397- "pageSize=" + pageSize + "KB isTHP=" + isTHP + " isHUGETLB=" + vmFlagHT ;
398- }
399- }
0 commit comments