1 /* |
1 /* |
2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1997, 2019, 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. |
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 const size_t 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 const size_t REHASH_LEN = 100; |
51 const size_t REHASH_LEN = 100; |
52 // We only get a chance to check whether we need |
|
53 // to clean infrequently (on class unloading), |
|
54 // so if we have even one dead entry then mark table for cleaning |
|
55 const double CLEAN_DEAD_HIGH_WATER_MARK = 0.0; |
|
56 |
52 |
57 const size_t ON_STACK_BUFFER_LENGTH = 128; |
53 const size_t ON_STACK_BUFFER_LENGTH = 128; |
58 |
54 |
59 // -------------------------------------------------------------------------- |
55 // -------------------------------------------------------------------------- |
60 |
56 |
140 } |
136 } |
141 |
137 |
142 SymbolTable::SymbolTable() : |
138 SymbolTable::SymbolTable() : |
143 _symbols_removed(0), _symbols_counted(0), _local_table(NULL), |
139 _symbols_removed(0), _symbols_counted(0), _local_table(NULL), |
144 _current_size(0), _has_work(0), _needs_rehashing(false), |
140 _current_size(0), _has_work(0), _needs_rehashing(false), |
145 _items_count(0), _uncleaned_items_count(0) { |
141 _items_count(0), _has_items_to_clean(false) { |
146 |
142 |
147 size_t start_size_log_2 = ceil_log2(SymbolTableSize); |
143 size_t start_size_log_2 = ceil_log2(SymbolTableSize); |
148 _current_size = ((size_t)1) << start_size_log_2; |
144 _current_size = ((size_t)1) << start_size_log_2; |
149 log_trace(symboltable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", |
145 log_trace(symboltable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", |
150 _current_size, start_size_log_2); |
146 _current_size, start_size_log_2); |
169 if (rehash) { |
165 if (rehash) { |
170 _needs_rehashing = true; |
166 _needs_rehashing = true; |
171 } |
167 } |
172 } |
168 } |
173 |
169 |
|
170 void SymbolTable::reset_has_items_to_clean() { Atomic::store(false, &_has_items_to_clean); } |
|
171 void SymbolTable::mark_has_items_to_clean() { Atomic::store(true, &_has_items_to_clean); } |
|
172 bool SymbolTable::has_items_to_clean() const { return Atomic::load(&_has_items_to_clean); } |
|
173 |
174 void SymbolTable::item_added() { |
174 void SymbolTable::item_added() { |
175 Atomic::inc(&(SymbolTable::the_table()->_items_count)); |
175 Atomic::inc(&(SymbolTable::the_table()->_items_count)); |
176 } |
|
177 |
|
178 void SymbolTable::set_item_clean_count(size_t ncl) { |
|
179 Atomic::store(ncl, &(SymbolTable::the_table()->_uncleaned_items_count)); |
|
180 log_trace(symboltable)("Set uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count); |
|
181 } |
|
182 |
|
183 // Mark one item as needing to be cleaned, but only if no other items are marked yet |
|
184 void SymbolTable::mark_item_clean_count() { |
|
185 if (Atomic::cmpxchg((size_t)1, &(SymbolTable::the_table()->_uncleaned_items_count), (size_t)0) == 0) { |
|
186 log_trace(symboltable)("Marked uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count); |
|
187 } |
|
188 } |
176 } |
189 |
177 |
190 void SymbolTable::item_removed() { |
178 void SymbolTable::item_removed() { |
191 Atomic::inc(&(SymbolTable::the_table()->_symbols_removed)); |
179 Atomic::inc(&(SymbolTable::the_table()->_symbols_removed)); |
192 Atomic::dec(&(SymbolTable::the_table()->_items_count)); |
180 Atomic::dec(&(SymbolTable::the_table()->_items_count)); |
194 |
182 |
195 double SymbolTable::get_load_factor() const { |
183 double SymbolTable::get_load_factor() const { |
196 return (double)_items_count/_current_size; |
184 return (double)_items_count/_current_size; |
197 } |
185 } |
198 |
186 |
199 double SymbolTable::get_dead_factor() const { |
|
200 return (double)_uncleaned_items_count/_current_size; |
|
201 } |
|
202 |
|
203 size_t SymbolTable::table_size() { |
187 size_t SymbolTable::table_size() { |
204 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); |
188 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); |
205 } |
189 } |
206 |
190 |
207 void SymbolTable::trigger_concurrent_work() { |
191 void SymbolTable::trigger_cleanup() { |
208 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); |
192 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); |
209 SymbolTable::the_table()->_has_work = true; |
193 SymbolTable::the_table()->_has_work = true; |
210 Service_lock->notify_all(); |
194 Service_lock->notify_all(); |
211 } |
195 } |
212 |
196 |
488 } while(true); |
472 } while(true); |
489 |
473 |
490 update_needs_rehash(rehash_warning); |
474 update_needs_rehash(rehash_warning); |
491 |
475 |
492 if (clean_hint) { |
476 if (clean_hint) { |
493 // we just found out that there is a dead item, |
477 mark_has_items_to_clean(); |
494 // which we were unable to clean right now, |
|
495 // but we have no way of telling whether it's |
|
496 // been previously counted or not, so mark |
|
497 // it only if no other items were found yet |
|
498 mark_item_clean_count(); |
|
499 check_concurrent_work(); |
478 check_concurrent_work(); |
500 } |
479 } |
501 |
480 |
502 assert((sym == NULL) || sym->refcount() != 0, "found dead symbol"); |
481 assert((sym == NULL) || sym->refcount() != 0, "found dead symbol"); |
503 return sym; |
482 return sym; |
709 |
688 |
710 void SymbolTable::check_concurrent_work() { |
689 void SymbolTable::check_concurrent_work() { |
711 if (_has_work) { |
690 if (_has_work) { |
712 return; |
691 return; |
713 } |
692 } |
714 double load_factor = SymbolTable::get_load_factor(); |
693 // We should clean/resize if we have |
715 double dead_factor = SymbolTable::get_dead_factor(); |
|
716 // We should clean/resize if we have more dead than alive, |
|
717 // more items than preferred load factor or |
694 // more items than preferred load factor or |
718 // more dead items than water mark. |
695 // more dead items than water mark. |
719 if ((dead_factor > load_factor) || |
696 if (has_items_to_clean() || (get_load_factor() > PREF_AVG_LIST_LEN)) { |
720 (load_factor > PREF_AVG_LIST_LEN) || |
697 log_debug(symboltable)("Concurrent work triggered, load factor: %f, items to clean: %s", |
721 (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) { |
698 get_load_factor(), has_items_to_clean() ? "true" : "false"); |
722 log_debug(symboltable)("Concurrent work triggered, live factor:%f dead factor:%f", |
699 trigger_cleanup(); |
723 load_factor, dead_factor); |
|
724 trigger_concurrent_work(); |
|
725 } |
700 } |
726 } |
701 } |
727 |
702 |
728 void SymbolTable::concurrent_work(JavaThread* jt) { |
703 void SymbolTable::concurrent_work(JavaThread* jt) { |
729 double load_factor = get_load_factor(); |
704 double load_factor = get_load_factor(); |
733 grow(jt); |
708 grow(jt); |
734 } else { |
709 } else { |
735 clean_dead_entries(jt); |
710 clean_dead_entries(jt); |
736 } |
711 } |
737 _has_work = false; |
712 _has_work = false; |
738 } |
|
739 |
|
740 class CountDead : StackObj { |
|
741 size_t _count; |
|
742 public: |
|
743 CountDead() : _count(0) {} |
|
744 bool operator()(Symbol** value) { |
|
745 assert(value != NULL, "expected valid value"); |
|
746 assert(*value != NULL, "value should point to a symbol"); |
|
747 Symbol* sym = *value; |
|
748 if (sym->refcount() == 0) { |
|
749 _count++; |
|
750 } |
|
751 return true; |
|
752 }; |
|
753 size_t get_dead_count() const { |
|
754 return _count; |
|
755 } |
|
756 }; |
|
757 |
|
758 void SymbolTable::do_check_concurrent_work() { |
|
759 CountDead counter; |
|
760 if (!SymbolTable::the_table()->_local_table->try_scan(Thread::current(), counter)) { |
|
761 log_info(symboltable)("count dead unavailable at this moment"); |
|
762 } else { |
|
763 SymbolTable::the_table()->set_item_clean_count(counter.get_dead_count()); |
|
764 SymbolTable::the_table()->check_concurrent_work(); |
|
765 } |
|
766 } |
713 } |
767 |
714 |
768 void SymbolTable::do_concurrent_work(JavaThread* jt) { |
715 void SymbolTable::do_concurrent_work(JavaThread* jt) { |
769 SymbolTable::the_table()->concurrent_work(jt); |
716 SymbolTable::the_table()->concurrent_work(jt); |
770 } |
717 } |
798 |
745 |
799 // Grow instead of rehash. |
746 // Grow instead of rehash. |
800 if (get_load_factor() > PREF_AVG_LIST_LEN && |
747 if (get_load_factor() > PREF_AVG_LIST_LEN && |
801 !_local_table->is_max_size_reached()) { |
748 !_local_table->is_max_size_reached()) { |
802 log_debug(symboltable)("Choosing growing over rehashing."); |
749 log_debug(symboltable)("Choosing growing over rehashing."); |
803 trigger_concurrent_work(); |
750 trigger_cleanup(); |
804 _needs_rehashing = false; |
751 _needs_rehashing = false; |
805 return; |
752 return; |
806 } |
753 } |
807 |
754 |
808 // Already rehashed. |
755 // Already rehashed. |
809 if (rehashed) { |
756 if (rehashed) { |
810 log_warning(symboltable)("Rehashing already done, still long lists."); |
757 log_warning(symboltable)("Rehashing already done, still long lists."); |
811 trigger_concurrent_work(); |
758 trigger_cleanup(); |
812 _needs_rehashing = false; |
759 _needs_rehashing = false; |
813 return; |
760 return; |
814 } |
761 } |
815 |
762 |
816 murmur_seed = AltHashing::compute_seed(); |
763 murmur_seed = AltHashing::compute_seed(); |