36
36
import static jdk .test .lib .Platform .isWindows ;
37
37
38
38
/*
39
- * @test id=preTouch
39
+ * @test id=preTouchTest
40
40
* @summary Test AlwaysPreTouchThreadStacks
41
41
* @requires os.family != "aix"
42
42
* @library /test/lib
45
45
* @run driver TestAlwaysPreTouchStacks preTouch
46
46
*/
47
47
48
- /*
49
- * @test id=noPreTouch
50
- * @summary Test that only touched committed memory is reported as thread stack usage.
51
- * @requires os.family != "aix"
52
- * @library /test/lib
53
- * @modules java.base/jdk.internal.misc
54
- * java.management
55
- * @run driver TestAlwaysPreTouchStacks noPreTouch
56
- */
57
-
58
48
public class TestAlwaysPreTouchStacks {
59
49
60
50
// We will create a bunch of large-stacked threads to make a significant imprint on combined thread stack size
61
- final static int MB = 1024 * 1024 ;
51
+ final static int MB = 1024 * 1024 ;
62
52
static int memoryCeilingMB = 128 ;
63
53
static int threadStackSizeMB = 8 ;
64
54
static int numThreads = memoryCeilingMB / threadStackSizeMB ;
55
+ static long min_stack_usage_with_pretouch = 1 * MB ;
56
+ static long max_stack_usage_with_pretouch = (long )(0.75 * threadStackSizeMB * MB );
57
+
65
58
static CyclicBarrier gate = new CyclicBarrier (numThreads + 1 );
66
59
67
60
static private final Thread createTestThread (int num ) {
@@ -79,10 +72,76 @@ static private final Thread createTestThread(int num) {
79
72
}
80
73
},
81
74
"TestThread-" + num , threadStackSizeMB * MB );
75
+ // Let test threads run as daemons to ensure that they are still running and
76
+ // that their stacks are still allocated when the JVM shuts down and the final
77
+ // NMT report is printed.
82
78
t .setDaemon (true );
83
79
return t ;
84
80
}
85
81
82
+ private static long runPreTouchTest (boolean preTouch ) throws Exception {
83
+ long reserved = 0L , committed = 0L ;
84
+ ArrayList <String > vmArgs = new ArrayList <>();
85
+ Collections .addAll (vmArgs ,
86
+ "-XX:+UnlockDiagnosticVMOptions" ,
87
+ "-Xmx100M" ,
88
+ "-XX:NativeMemoryTracking=summary" , "-XX:+PrintNMTStatistics" );
89
+ if (preTouch ){
90
+ vmArgs .add ("-XX:+AlwaysPreTouchStacks" );
91
+ }
92
+ if (System .getProperty ("os.name" ).contains ("Linux" )) {
93
+ vmArgs .add ("-XX:-UseMadvPopulateWrite" );
94
+ }
95
+ Collections .addAll (vmArgs , "TestAlwaysPreTouchStacks" , "test" );
96
+ ProcessBuilder pb = ProcessTools .createLimitedTestJavaProcessBuilder (vmArgs );
97
+ OutputAnalyzer output = new OutputAnalyzer (pb .start ());
98
+
99
+ output .shouldHaveExitValue (0 );
100
+
101
+ for (int i = 0 ; i < numThreads ; i ++) {
102
+ output .shouldContain ("Alive: " + i );
103
+ }
104
+
105
+ // If using -XX:+AlwaysPreTouchStacks, we want to see, in the final NMT printout,
106
+ // a committed thread stack size very close to reserved stack size. Like this:
107
+ // - Thread (reserved=10332400KB, committed=10284360KB)
108
+ // (thread #10021)
109
+ // (stack: reserved=10301560KB, committed=10253520KB) <<<<
110
+ //
111
+ // ... without -XX:+AlwaysPreTouchStacks, the committed/reserved ratio for thread stacks should be
112
+ // a lot lower, e.g.:
113
+ // - Thread (reserved=10332400KB, committed=331828KB)
114
+ // (thread #10021)
115
+ // (stack: reserved=10301560KB, committed=300988KB) <<<
116
+
117
+ output .shouldMatch ("- *Thread.*reserved.*committed" );
118
+ output .reportDiagnosticSummary ();
119
+ Pattern pat = Pattern .compile (".*stack: reserved=(\\ d+), committed=(\\ d+).*" );
120
+ boolean foundLine = false ;
121
+ for (String line : output .asLines ()) {
122
+ Matcher m = pat .matcher (line );
123
+ if (m .matches ()) {
124
+ reserved = Long .parseLong (m .group (1 ));
125
+ committed = Long .parseLong (m .group (2 ));
126
+ System .out .println (">>>>> " + line + ": " + reserved + " - " + committed );
127
+ // Added sanity tests: we expect our test threads to be still alive when NMT prints its final
128
+ // report, so their stacks should dominate the NMT-reported total stack size.
129
+ long max_reserved = memoryCeilingMB * 3 * MB ;
130
+ long min_reserved = memoryCeilingMB * MB ;
131
+ if (reserved >= max_reserved || reserved < min_reserved ) {
132
+ throw new RuntimeException ("Total reserved stack sizes outside of our expectations (" + reserved +
133
+ ", expected " + min_reserved + ".." + max_reserved + ")" );
134
+ }
135
+ foundLine = true ;
136
+ break ;
137
+ }
138
+ }
139
+ if (!foundLine ) {
140
+ throw new RuntimeException ("Did not find expected NMT output" );
141
+ }
142
+ return committed ;
143
+ }
144
+
86
145
public static void main (String [] args ) throws Exception {
87
146
88
147
if (args .length == 1 && args [0 ].equals ("test" )) {
@@ -103,83 +162,23 @@ public static void main(String[] args) throws Exception {
103
162
// should show up with fully - or almost fully - committed thread stacks.
104
163
105
164
} else {
106
- boolean preTouch ;
107
- if (args .length == 1 && args [0 ].equals ("noPreTouch" )){
108
- preTouch = false ;
109
- } else if (args .length == 1 && args [0 ].equals ("preTouch" )){
110
- preTouch = true ;
111
- } else {
112
- throw new RuntimeException ("Invalid test input. Must be 'preTouch' or 'noPreTouch'." );
113
- }
114
- ArrayList <String > vmArgs = new ArrayList <>();
115
- Collections .addAll (vmArgs ,
116
- "-XX:+UnlockDiagnosticVMOptions" ,
117
- "-Xmx100M" ,
118
- "-XX:NativeMemoryTracking=summary" , "-XX:+PrintNMTStatistics" );
119
- if (preTouch ){
120
- vmArgs .add ("-XX:+AlwaysPreTouchStacks" );
121
- }
122
- if (System .getProperty ("os.name" ).contains ("Linux" )) {
123
- vmArgs .add ("-XX:-UseMadvPopulateWrite" );
124
- }
125
- Collections .addAll (vmArgs , "TestAlwaysPreTouchStacks" , "test" );
126
- ProcessBuilder pb = ProcessTools .createLimitedTestJavaProcessBuilder (vmArgs );
127
- OutputAnalyzer output = new OutputAnalyzer (pb .start ());
128
- output .reportDiagnosticSummary ();
129
-
130
- output .shouldHaveExitValue (0 );
131
-
132
- for (int i = 0 ; i < numThreads ; i ++) {
133
- output .shouldContain ("Alive: " + i );
134
- }
135
-
136
- // If using -XX:+AlwaysPreTouchStacks, we want to see, in the final NMT printout,
137
- // a committed thread stack size very close to reserved stack size. Like this:
138
- // - Thread (reserved=10332400KB, committed=10284360KB)
139
- // (thread #10021)
140
- // (stack: reserved=10301560KB, committed=10253520KB) <<<<
141
- //
142
- // ... without -XX:+AlwaysPreTouchStacks, the committed/reserved ratio for thread stacks should be
143
- // a lot lower, e.g.:
144
- // - Thread (reserved=10332400KB, committed=331828KB)
145
- // (thread #10021)
146
- // (stack: reserved=10301560KB, committed=300988KB) <<<
147
-
148
- output .shouldMatch ("- *Thread.*reserved.*committed" );
149
- Pattern pat = Pattern .compile (".*stack: reserved=(\\ d+), committed=(\\ d+).*" );
150
- boolean foundLine = false ;
151
- for (String line : output .asLines ()) {
152
- Matcher m = pat .matcher (line );
153
- if (m .matches ()) {
154
- long reserved = Long .parseLong (m .group (1 ));
155
- long committed = Long .parseLong (m .group (2 ));
156
- System .out .println (">>>>> " + line + ": " + reserved + " - " + committed );
157
- // This is a bit fuzzy: even with PreTouch we don't commit the full range of what NMT counts
158
- // as thread stack. But without pre-touching, the thread stacks would be committed to about 1/5th
159
- // of their reserved size. Requiring them to be committed for over 3/4th shows that pretouch is
160
- // really working.
161
- if (preTouch && (double )committed < ((double )reserved * 0.75 )) {
162
- throw new RuntimeException ("Expected a higher ratio between stack committed and reserved." );
163
- } else if (!preTouch && (double )committed > ((double )reserved * 0.50 )){
164
- throw new RuntimeException ("Expected a lower ratio between stack committed and reserved." );
165
- }
166
- // Added sanity tests: we expect our test threads to be still alive when NMT prints its final
167
- // report, so their stacks should dominate the NMT-reported total stack size.
168
- long max_reserved = memoryCeilingMB * 3 * MB ;
169
- long min_reserved = memoryCeilingMB * MB ;
170
- if (reserved >= max_reserved || reserved < min_reserved ) {
171
- throw new RuntimeException ("Total reserved stack sizes outside of our expectations (" + reserved +
172
- ", expected " + min_reserved + ".." + max_reserved + ")" );
173
- }
174
- foundLine = true ;
175
- break ;
176
- }
177
- }
178
- if (!foundLine ) {
179
- throw new RuntimeException ("Did not find expected NMT output" );
180
- }
181
- }
182
-
165
+ long pretouch_committed = runPreTouchTest (true );
166
+ long no_pretouch_committed = runPreTouchTest (false );
167
+ if (pretouch_committed == 0 || no_pretouch_committed == 0 ) {
168
+ throw new RuntimeException ("Could not run with PreTouch flag." );
169
+ }
170
+ long expected_delta = numThreads * (max_stack_usage_with_pretouch - min_stack_usage_with_pretouch );
171
+ long actual_delta = pretouch_committed - no_pretouch_committed ;
172
+ if (pretouch_committed <= (no_pretouch_committed + expected_delta )) {
173
+ throw new RuntimeException ("Expected a higher amount of committed with pretouch stacks" +
174
+ "PreTouch amount: " + pretouch_committed +
175
+ "NoPreTouch amount: " + (no_pretouch_committed + expected_delta ));
176
+ }
177
+ if (actual_delta < expected_delta ) {
178
+ throw new RuntimeException ("Expected a higher delta between stack committed of with and without pretouch." +
179
+ "Expected: " + expected_delta + " Actual: " + actual_delta );
180
+ }
181
+ }
183
182
}
184
183
185
184
}
0 commit comments