Sat, 18 May 2013 20:41:01 -0700
8014262: PrintStringTableStatistics should include more footprint info
Summary: Added info for the string/symbol objects and the hash entries
Reviewed-by: coleenp, rbackman
1.1 --- a/src/share/vm/classfile/symbolTable.cpp Fri May 17 17:52:07 2013 -0700 1.2 +++ b/src/share/vm/classfile/symbolTable.cpp Sat May 18 20:41:01 2013 -0700 1.3 @@ -35,7 +35,6 @@ 1.4 #include "oops/oop.inline2.hpp" 1.5 #include "runtime/mutexLocker.hpp" 1.6 #include "utilities/hashtable.inline.hpp" 1.7 -#include "utilities/numberSeq.hpp" 1.8 1.9 // -------------------------------------------------------------------------- 1.10 1.11 @@ -451,21 +450,7 @@ 1.12 } 1.13 1.14 void SymbolTable::dump(outputStream* st) { 1.15 - NumberSeq summary; 1.16 - for (int i = 0; i < the_table()->table_size(); ++i) { 1.17 - int count = 0; 1.18 - for (HashtableEntry<Symbol*, mtSymbol>* e = the_table()->bucket(i); 1.19 - e != NULL; e = e->next()) { 1.20 - count++; 1.21 - } 1.22 - summary.add((double)count); 1.23 - } 1.24 - st->print_cr("SymbolTable statistics:"); 1.25 - st->print_cr("Number of buckets : %7d", summary.num()); 1.26 - st->print_cr("Average bucket size : %7.0f", summary.avg()); 1.27 - st->print_cr("Variance of bucket size : %7.0f", summary.variance()); 1.28 - st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); 1.29 - st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); 1.30 + the_table()->dump_table(st, "SymbolTable"); 1.31 } 1.32 1.33 1.34 @@ -814,21 +799,7 @@ 1.35 } 1.36 1.37 void StringTable::dump(outputStream* st) { 1.38 - NumberSeq summary; 1.39 - for (int i = 0; i < the_table()->table_size(); ++i) { 1.40 - HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i); 1.41 - int count = 0; 1.42 - for ( ; p != NULL; p = p->next()) { 1.43 - count++; 1.44 - } 1.45 - summary.add((double)count); 1.46 - } 1.47 - st->print_cr("StringTable statistics:"); 1.48 - st->print_cr("Number of buckets : %7d", summary.num()); 1.49 - st->print_cr("Average bucket size : %7.0f", summary.avg()); 1.50 - st->print_cr("Variance of bucket size : %7.0f", summary.variance()); 1.51 - st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); 1.52 - st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); 1.53 + the_table()->dump_table(st, "StringTable"); 1.54 } 1.55 1.56
2.1 --- a/src/share/vm/utilities/hashtable.cpp Fri May 17 17:52:07 2013 -0700 2.2 +++ b/src/share/vm/utilities/hashtable.cpp Sat May 18 20:41:01 2013 -0700 2.3 @@ -33,6 +33,7 @@ 2.4 #include "utilities/dtrace.hpp" 2.5 #include "utilities/hashtable.hpp" 2.6 #include "utilities/hashtable.inline.hpp" 2.7 +#include "utilities/numberSeq.hpp" 2.8 2.9 2.10 // This is a generic hashtable, designed to be used for the symbol 2.11 @@ -237,6 +238,57 @@ 2.12 } 2.13 } 2.14 2.15 +template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(Symbol *symbol) { 2.16 + return symbol->size() * HeapWordSize; 2.17 +} 2.18 + 2.19 +template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) { 2.20 + // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, 2.21 + // and the String.value array is shared by several Strings. However, starting from JDK8, 2.22 + // the String.value array is not shared anymore. 2.23 + assert(oop != NULL && oop->klass() == SystemDictionary::String_klass(), "only strings are supported"); 2.24 + return (oop->size() + java_lang_String::value(oop)->size()) * HeapWordSize; 2.25 +} 2.26 + 2.27 +// Dump footprint and bucket length statistics 2.28 +// 2.29 +// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to 2.30 +// add a new function Hashtable<T, F>::literal_size(MyNewType lit) 2.31 + 2.32 +template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st, const char *table_name) { 2.33 + NumberSeq summary; 2.34 + int literal_bytes = 0; 2.35 + for (int i = 0; i < this->table_size(); ++i) { 2.36 + int count = 0; 2.37 + for (HashtableEntry<T, F>* e = bucket(i); 2.38 + e != NULL; e = e->next()) { 2.39 + count++; 2.40 + literal_bytes += literal_size(e->literal()); 2.41 + } 2.42 + summary.add((double)count); 2.43 + } 2.44 + double num_buckets = summary.num(); 2.45 + double num_entries = summary.sum(); 2.46 + 2.47 + int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); 2.48 + int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>); 2.49 + int total_bytes = literal_bytes + bucket_bytes + entry_bytes; 2.50 + 2.51 + double bucket_avg = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets); 2.52 + double entry_avg = (num_entries <= 0) ? 0 : (entry_bytes / num_entries); 2.53 + double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries); 2.54 + 2.55 + st->print_cr("%s statistics:", table_name); 2.56 + st->print_cr("Number of buckets : %9d = %9d bytes, avg %7.3f", (int)num_buckets, bucket_bytes, bucket_avg); 2.57 + st->print_cr("Number of entries : %9d = %9d bytes, avg %7.3f", (int)num_entries, entry_bytes, entry_avg); 2.58 + st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg); 2.59 + st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes); 2.60 + st->print_cr("Average bucket size : %9.3f", summary.avg()); 2.61 + st->print_cr("Variance of bucket size : %9.3f", summary.variance()); 2.62 + st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); 2.63 + st->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); 2.64 +} 2.65 + 2.66 2.67 // Dump the hash table buckets. 2.68
3.1 --- a/src/share/vm/utilities/hashtable.hpp Fri May 17 17:52:07 2013 -0700 3.2 +++ b/src/share/vm/utilities/hashtable.hpp Sat May 18 20:41:01 2013 -0700 3.3 @@ -282,6 +282,19 @@ 3.4 static bool use_alternate_hashcode() { return _seed != 0; } 3.5 static jint seed() { return _seed; } 3.6 3.7 + static int literal_size(Symbol *symbol); 3.8 + static int literal_size(oop oop); 3.9 + 3.10 + // The following two are currently not used, but are needed anyway because some 3.11 + // C++ compilers (MacOS and Solaris) force the instantiation of 3.12 + // Hashtable<ConstantPool*, mtClass>::dump_table() even though we never call this function 3.13 + // in the VM code. 3.14 + static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} 3.15 + static int literal_size(Klass *k) {Unimplemented(); return 0;} 3.16 + 3.17 +public: 3.18 + void dump_table(outputStream* st, const char *table_name); 3.19 + 3.20 private: 3.21 static jint _seed; 3.22 };