TestInstanceKlassSizeForInterface.java revision 12290:8953c0318163
1/*
2 * Copyright (c) 2015, 2016, 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
24import sun.jvm.hotspot.HotSpotAgent;
25import sun.jvm.hotspot.utilities.SystemDictionaryHelper;
26import sun.jvm.hotspot.oops.InstanceKlass;
27import sun.jvm.hotspot.debugger.*;
28
29import jdk.test.lib.JDKToolLauncher;
30import jdk.test.lib.JDKToolFinder;
31import jdk.test.lib.Platform;
32import jdk.test.lib.process.ProcessTools;
33import jdk.test.lib.process.OutputAnalyzer;
34import jdk.test.lib.Utils;
35import jdk.test.lib.Asserts;
36
37/*
38 * @test
39 * @library /test/lib
40 * @modules java.base/jdk.internal.misc
41 * @compile -XDignore.symbol.file=true
42 *          --add-modules=jdk.hotspot.agent
43 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
44 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
45 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
46 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED
47 *          TestInstanceKlassSizeForInterface.java
48 * @run main/othervm
49 *          --add-modules=jdk.hotspot.agent
50 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
51 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
52 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
53 *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED
54 *          TestInstanceKlassSizeForInterface
55 */
56
57interface Language {
58    static final long nbrOfWords = 99999;
59    public abstract long getNbrOfWords();
60}
61
62class ParselTongue implements Language {
63    public long getNbrOfWords() {
64      return nbrOfWords * 4;
65    }
66}
67
68public class TestInstanceKlassSizeForInterface {
69
70    private static void SAInstanceKlassSize(int pid,
71                                            String[] instanceKlassNames) {
72
73        HotSpotAgent agent = new HotSpotAgent();
74        try {
75            agent.attach((int)pid);
76        }
77        catch (DebuggerException e) {
78            System.out.println(e.getMessage());
79            System.err.println("Unable to connect to process ID: " + pid);
80
81            agent.detach();
82            e.printStackTrace();
83        }
84
85        for (String instanceKlassName : instanceKlassNames) {
86            InstanceKlass iKlass = SystemDictionaryHelper.findInstanceKlass(
87                                       instanceKlassName);
88            Asserts.assertNotNull(iKlass,
89                String.format("Unable to find instance klass for %s", instanceKlassName));
90            System.out.println("SA: The size of " + instanceKlassName +
91                               " is " + iKlass.getSize());
92        }
93        agent.detach();
94    }
95
96    private static String getJcmdInstanceKlassSize(OutputAnalyzer output,
97                                                   String instanceKlassName) {
98        for (String s : output.asLines()) {
99            if (s.contains(instanceKlassName)) {
100                String tokens[];
101                System.out.println(s);
102                tokens = s.split("\\s+");
103                return tokens[3];
104            }
105        }
106        return null;
107    }
108
109    private static void createAnotherToAttach(
110                            String[] instanceKlassNames) throws Exception {
111
112        ProcessBuilder pb = new ProcessBuilder();
113
114        // Grab the pid from the current java process and pass it
115        String[] toolArgs = {
116            "--add-modules=jdk.hotspot.agent",
117            "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED",
118            "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED",
119            "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED",
120            "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED",
121            "TestInstanceKlassSizeForInterface",
122            Long.toString(ProcessTools.getProcessId())
123        };
124
125        pb.command(new String[] {
126                          JDKToolFinder.getJDKTool("jcmd"),
127                          Long.toString(ProcessTools.getProcessId()),
128                          "GC.class_stats",
129                          "VTab,ITab,OopMap,KlassBytes"
130                      }
131                  );
132
133        // Start a new process to attach to the current process
134        ProcessBuilder processBuilder = ProcessTools
135                  .createJavaProcessBuilder(toolArgs);
136        OutputAnalyzer SAOutput = ProcessTools.executeProcess(processBuilder);
137        System.out.println(SAOutput.getOutput());
138
139        OutputAnalyzer jcmdOutput = new OutputAnalyzer(pb.start());
140        System.out.println(jcmdOutput.getOutput());
141
142        // Match the sizes from both the output streams
143        for (String instanceKlassName : instanceKlassNames) {
144            System.out.println ("Trying to match for " + instanceKlassName);
145            String jcmdInstanceKlassSize = getJcmdInstanceKlassSize(
146                                                      jcmdOutput,
147                                                      instanceKlassName);
148            Asserts.assertNotNull(jcmdInstanceKlassSize,
149                "Could not get the instance klass size from the jcmd output");
150            for (String s : SAOutput.asLines()) {
151                if (s.contains(instanceKlassName)) {
152                   Asserts.assertTrue(
153                      s.contains(jcmdInstanceKlassSize),
154                      "The size computed by SA for " +
155                      instanceKlassName + " does not match.");
156                }
157            }
158        }
159    }
160
161    public static void main (String... args) throws Exception {
162        String[] instanceKlassNames = new String[] {
163                                          "Language",
164                                          "ParselTongue",
165                                          "TestInstanceKlassSizeForInterface$1"
166                                      };
167
168        if (!Platform.shouldSAAttach()) {
169            System.out.println(
170               "SA attach not expected to work - test skipped.");
171            return;
172        }
173
174        if (args == null || args.length == 0) {
175            ParselTongue lang = new ParselTongue();
176
177            Language ventro = new Language() {
178                public long getNbrOfWords() {
179                    return nbrOfWords * 8;
180                }
181            };
182
183            // Not tested at this point. The test needs to be enhanced
184            // later to test for the sizes of the Lambda MetaFactory
185            // generated anonymous classes too. (After JDK-8160228 gets
186            // fixed.)
187            Runnable r2 = () -> System.out.println("Hello world!");
188            r2.run();
189
190            createAnotherToAttach(instanceKlassNames);
191        } else {
192            SAInstanceKlassSize(Integer.parseInt(args[0]), instanceKlassNames);
193        }
194    }
195}
196