31 #include "oops/oop.inline.hpp" |
31 #include "oops/oop.inline.hpp" |
32 #include "runtime/safepoint.hpp" |
32 #include "runtime/safepoint.hpp" |
33 #include "utilities/dtrace.hpp" |
33 #include "utilities/dtrace.hpp" |
34 #include "utilities/hashtable.hpp" |
34 #include "utilities/hashtable.hpp" |
35 #include "utilities/hashtable.inline.hpp" |
35 #include "utilities/hashtable.inline.hpp" |
|
36 #include "utilities/numberSeq.hpp" |
36 |
37 |
37 |
38 |
38 // This is a generic hashtable, designed to be used for the symbol |
39 // This is a generic hashtable, designed to be used for the symbol |
39 // and string tables. |
40 // and string tables. |
40 // |
41 // |
235 *bucket_addr(i) = high_list; |
236 *bucket_addr(i) = high_list; |
236 } |
237 } |
237 } |
238 } |
238 } |
239 } |
239 |
240 |
|
241 template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(Symbol *symbol) { |
|
242 return symbol->size() * HeapWordSize; |
|
243 } |
|
244 |
|
245 template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) { |
|
246 // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, |
|
247 // and the String.value array is shared by several Strings. However, starting from JDK8, |
|
248 // the String.value array is not shared anymore. |
|
249 assert(oop != NULL && oop->klass() == SystemDictionary::String_klass(), "only strings are supported"); |
|
250 return (oop->size() + java_lang_String::value(oop)->size()) * HeapWordSize; |
|
251 } |
|
252 |
|
253 // Dump footprint and bucket length statistics |
|
254 // |
|
255 // Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to |
|
256 // add a new function Hashtable<T, F>::literal_size(MyNewType lit) |
|
257 |
|
258 template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st, const char *table_name) { |
|
259 NumberSeq summary; |
|
260 int literal_bytes = 0; |
|
261 for (int i = 0; i < this->table_size(); ++i) { |
|
262 int count = 0; |
|
263 for (HashtableEntry<T, F>* e = bucket(i); |
|
264 e != NULL; e = e->next()) { |
|
265 count++; |
|
266 literal_bytes += literal_size(e->literal()); |
|
267 } |
|
268 summary.add((double)count); |
|
269 } |
|
270 double num_buckets = summary.num(); |
|
271 double num_entries = summary.sum(); |
|
272 |
|
273 int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); |
|
274 int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>); |
|
275 int total_bytes = literal_bytes + bucket_bytes + entry_bytes; |
|
276 |
|
277 double bucket_avg = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets); |
|
278 double entry_avg = (num_entries <= 0) ? 0 : (entry_bytes / num_entries); |
|
279 double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries); |
|
280 |
|
281 st->print_cr("%s statistics:", table_name); |
|
282 st->print_cr("Number of buckets : %9d = %9d bytes, avg %7.3f", (int)num_buckets, bucket_bytes, bucket_avg); |
|
283 st->print_cr("Number of entries : %9d = %9d bytes, avg %7.3f", (int)num_entries, entry_bytes, entry_avg); |
|
284 st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg); |
|
285 st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes); |
|
286 st->print_cr("Average bucket size : %9.3f", summary.avg()); |
|
287 st->print_cr("Variance of bucket size : %9.3f", summary.variance()); |
|
288 st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); |
|
289 st->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); |
|
290 } |
|
291 |
240 |
292 |
241 // Dump the hash table buckets. |
293 // Dump the hash table buckets. |
242 |
294 |
243 template <MEMFLAGS F> void BasicHashtable<F>::copy_buckets(char** top, char* end) { |
295 template <MEMFLAGS F> void BasicHashtable<F>::copy_buckets(char** top, char* end) { |
244 intptr_t len = _table_size * sizeof(HashtableBucket<F>); |
296 intptr_t len = _table_size * sizeof(HashtableBucket<F>); |