comparison src/share/vm/memory/heapInspection.cpp @ 7956:16fb9f942703

6479360: PrintClassHistogram improvements Summary: jcmd <pid> GC.class_stats (UnlockDiagnosticVMOptions) Reviewed-by: coleenp, hseigel, sla, acorn Contributed-by: ioi.lam@oracle.com
author acorn
date Fri, 25 Jan 2013 15:06:18 -0500
parents da91efe96a93
children 3c9bc17b9403
comparison
equal deleted inserted replaced
7950:6cf2530f7fd3 7956:16fb9f942703
1 /* 1 /*
2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
21 * questions. 21 * questions.
22 * 22 *
23 */ 23 */
24 24
25 #include "precompiled.hpp" 25 #include "precompiled.hpp"
26 #include "classfile/classLoaderData.hpp"
26 #include "gc_interface/collectedHeap.hpp" 27 #include "gc_interface/collectedHeap.hpp"
27 #include "memory/genCollectedHeap.hpp" 28 #include "memory/genCollectedHeap.hpp"
28 #include "memory/heapInspection.hpp" 29 #include "memory/heapInspection.hpp"
29 #include "memory/resourceArea.hpp" 30 #include "memory/resourceArea.hpp"
30 #include "runtime/os.hpp" 31 #include "runtime/os.hpp"
39 if(e1->_instance_words > e2->_instance_words) { 40 if(e1->_instance_words > e2->_instance_words) {
40 return -1; 41 return -1;
41 } else if(e1->_instance_words < e2->_instance_words) { 42 } else if(e1->_instance_words < e2->_instance_words) {
42 return 1; 43 return 1;
43 } 44 }
44 return 0; 45 // Sort alphabetically, note 'Z' < '[' < 'a', but it's better to group
45 } 46 // the array classes before all the instance classes.
46
47 void KlassInfoEntry::print_on(outputStream* st) const {
48 ResourceMark rm; 47 ResourceMark rm;
49 const char* name;; 48 const char* name1 = e1->klass()->external_name();
49 const char* name2 = e2->klass()->external_name();
50 bool d1 = (name1[0] == '[');
51 bool d2 = (name2[0] == '[');
52 if (d1 && !d2) {
53 return -1;
54 } else if (d2 && !d1) {
55 return 1;
56 } else {
57 return strcmp(name1, name2);
58 }
59 }
60
61 const char* KlassInfoEntry::name() const {
62 const char* name;
50 if (_klass->name() != NULL) { 63 if (_klass->name() != NULL) {
51 name = _klass->external_name(); 64 name = _klass->external_name();
52 } else { 65 } else {
53 if (_klass == Universe::boolArrayKlassObj()) name = "<boolArrayKlass>"; else 66 if (_klass == Universe::boolArrayKlassObj()) name = "<boolArrayKlass>"; else
54 if (_klass == Universe::charArrayKlassObj()) name = "<charArrayKlass>"; else 67 if (_klass == Universe::charArrayKlassObj()) name = "<charArrayKlass>"; else
58 if (_klass == Universe::shortArrayKlassObj()) name = "<shortArrayKlass>"; else 71 if (_klass == Universe::shortArrayKlassObj()) name = "<shortArrayKlass>"; else
59 if (_klass == Universe::intArrayKlassObj()) name = "<intArrayKlass>"; else 72 if (_klass == Universe::intArrayKlassObj()) name = "<intArrayKlass>"; else
60 if (_klass == Universe::longArrayKlassObj()) name = "<longArrayKlass>"; else 73 if (_klass == Universe::longArrayKlassObj()) name = "<longArrayKlass>"; else
61 name = "<no name>"; 74 name = "<no name>";
62 } 75 }
76 return name;
77 }
78
79 void KlassInfoEntry::print_on(outputStream* st) const {
80 ResourceMark rm;
81
63 // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit 82 // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit
64 st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s", 83 st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s",
65 (jlong) _instance_count, 84 (jlong) _instance_count,
66 (julong) _instance_words * HeapWordSize, 85 (julong) _instance_words * HeapWordSize,
67 name); 86 name());
68 } 87 }
69 88
70 KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) { 89 KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) {
71 KlassInfoEntry* elt = _list; 90 KlassInfoEntry* elt = _list;
72 while (elt != NULL) { 91 while (elt != NULL) {
99 delete elt; 118 delete elt;
100 elt = next; 119 elt = next;
101 } 120 }
102 } 121 }
103 122
104 KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { 123 void KlassInfoTable::AllClassesFinder::do_klass(Klass* k) {
124 // This has the SIDE EFFECT of creating a KlassInfoEntry
125 // for <k>, if one doesn't exist yet.
126 _table->lookup(k);
127 }
128
129 KlassInfoTable::KlassInfoTable(int size, HeapWord* ref,
130 bool need_class_stats) {
105 _size = 0; 131 _size = 0;
106 _ref = ref; 132 _ref = ref;
107 _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size, mtInternal); 133 _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size, mtInternal);
108 if (_buckets != NULL) { 134 if (_buckets != NULL) {
109 _size = size; 135 _size = size;
110 for (int index = 0; index < _size; index++) { 136 for (int index = 0; index < _size; index++) {
111 _buckets[index].initialize(); 137 _buckets[index].initialize();
138 }
139 if (need_class_stats) {
140 AllClassesFinder finder(this);
141 ClassLoaderDataGraph::classes_do(&finder);
112 } 142 }
113 } 143 }
114 } 144 }
115 145
116 KlassInfoTable::~KlassInfoTable() { 146 KlassInfoTable::~KlassInfoTable() {
163 193
164 int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { 194 int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) {
165 return (*e1)->compare(*e1,*e2); 195 return (*e1)->compare(*e1,*e2);
166 } 196 }
167 197
168 KlassInfoHisto::KlassInfoHisto(const char* title, int estimatedCount) : 198 KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount) :
199 _cit(cit),
169 _title(title) { 200 _title(title) {
170 _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<KlassInfoEntry*>(estimatedCount,true); 201 _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<KlassInfoEntry*>(estimatedCount,true);
171 } 202 }
172 203
173 KlassInfoHisto::~KlassInfoHisto() { 204 KlassInfoHisto::~KlassInfoHisto() {
194 } 225 }
195 st->print_cr("Total " INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13), 226 st->print_cr("Total " INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13),
196 total, totalw * HeapWordSize); 227 total, totalw * HeapWordSize);
197 } 228 }
198 229
199 void KlassInfoHisto::print_on(outputStream* st) const { 230 #define MAKE_COL_NAME(field, name, help) #name,
200 st->print_cr("%s",title()); 231 #define MAKE_COL_HELP(field, name, help) help,
201 print_elements(st); 232
233 static const char *name_table[] = {
234 HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_NAME)
235 };
236
237 static const char *help_table[] = {
238 HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_HELP)
239 };
240
241 bool KlassInfoHisto::is_selected(const char *col_name) {
242 if (_selected_columns == NULL) {
243 return true;
244 }
245 if (strcmp(_selected_columns, col_name) == 0) {
246 return true;
247 }
248
249 const char *start = strstr(_selected_columns, col_name);
250 if (start == NULL) {
251 return false;
252 }
253
254 // The following must be true, because _selected_columns != col_name
255 if (start > _selected_columns && start[-1] != ',') {
256 return false;
257 }
258 char x = start[strlen(col_name)];
259 if (x != ',' && x != '\0') {
260 return false;
261 }
262
263 return true;
264 }
265
266 void KlassInfoHisto::print_title(outputStream* st, bool csv_format,
267 bool selected[], int width_table[],
268 const char *name_table[]) {
269 if (csv_format) {
270 st->print("Index,Super");
271 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
272 if (selected[c]) {st->print(",%s", name_table[c]);}
273 }
274 st->print(",ClassName");
275 } else {
276 st->print("Index Super");
277 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
278 if (selected[c]) {st->print(str_fmt(width_table[c]), name_table[c]);}
279 }
280 st->print(" ClassName");
281 }
282
283 if (is_selected("ClassLoader")) {
284 st->print(",ClassLoader");
285 }
286 st->cr();
287 }
288
289 void KlassInfoHisto::print_class_stats(outputStream* st,
290 bool csv_format, const char *columns) {
291 ResourceMark rm;
292 KlassSizeStats sz, sz_sum;
293 int i;
294 julong *col_table = (julong*)(&sz);
295 julong *colsum_table = (julong*)(&sz_sum);
296 int width_table[KlassSizeStats::_num_columns];
297 bool selected[KlassSizeStats::_num_columns];
298
299 _selected_columns = columns;
300
301 memset(&sz_sum, 0, sizeof(sz_sum));
302 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
303 selected[c] = is_selected(name_table[c]);
304 }
305
306 for(i=0; i < elements()->length(); i++) {
307 elements()->at(i)->set_index(i+1);
308 }
309
310 for (int pass=1; pass<=2; pass++) {
311 if (pass == 2) {
312 print_title(st, csv_format, selected, width_table, name_table);
313 }
314 for(i=0; i < elements()->length(); i++) {
315 KlassInfoEntry* e = (KlassInfoEntry*)elements()->at(i);
316 const Klass* k = e->klass();
317
318 memset(&sz, 0, sizeof(sz));
319 sz._inst_count = e->count();
320 sz._inst_bytes = HeapWordSize * e->words();
321 k->collect_statistics(&sz);
322 sz._total_bytes = sz._ro_bytes + sz._rw_bytes;
323
324 if (pass == 1) {
325 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
326 colsum_table[c] += col_table[c];
327 }
328 } else {
329 int super_index = -1;
330 if (k->oop_is_instance()) {
331 Klass* super = ((InstanceKlass*)k)->java_super();
332 if (super) {
333 KlassInfoEntry* super_e = _cit->lookup(super);
334 if (super_e) {
335 super_index = super_e->index();
336 }
337 }
338 }
339
340 if (csv_format) {
341 st->print("%d,%d", e->index(), super_index);
342 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
343 if (selected[c]) {st->print("," JULONG_FORMAT, col_table[c]);}
344 }
345 st->print(",%s",e->name());
346 } else {
347 st->print("%5d %5d", e->index(), super_index);
348 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
349 if (selected[c]) {print_julong(st, width_table[c], col_table[c]);}
350 }
351 st->print(" %s", e->name());
352 }
353 if (is_selected("ClassLoader")) {
354 ClassLoaderData* loader_data = k->class_loader_data();
355 st->print(",");
356 loader_data->print_value_on(st);
357 }
358 st->cr();
359 }
360 }
361
362 if (pass == 1) {
363 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
364 width_table[c] = col_width(colsum_table[c], name_table[c]);
365 }
366 }
367 }
368
369 sz_sum._inst_size = 0;
370
371 if (csv_format) {
372 st->print(",");
373 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
374 if (selected[c]) {st->print("," JULONG_FORMAT, colsum_table[c]);}
375 }
376 } else {
377 st->print(" ");
378 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
379 if (selected[c]) {print_julong(st, width_table[c], colsum_table[c]);}
380 }
381 st->print(" Total");
382 if (sz_sum._total_bytes > 0) {
383 st->cr();
384 st->print(" ");
385 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
386 if (selected[c]) {
387 switch (c) {
388 case KlassSizeStats::_index_inst_size:
389 case KlassSizeStats::_index_inst_count:
390 case KlassSizeStats::_index_method_count:
391 st->print(str_fmt(width_table[c]), "-");
392 break;
393 default:
394 {
395 double perc = (double)(100) * (double)(colsum_table[c]) / (double)sz_sum._total_bytes;
396 st->print(perc_fmt(width_table[c]), perc);
397 }
398 }
399 }
400 }
401 }
402 }
403 st->cr();
404
405 if (!csv_format) {
406 print_title(st, csv_format, selected, width_table, name_table);
407 }
408 }
409
410 julong KlassInfoHisto::annotations_bytes(Array<AnnotationArray*>* p) const {
411 julong bytes = 0;
412 if (p != NULL) {
413 for (int i = 0; i < p->length(); i++) {
414 bytes += count_bytes_array(p->at(i));
415 }
416 bytes += count_bytes_array(p);
417 }
418 return bytes;
419 }
420
421 void KlassInfoHisto::print_histo_on(outputStream* st, bool print_stats,
422 bool csv_format, const char *columns) {
423 if (print_stats) {
424 print_class_stats(st, csv_format, columns);
425 } else {
426 st->print_cr("%s",title());
427 print_elements(st);
428 }
202 } 429 }
203 430
204 class HistoClosure : public KlassInfoClosure { 431 class HistoClosure : public KlassInfoClosure {
205 private: 432 private:
206 KlassInfoHisto* _cih; 433 KlassInfoHisto* _cih;
234 // Get some random number for ref (the hash key) 461 // Get some random number for ref (the hash key)
235 HeapWord* ref = (HeapWord*) Universe::boolArrayKlassObj(); 462 HeapWord* ref = (HeapWord*) Universe::boolArrayKlassObj();
236 CollectedHeap* heap = Universe::heap(); 463 CollectedHeap* heap = Universe::heap();
237 bool is_shared_heap = false; 464 bool is_shared_heap = false;
238 465
466 if (_print_help) {
467 for (int c=0; c<KlassSizeStats::_num_columns; c++) {
468 st->print("%s:\n\t", name_table[c]);
469 const int max_col = 60;
470 int col = 0;
471 for (const char *p = help_table[c]; *p; p++,col++) {
472 if (col >= max_col && *p == ' ') {
473 st->print("\n\t");
474 col = 0;
475 } else {
476 st->print("%c", *p);
477 }
478 }
479 st->print_cr(".\n");
480 }
481 return;
482 }
483
239 // Collect klass instance info 484 // Collect klass instance info
240 KlassInfoTable cit(KlassInfoTable::cit_size, ref); 485 KlassInfoTable cit(KlassInfoTable::cit_size, ref, _print_class_stats);
241 if (!cit.allocation_failed()) { 486 if (!cit.allocation_failed()) {
242 // Iterate over objects in the heap 487 // Iterate over objects in the heap
243 RecordInstanceClosure ric(&cit); 488 RecordInstanceClosure ric(&cit);
244 Universe::heap()->object_iterate(&ric); 489 Universe::heap()->object_iterate(&ric);
245 490
250 st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT 495 st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT
251 " total instances in data below", 496 " total instances in data below",
252 missed_count); 497 missed_count);
253 } 498 }
254 // Sort and print klass instance info 499 // Sort and print klass instance info
255 KlassInfoHisto histo("\n" 500 const char *title = "\n"
256 " num #instances #bytes class name\n" 501 " num #instances #bytes class name\n"
257 "----------------------------------------------", 502 "----------------------------------------------";
258 KlassInfoHisto::histo_initial_size); 503 KlassInfoHisto histo(&cit, title, KlassInfoHisto::histo_initial_size);
259 HistoClosure hc(&histo); 504 HistoClosure hc(&histo);
260 cit.iterate(&hc); 505 cit.iterate(&hc);
261 histo.sort(); 506 histo.sort();
262 histo.print_on(st); 507 histo.print_histo_on(st, _print_class_stats, _csv_format, _columns);
263 } else { 508 } else {
264 st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); 509 st->print_cr("WARNING: Ran out of C-heap; histogram not generated");
265 } 510 }
266 st->flush(); 511 st->flush();
267 512