# HG changeset patch # User iklam # Date 1368934861 25200 # Node ID a5d6f0c3585ffc0b15070cfa85f2003d924191ef # Parent 386b77bf64276ee1402cbda4e5b2e29572380d6e 8014262: PrintStringTableStatistics should include more footprint info Summary: Added info for the string/symbol objects and the hash entries Reviewed-by: coleenp, rbackman diff -r 386b77bf6427 -r a5d6f0c3585f src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Fri May 17 17:52:07 2013 -0700 +++ b/src/share/vm/classfile/symbolTable.cpp Sat May 18 20:41:01 2013 -0700 @@ -35,7 +35,6 @@ #include "oops/oop.inline2.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/hashtable.inline.hpp" -#include "utilities/numberSeq.hpp" // -------------------------------------------------------------------------- @@ -451,21 +450,7 @@ } void SymbolTable::dump(outputStream* st) { - NumberSeq summary; - for (int i = 0; i < the_table()->table_size(); ++i) { - int count = 0; - for (HashtableEntry* e = the_table()->bucket(i); - e != NULL; e = e->next()) { - count++; - } - summary.add((double)count); - } - st->print_cr("SymbolTable statistics:"); - st->print_cr("Number of buckets : %7d", summary.num()); - st->print_cr("Average bucket size : %7.0f", summary.avg()); - st->print_cr("Variance of bucket size : %7.0f", summary.variance()); - st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); - st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); + the_table()->dump_table(st, "SymbolTable"); } @@ -814,21 +799,7 @@ } void StringTable::dump(outputStream* st) { - NumberSeq summary; - for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry* p = the_table()->bucket(i); - int count = 0; - for ( ; p != NULL; p = p->next()) { - count++; - } - summary.add((double)count); - } - st->print_cr("StringTable statistics:"); - st->print_cr("Number of buckets : %7d", summary.num()); - st->print_cr("Average bucket size : %7.0f", summary.avg()); - st->print_cr("Variance of bucket size : %7.0f", summary.variance()); - st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); - st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); + the_table()->dump_table(st, "StringTable"); } diff -r 386b77bf6427 -r a5d6f0c3585f src/share/vm/utilities/hashtable.cpp --- a/src/share/vm/utilities/hashtable.cpp Fri May 17 17:52:07 2013 -0700 +++ b/src/share/vm/utilities/hashtable.cpp Sat May 18 20:41:01 2013 -0700 @@ -33,6 +33,7 @@ #include "utilities/dtrace.hpp" #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" +#include "utilities/numberSeq.hpp" // This is a generic hashtable, designed to be used for the symbol @@ -237,6 +238,57 @@ } } +template int Hashtable::literal_size(Symbol *symbol) { + return symbol->size() * HeapWordSize; +} + +template int Hashtable::literal_size(oop oop) { + // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, + // and the String.value array is shared by several Strings. However, starting from JDK8, + // the String.value array is not shared anymore. + assert(oop != NULL && oop->klass() == SystemDictionary::String_klass(), "only strings are supported"); + return (oop->size() + java_lang_String::value(oop)->size()) * HeapWordSize; +} + +// Dump footprint and bucket length statistics +// +// Note: if you create a new subclass of Hashtable, you will need to +// add a new function Hashtable::literal_size(MyNewType lit) + +template void Hashtable::dump_table(outputStream* st, const char *table_name) { + NumberSeq summary; + int literal_bytes = 0; + for (int i = 0; i < this->table_size(); ++i) { + int count = 0; + for (HashtableEntry* e = bucket(i); + e != NULL; e = e->next()) { + count++; + literal_bytes += literal_size(e->literal()); + } + summary.add((double)count); + } + double num_buckets = summary.num(); + double num_entries = summary.sum(); + + int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); + int entry_bytes = (int)num_entries * sizeof(HashtableEntry); + int total_bytes = literal_bytes + bucket_bytes + entry_bytes; + + double bucket_avg = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets); + double entry_avg = (num_entries <= 0) ? 0 : (entry_bytes / num_entries); + double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries); + + st->print_cr("%s statistics:", table_name); + st->print_cr("Number of buckets : %9d = %9d bytes, avg %7.3f", (int)num_buckets, bucket_bytes, bucket_avg); + st->print_cr("Number of entries : %9d = %9d bytes, avg %7.3f", (int)num_entries, entry_bytes, entry_avg); + st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg); + st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes); + st->print_cr("Average bucket size : %9.3f", summary.avg()); + st->print_cr("Variance of bucket size : %9.3f", summary.variance()); + st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); + st->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); +} + // Dump the hash table buckets. diff -r 386b77bf6427 -r a5d6f0c3585f src/share/vm/utilities/hashtable.hpp --- a/src/share/vm/utilities/hashtable.hpp Fri May 17 17:52:07 2013 -0700 +++ b/src/share/vm/utilities/hashtable.hpp Sat May 18 20:41:01 2013 -0700 @@ -282,6 +282,19 @@ static bool use_alternate_hashcode() { return _seed != 0; } static jint seed() { return _seed; } + static int literal_size(Symbol *symbol); + static int literal_size(oop oop); + + // The following two are currently not used, but are needed anyway because some + // C++ compilers (MacOS and Solaris) force the instantiation of + // Hashtable::dump_table() even though we never call this function + // in the VM code. + static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} + static int literal_size(Klass *k) {Unimplemented(); return 0;} + +public: + void dump_table(outputStream* st, const char *table_name); + private: static jint _seed; };