comparison agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children 7f601f7c9b48
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2003-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 package sun.jvm.hotspot.tools;
26
27 import java.io.*;
28 import java.util.*;
29
30 import sun.jvm.hotspot.debugger.*;
31 import sun.jvm.hotspot.memory.*;
32 import sun.jvm.hotspot.oops.*;
33 import sun.jvm.hotspot.runtime.*;
34 import sun.jvm.hotspot.tools.*;
35 import sun.jvm.hotspot.utilities.*;
36
37 /**
38 A command line tool to print perm. generation statistics.
39 */
40
41 public class PermStat extends Tool {
42 boolean verbose = true;
43
44 public static void main(String[] args) {
45 PermStat ps = new PermStat();
46 ps.start(args);
47 ps.stop();
48 }
49
50 private static class ClassData {
51 Klass klass;
52 long size;
53
54 ClassData(Klass klass, long size) {
55 this.klass = klass; this.size = size;
56 }
57 }
58
59 private static class LoaderData {
60 long numClasses;
61 long classSize;
62 List classDetail = new ArrayList(); // List<ClassData>
63 }
64
65 public void run() {
66 printInternStringStatistics();
67 printClassLoaderStatistics();
68 }
69
70 private void printInternStringStatistics() {
71 class StringStat implements StringTable.StringVisitor {
72 private int count;
73 private long size;
74 private OopField stringValueField;
75
76 StringStat() {
77 VM vm = VM.getVM();
78 SystemDictionary sysDict = vm.getSystemDictionary();
79 InstanceKlass strKlass = sysDict.getStringKlass();
80 // String has a field named 'value' of type 'char[]'.
81 stringValueField = (OopField) strKlass.findField("value", "[C");
82 }
83
84 private long stringSize(Instance instance) {
85 // We include String content in size calculation.
86 return instance.getObjectSize() +
87 stringValueField.getValue(instance).getObjectSize();
88 }
89
90 public void visit(Instance str) {
91 count++;
92 size += stringSize(str);
93 }
94
95 public void print() {
96 System.out.println(count +
97 " intern Strings occupying " + size + " bytes.");
98 }
99 }
100
101 StringStat stat = new StringStat();
102 StringTable strTable = VM.getVM().getStringTable();
103 strTable.stringsDo(stat);
104 stat.print();
105 }
106
107 private void printClassLoaderStatistics() {
108 final PrintStream out = System.out;
109 final PrintStream err = System.err;
110 final Map loaderMap = new HashMap();
111 // loader data for bootstrap class loader
112 final LoaderData bootstrapLoaderData = new LoaderData();
113 if (verbose) {
114 err.print("finding class loader instances ..");
115 }
116
117 VM vm = VM.getVM();
118 ObjectHeap heap = vm.getObjectHeap();
119 Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass();
120 try {
121 heap.iterateObjectsOfKlass(new DefaultHeapVisitor() {
122 public boolean doObj(Oop oop) {
123 loaderMap.put(oop, new LoaderData());
124 return false;
125 }
126 }, classLoaderKlass);
127 } catch (Exception se) {
128 se.printStackTrace();
129 }
130
131 if (verbose) {
132 err.println("done.");
133 err.print("computing per loader stat ..");
134 }
135
136 SystemDictionary dict = VM.getVM().getSystemDictionary();
137 dict.classesDo(new SystemDictionary.ClassAndLoaderVisitor() {
138 public void visit(Klass k, Oop loader) {
139 if (! (k instanceof InstanceKlass)) {
140 return;
141 }
142 LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader)
143 : bootstrapLoaderData;
144 if (ld != null) {
145 ld.numClasses++;
146 long size = computeSize((InstanceKlass)k);
147 ld.classDetail.add(new ClassData(k, size));
148 ld.classSize += size;
149 }
150 }
151 });
152
153 if (verbose) {
154 err.println("done.");
155 err.print("please wait.. computing liveness");
156 }
157
158 // compute reverse pointer analysis (takes long time for larger app)
159 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis();
160
161 if (verbose) {
162 analysis.setHeapProgressThunk(new HeapProgressThunk() {
163 public void heapIterationFractionUpdate(double fractionOfHeapVisited) {
164 err.print('.');
165 }
166 // This will be called after the iteration is complete
167 public void heapIterationComplete() {
168 err.println("done.");
169 }
170 });
171 }
172
173 try {
174 analysis.run();
175 } catch (Exception e) {
176 // e.printStackTrace();
177 if (verbose)
178 err.println("liveness analysis may be inaccurate ...");
179 }
180 ReversePtrs liveness = VM.getVM().getRevPtrs();
181
182 out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype");
183 out.println();
184
185 long numClassLoaders = 1L;
186 long totalNumClasses = bootstrapLoaderData.numClasses;
187 long totalClassSize = bootstrapLoaderData.classSize;
188 long numAliveLoaders = 1L;
189 long numDeadLoaders = 0L;
190
191 // print bootstrap loader details
192 out.print("<bootstrap>");
193 out.print('\t');
194 out.print(bootstrapLoaderData.numClasses);
195 out.print('\t');
196 out.print(bootstrapLoaderData.classSize);
197 out.print('\t');
198 out.print(" null ");
199 out.print('\t');
200 // bootstrap loader is always alive
201 out.print("live");
202 out.print('\t');
203 out.println("<internal>");
204
205 for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) {
206 Oop loader = (Oop) keyItr.next();
207 LoaderData data = (LoaderData) loaderMap.get(loader);
208 numClassLoaders ++;
209 totalNumClasses += data.numClasses;
210 totalClassSize += data.classSize;
211
212 out.print(loader.getHandle());
213 out.print('\t');
214 out.print(data.numClasses);
215 out.print('\t');
216 out.print(data.classSize);
217 out.print('\t');
218
219 class ParentFinder extends DefaultOopVisitor {
220 public void doOop(OopField field, boolean isVMField) {
221 if (field.getID().getName().equals("parent")) {
222 parent = field.getValue(getObj());
223 }
224 }
225 private Oop parent = null;
226 public Oop getParent() { return parent; }
227 }
228
229 ParentFinder parentFinder = new ParentFinder();
230 loader.iterate(parentFinder, false);
231 Oop parent = parentFinder.getParent();
232 out.print((parent != null)? parent.getHandle().toString() : " null ");
233 out.print('\t');
234 boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true;
235 out.print(alive? "live" : "dead");
236 if (alive) numAliveLoaders++; else numDeadLoaders++;
237 out.print('\t');
238 Klass loaderKlass = loader.getKlass();
239 if (loaderKlass != null) {
240 out.print(loaderKlass.getName().asString());
241 out.print('@');
242 out.print(loader.getKlass().getHandle());
243 } else {
244 out.print(" null! ");
245 }
246 out.println();
247 }
248
249 out.println();
250 // summary line
251 out.print("total = ");
252 out.print(numClassLoaders);
253 out.print('\t');
254 out.print(totalNumClasses);
255 out.print('\t');
256 out.print(totalClassSize);
257 out.print('\t');
258 out.print(" N/A ");
259 out.print('\t');
260 out.print("alive=");
261 out.print(numAliveLoaders);
262 out.print(", dead=");
263 out.print(numDeadLoaders);
264 out.print('\t');
265 out.print(" N/A ");
266 out.println();
267 }
268
269 private long computeSize(InstanceKlass k) {
270 long size = 0L;
271 // InstanceKlass object size
272 size += k.getObjectSize();
273
274 // add ConstantPool size
275 size += k.getConstants().getObjectSize();
276
277 // add ConstantPoolCache, if any
278 ConstantPoolCache cpCache = k.getConstants().getCache();
279 if (cpCache != null) {
280 size += cpCache.getObjectSize();
281 }
282
283 // add interfaces size
284 ObjArray interfaces = k.getLocalInterfaces();
285 size += (interfaces.getLength() != 0L)? interfaces.getObjectSize() : 0L;
286 ObjArray transitiveInterfaces = k.getTransitiveInterfaces();
287 size += (transitiveInterfaces.getLength() != 0L)? transitiveInterfaces.getObjectSize() : 0L;
288
289 // add inner classes size
290 TypeArray innerClasses = k.getInnerClasses();
291 size += innerClasses.getObjectSize();
292
293 // add fields size
294 size += k.getFields().getObjectSize();
295
296 // add methods size
297 ObjArray methods = k.getMethods();
298 size += (methods.getLength() != 0L)? methods.getObjectSize() : 0L;
299 TypeArray methodOrdering = k.getMethodOrdering();
300 size += (methodOrdering.getLength() != 0L)? methodOrdering.getObjectSize() : 0;
301
302 // add each method's size
303 int numMethods = (int) methods.getLength();
304 for (int i = 0; i < numMethods; i++) {
305 Method m = (Method) methods.getObjAt(i);
306 size += m.getObjectSize();
307 }
308
309 return size;
310 }
311 }