1 /*
 2  * Copyright Amazon.com Inc. 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 import jdk.test.lib.process.OutputAnalyzer;
25 import jdk.test.lib.process.ProcessTools;
26 
27 import java.io.IOException;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 /*
32  * @test
33  * @summary Tests that recursive locking doesn't cause excessive native memory usage
34  * @library /test/lib
35  * @run driver TestRecursiveMonitorChurn
36  */
37 public class TestRecursiveMonitorChurn {
38     static class Monitor {
39         public static volatile int i, j;
40         synchronized void doSomething() {
41             i++;
42             doSomethingElse();
43         }
44         synchronized void doSomethingElse() {
45             j++;
46         }
47     }
48 
49     public static volatile Monitor monitor;
50     public static void main(String[] args) throws IOException {
51         if (args.length == 1 && args[0].equals("test")) {
52             // The actual test, in a forked JVM.
53             for (int i = 0; i < 100000; i++) {
54                 monitor = new Monitor();
55                 monitor.doSomething();
56             }
57             System.out.println("i + j = " + (Monitor.i + Monitor.j));
58         } else {
59             ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
60                     "-XX:+UnlockDiagnosticVMOptions",
61                     "-Xmx100M", "-XX:AsyncDeflationInterval=0", "-XX:GuaranteedAsyncDeflationInterval=0",
62                     "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics",
63                     "TestRecursiveMonitorChurn",
64                     "test");
65             OutputAnalyzer output = new OutputAnalyzer(pb.start());
66             output.reportDiagnosticSummary();
67 
68             output.shouldHaveExitValue(0);
69 
70             // We want to see, in the final NMT printout, a committed object monitor size that is reasonably low.
71             // Like this:
72             // -           Object Monitors (reserved=208, committed=208)
73             //                             (malloc=208 #1) (at peak)
74             //
75             // Without recursive locking support, this would look more like this:
76             // -           Object Monitors (reserved=20800624, committed=20800624)
77             //                             (malloc=20800624 #100003) (at peak)
78 
79             Pattern pat = Pattern.compile("- *Object Monitors.*reserved=(\\d+), committed=(\\d+).*");
80             for (String line : output.asLines()) {
81                 Matcher m = pat.matcher(line);
82                 if (m.matches()) {
83                     long reserved = Long.parseLong(m.group(1));
84                     long committed = Long.parseLong(m.group(2));
85                     System.out.println(">>>>> " + line + ": " + reserved + " - " + committed);
86                     if (committed > 1000) {
87                         throw new RuntimeException("Allocated too many monitors");
88                     }
89                     return;
90                 }
91             }
92             throw new RuntimeException("Did not find expected NMT output");
93         }
94     }
95 }