11/*
2- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2023, 2024, Red Hat, Inc. All rights reserved.
3+ * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
34 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
45 *
56 * This code is free software; you can redistribute it and/or modify it
5556
5657package compiler .print ;
5758
59+ import jdk .test .lib .Platform ;
5860import jdk .test .lib .process .OutputAnalyzer ;
5961import jdk .test .lib .process .ProcessTools ;
6062
6466
6567public class CompileCommandMemLimit {
6668
69+ // Method we don't specify; default memlimit should apply
6770 final static String METHOD1 = "method1" ;
71+ // Method we explicitly limit to 4K limit
6872 final static String METHOD2 = "method2" ;
73+ // Method for which we explicitly disable a limit on the command line.
74+ final static String METHOD3 = "method3" ;
6975
7076 static boolean c2 ;
7177 static boolean test_crash ;
@@ -77,27 +83,22 @@ public static void main(String[] args) throws Exception {
7783 default : throw new RuntimeException ("invalid argument" );
7884 }
7985 c2 = Boolean .parseBoolean (args [1 ]);
80- test (METHOD1 , METHOD2 );
81- test (METHOD2 , METHOD1 );
82- }
83-
84- private static void test (String include , String exclude ) throws Exception {
85-
86- // A method that is known to cost compilers a bit of memory to compile
8786
8887 List <String > options = new ArrayList <String >();
8988 options .add ("-Xcomp" );
9089 options .add ("-XX:-Inline" );
9190 options .add ("-Xmx100m" );
91+ options .add ("-XX:-CreateCoredumpOnCrash" );
9292 options .add ("-XX:CompileCommand=compileonly," + getTestClass () + "::*" );
93- // We pass a very small size to guarantee the crash
94- options .add ("-XX:CompileCommand=MemStat," + getTestMethod (include ) + ",print" );
95- if (test_crash ) {
96- options .add ("-XX:CompileCommand=MemLimit," + getTestMethod (include ) + ",4k~crash" );
97- options .add ("-XX:-CreateCoredumpOnCrash" );
98- } else {
99- options .add ("-XX:CompileCommand=MemLimit," + getTestMethod (include ) + ",4k" );
100- }
93+
94+ // We want a final report
95+ options .add ("-XX:CompileCommand=MemStat,*.*,print" );
96+
97+ // We limit method 2 to a very small limit that is guaranteed to trigger
98+ options .add ("-XX:CompileCommand=MemLimit," + getTestMethod (METHOD2 ) + ",4k" + (test_crash ? "~crash" : "" ));
99+
100+ // We disable any limit set on method 3
101+ options .add ("-XX:CompileCommand=MemLimit," + getTestMethod (METHOD3 ) + ",0" );
101102
102103 if (c2 ) {
103104 options .add ("-XX:-TieredCompilation" );
@@ -110,20 +111,22 @@ private static void test(String include, String exclude) throws Exception {
110111
111112 oa .reportDiagnosticSummary ();
112113
113- String expectedNameIncl = getTestMethod (include )
114- .replace ('.' , '/' )
115- .replace ("$" , "\\ $" );
116- String expectedNameExcl = getTestMethod (exclude )
117- .replace ('.' , '/' )
118- .replace ("$" , "\\ $" );
119-
114+ String method1regex = testMethodNameForRegex (getTestMethod (METHOD1 ));
115+ String method2regex = testMethodNameForRegex (getTestMethod (METHOD2 ));
116+ String method3regex = testMethodNameForRegex (getTestMethod (METHOD3 ));
120117 String ct = c2 ? "c2" : "c1" ;
121118
122119 if (test_crash ) {
123120 oa .shouldNotHaveExitValue (0 );
124121 oa .shouldMatch ("# *Internal Error.*" );
125- oa .shouldMatch ("# *fatal error: " + ct + " *" + expectedNameIncl + ".*: Hit MemLimit .*limit: 4096.*" );
126- oa .shouldNotMatch (".*" + expectedNameExcl + ".*" );
122+
123+ // method 2 should have hit its tiny limit
124+ oa .shouldMatch ("# *fatal error: " + ct + " *" + method2regex + ".*: Hit MemLimit .*limit: 4096.*" );
125+
126+ // none of the other ones should have hit a limit
127+ oa .shouldNotMatch (method1regex + ".*Hit MemLimit" );
128+ oa .shouldNotMatch (method3regex + ".*Hit MemLimit" );
129+
127130 // Make sure we get a non-zero-sized replay file (JDK-8331314)
128131 oa .shouldContain ("# Compiler replay data is saved as:" );
129132 String replayfile = oa .firstMatch ("# (\\ S+replay_pid\\ d+\\ .log)" , 1 );
@@ -137,18 +140,38 @@ private static void test(String include, String exclude) throws Exception {
137140 if (f .length () == 0 ) {
138141 throw new RuntimeException ("Replayfile " + replayfile + " has size 0" );
139142 }
140-
141143 } else {
142- // Should see trace output when methods are compiled
143- oa .shouldHaveExitValue (0 )
144- .shouldMatch (".*" + expectedNameIncl + ".*" )
145- .shouldNotMatch (".*" + expectedNameExcl + ".*" );
144+ oa .shouldHaveExitValue (0 );
145+
146+ // In debug builds we have an inbuilt MemLimit. It is very high, so we don't expect it to fire in this test.
147+ // But it will still show up in the final report.
148+ String implicitMemoryLimit = Platform .isDebugBuild () ? "1024M" : "-" ;
149+
150+ // With C2, we print number of nodes, with C1 we don't
151+ String numberNodesRegex = c2 ? "\\ d+" : "-" ;
146152
147- // Expect this log line
148- oa .shouldMatch (".* " + expectedNameIncl + ".*Hit MemLimit.* " );
153+ // method 2 should have hit its tiny limit
154+ oa .shouldMatch (ct + " " + method2regex + ".*: Hit MemLimit \\ (limit: 4096 now: \\ d+ \\ ) " );
149155
150- // Expect final output to contain "oom"
151- oa .shouldMatch (".*oom.*" + expectedNameIncl + ".*" );
156+ // neither of the other ones should have hit a limit
157+ oa .shouldNotMatch (method1regex + ".*Hit MemLimit" );
158+ oa .shouldNotMatch (method3regex + ".*Hit MemLimit" );
159+
160+ // Final report:
161+ // Method 1 should show up as "ok" and with the default limit, e.g.
162+ // total NA RA result #nodes limit time type #rc thread method
163+ // 32728 0 32728 ok - 1024M 0.045 c1 1 0x000000011b019c10 compiler/print/CompileCommandMemLimit$TestMain::method1(()J)
164+ oa .shouldMatch ("\\ d+ +\\ d+ +\\ d+ +ok +" + numberNodesRegex + " +" + implicitMemoryLimit + " +.* +" + method1regex );
165+
166+ // Method 2 should show up as "oom" and with its tiny limit, e.g.
167+ // total NA RA result #nodes limit time type #rc thread method
168+ // 32728 0 32728 oom - 4096B 0.045 c1 1 0x000000011b019c10 compiler/print/CompileCommandMemLimit$TestMain::method1(()J)
169+ oa .shouldMatch ("\\ d+ +\\ d+ +\\ d+ +oom +" + numberNodesRegex + " +4096B +.* +" + method2regex );
170+
171+ // Method 3 should show up as "ok", and with no limit, even in debug builds, e.g.
172+ // total NA RA result #nodes limit time type #rc thread method
173+ // 32728 0 32728 ok - - 0.045 c1 1 0x000000011b019c10 compiler/print/CompileCommandMemLimit$TestMain::method1(()J)
174+ oa .shouldMatch ("\\ d+ +\\ d+ +\\ d+ +ok +" + numberNodesRegex + " +- +.* +" + method3regex );
152175 }
153176 }
154177
@@ -161,16 +184,23 @@ public static String getTestMethod(String method) {
161184 return getTestClass () + "::" + method ;
162185 }
163186
187+ private static String testMethodNameForRegex (String m ) {
188+ return m .replace ('.' , '/' )
189+ .replace ("$" , "\\ $" );
190+ }
191+
164192 public static class TestMain {
165193 public static void main (String [] args ) {
166194 method1 ();
167195 method2 ();
196+ method3 ();
168197 }
169198
170199 static long method1 () {
171200 return System .currentTimeMillis ();
172201 }
173202 static void method2 () {}
203+ static void method3 () {}
174204 }
175205}
176206
0 commit comments