40 #include "utilities/concurrentHashTableTasks.inline.hpp" |
40 #include "utilities/concurrentHashTableTasks.inline.hpp" |
41 |
41 |
42 // We used to not resize at all, so let's be conservative |
42 // We used to not resize at all, so let's be conservative |
43 // and not set it too short before we decide to resize, |
43 // and not set it too short before we decide to resize, |
44 // to match previous startup behavior |
44 // to match previous startup behavior |
45 #define PREF_AVG_LIST_LEN 8 |
45 const double PREF_AVG_LIST_LEN = 8.0; |
46 // 2^17 (131,072) is max size, which is about 6.5 times as large |
46 // 2^17 (131,072) is max size, which is about 6.5 times as large |
47 // as the previous table size (used to be 20,011), |
47 // as the previous table size (used to be 20,011), |
48 // which never resized |
48 // which never resized |
49 #define END_SIZE 17 |
49 const size_t END_SIZE = 17; |
50 // If a chain gets to 100 something might be wrong |
50 // If a chain gets to 100 something might be wrong |
51 #define REHASH_LEN 100 |
51 const size_t REHASH_LEN = 100; |
52 // We only get a chance to check whether we need |
52 // We only get a chance to check whether we need |
53 // to clean infrequently (on class unloading), |
53 // to clean infrequently (on class unloading), |
54 // so if we have even one dead entry then mark table for cleaning |
54 // so if we have even one dead entry then mark table for cleaning |
55 #define CLEAN_DEAD_HIGH_WATER_MARK 0.0 |
55 const double CLEAN_DEAD_HIGH_WATER_MARK = 0.0; |
56 |
56 |
57 #define ON_STACK_BUFFER_LENGTH 128 |
57 const size_t ON_STACK_BUFFER_LENGTH = 128; |
58 |
58 |
59 // -------------------------------------------------------------------------- |
59 // -------------------------------------------------------------------------- |
60 |
60 |
61 inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) { |
61 inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) { |
62 if (value->equals(key, len)) { |
62 if (value->equals(key, len)) { |
169 void SymbolTable::set_item_clean_count(size_t ncl) { |
169 void SymbolTable::set_item_clean_count(size_t ncl) { |
170 Atomic::store(ncl, &(SymbolTable::the_table()->_uncleaned_items_count)); |
170 Atomic::store(ncl, &(SymbolTable::the_table()->_uncleaned_items_count)); |
171 log_trace(symboltable)("Set uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count); |
171 log_trace(symboltable)("Set uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count); |
172 } |
172 } |
173 |
173 |
|
174 // Mark one item as needing to be cleaned, but only if no other items are marked yet |
174 void SymbolTable::mark_item_clean_count() { |
175 void SymbolTable::mark_item_clean_count() { |
175 if (Atomic::cmpxchg((size_t)1, &(SymbolTable::the_table()->_uncleaned_items_count), (size_t)0) == 0) { // only mark if unset |
176 if (Atomic::cmpxchg((size_t)1, &(SymbolTable::the_table()->_uncleaned_items_count), (size_t)0) == 0) { |
176 log_trace(symboltable)("Marked uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count); |
177 log_trace(symboltable)("Marked uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count); |
177 } |
178 } |
178 } |
179 } |
179 |
180 |
180 void SymbolTable::item_removed() { |
181 void SymbolTable::item_removed() { |
181 Atomic::inc(&(SymbolTable::the_table()->_symbols_removed)); |
182 Atomic::inc(&(SymbolTable::the_table()->_symbols_removed)); |
182 Atomic::dec(&(SymbolTable::the_table()->_items_count)); |
183 Atomic::dec(&(SymbolTable::the_table()->_items_count)); |
183 } |
184 } |
184 |
185 |
185 double SymbolTable::get_load_factor() { |
186 double SymbolTable::get_load_factor() const { |
186 return (double)_items_count/_current_size; |
187 return (double)_items_count/_current_size; |
187 } |
188 } |
188 |
189 |
189 double SymbolTable::get_dead_factor() { |
190 double SymbolTable::get_dead_factor() const { |
190 return (double)_uncleaned_items_count/_current_size; |
191 return (double)_uncleaned_items_count/_current_size; |
191 } |
192 } |
192 |
193 |
193 size_t SymbolTable::table_size() { |
194 size_t SymbolTable::table_size() { |
194 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); |
195 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); |
384 void operator()(Symbol** value) { |
385 void operator()(Symbol** value) { |
385 assert(value != NULL, "expected valid value"); |
386 assert(value != NULL, "expected valid value"); |
386 assert(*value != NULL, "value should point to a symbol"); |
387 assert(*value != NULL, "value should point to a symbol"); |
387 _return = *value; |
388 _return = *value; |
388 } |
389 } |
389 Symbol* get_res_sym() { |
390 Symbol* get_res_sym() const { |
390 return _return; |
391 return _return; |
391 } |
392 } |
392 }; |
393 }; |
393 |
394 |
394 Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) { |
395 Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) { |
692 _current_size = table_size(); |
693 _current_size = table_size(); |
693 log_debug(symboltable)("Grown to size:" SIZE_FORMAT, _current_size); |
694 log_debug(symboltable)("Grown to size:" SIZE_FORMAT, _current_size); |
694 } |
695 } |
695 |
696 |
696 struct SymbolTableDoDelete : StackObj { |
697 struct SymbolTableDoDelete : StackObj { |
697 int _deleted; |
698 size_t _deleted; |
698 SymbolTableDoDelete() : _deleted(0) {} |
699 SymbolTableDoDelete() : _deleted(0) {} |
699 void operator()(Symbol** value) { |
700 void operator()(Symbol** value) { |
700 assert(value != NULL, "expected valid value"); |
701 assert(value != NULL, "expected valid value"); |
701 assert(*value != NULL, "value should point to a symbol"); |
702 assert(*value != NULL, "value should point to a symbol"); |
702 Symbol *sym = *value; |
703 Symbol *sym = *value; |
704 _deleted++; |
705 _deleted++; |
705 } |
706 } |
706 }; |
707 }; |
707 |
708 |
708 struct SymbolTableDeleteCheck : StackObj { |
709 struct SymbolTableDeleteCheck : StackObj { |
709 int _processed; |
710 size_t _processed; |
710 SymbolTableDeleteCheck() : _processed(0) {} |
711 SymbolTableDeleteCheck() : _processed(0) {} |
711 bool operator()(Symbol** value) { |
712 bool operator()(Symbol** value) { |
712 assert(value != NULL, "expected valid value"); |
713 assert(value != NULL, "expected valid value"); |
713 assert(*value != NULL, "value should point to a symbol"); |
714 assert(*value != NULL, "value should point to a symbol"); |
714 _processed++; |
715 _processed++; |
736 } |
737 } |
737 SymbolTable::the_table()->set_item_clean_count(0); |
738 SymbolTable::the_table()->set_item_clean_count(0); |
738 bdt.done(jt); |
739 bdt.done(jt); |
739 } |
740 } |
740 |
741 |
741 Atomic::add((size_t)stdc._processed, &_symbols_counted); |
742 Atomic::add(stdc._processed, &_symbols_counted); |
742 |
743 |
743 log_debug(symboltable)("Cleaned " INT32_FORMAT " of " INT32_FORMAT, |
744 log_debug(symboltable)("Cleaned " SIZE_FORMAT " of " SIZE_FORMAT, |
744 stdd._deleted, stdc._processed); |
745 stdd._deleted, stdc._processed); |
745 } |
746 } |
746 |
747 |
747 void SymbolTable::check_concurrent_work() { |
748 void SymbolTable::check_concurrent_work() { |
748 if (_has_work) { |
749 if (_has_work) { |
773 } |
774 } |
774 _has_work = false; |
775 _has_work = false; |
775 } |
776 } |
776 |
777 |
777 class CountDead : StackObj { |
778 class CountDead : StackObj { |
778 int _count; |
779 size_t _count; |
779 public: |
780 public: |
780 CountDead() : _count(0) {} |
781 CountDead() : _count(0) {} |
781 bool operator()(Symbol** value) { |
782 bool operator()(Symbol** value) { |
782 assert(value != NULL, "expected valid value"); |
783 assert(value != NULL, "expected valid value"); |
783 assert(*value != NULL, "value should point to a symbol"); |
784 assert(*value != NULL, "value should point to a symbol"); |