Mercurial > hg > graal-compiler
comparison src/share/vm/classfile/symbolTable.cpp @ 14303:893ce66f7473
8027476: Improve performance of Stringtable unlink
8027455: Improve symbol table scan times during gc pauses
Summary: Parallelize string table and symbol table scan during remark and full GC. Some additional statistics output if the experimental flag G1TraceStringSymbolTableScrubbing is set.
Reviewed-by: mgerdin, coleenp, brutisso
author | tschatzl |
---|---|
date | Mon, 20 Jan 2014 11:47:07 +0100 |
parents | a5ac0873476c |
children | 4ca6dc0799b6 595c0f60d50d |
comparison
equal
deleted
inserted
replaced
14265:3e2b76368121 | 14303:893ce66f7473 |
---|---|
36 #include "runtime/mutexLocker.hpp" | 36 #include "runtime/mutexLocker.hpp" |
37 #include "utilities/hashtable.inline.hpp" | 37 #include "utilities/hashtable.inline.hpp" |
38 | 38 |
39 // -------------------------------------------------------------------------- | 39 // -------------------------------------------------------------------------- |
40 | 40 |
41 // the number of buckets a thread claims | |
42 const int ClaimChunkSize = 32; | |
43 | |
41 SymbolTable* SymbolTable::_the_table = NULL; | 44 SymbolTable* SymbolTable::_the_table = NULL; |
42 // Static arena for symbols that are not deallocated | 45 // Static arena for symbols that are not deallocated |
43 Arena* SymbolTable::_arena = NULL; | 46 Arena* SymbolTable::_arena = NULL; |
44 bool SymbolTable::_needs_rehashing = false; | 47 bool SymbolTable::_needs_rehashing = false; |
45 | 48 |
81 cl->do_symbol(p->literal_addr()); | 84 cl->do_symbol(p->literal_addr()); |
82 } | 85 } |
83 } | 86 } |
84 } | 87 } |
85 | 88 |
86 int SymbolTable::symbols_removed = 0; | 89 int SymbolTable::_symbols_removed = 0; |
87 int SymbolTable::symbols_counted = 0; | 90 int SymbolTable::_symbols_counted = 0; |
88 | 91 volatile int SymbolTable::_parallel_claimed_idx = 0; |
89 // Remove unreferenced symbols from the symbol table | 92 |
90 // This is done late during GC. | 93 void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total) { |
91 void SymbolTable::unlink() { | 94 for (int i = start_idx; i < end_idx; ++i) { |
92 int removed = 0; | |
93 int total = 0; | |
94 size_t memory_total = 0; | |
95 for (int i = 0; i < the_table()->table_size(); ++i) { | |
96 HashtableEntry<Symbol*, mtSymbol>** p = the_table()->bucket_addr(i); | 95 HashtableEntry<Symbol*, mtSymbol>** p = the_table()->bucket_addr(i); |
97 HashtableEntry<Symbol*, mtSymbol>* entry = the_table()->bucket(i); | 96 HashtableEntry<Symbol*, mtSymbol>* entry = the_table()->bucket(i); |
98 while (entry != NULL) { | 97 while (entry != NULL) { |
99 // Shared entries are normally at the end of the bucket and if we run into | 98 // Shared entries are normally at the end of the bucket and if we run into |
100 // a shared entry, then there is nothing more to remove. However, if we | 99 // a shared entry, then there is nothing more to remove. However, if we |
102 // end of the bucket. | 101 // end of the bucket. |
103 if (entry->is_shared() && !use_alternate_hashcode()) { | 102 if (entry->is_shared() && !use_alternate_hashcode()) { |
104 break; | 103 break; |
105 } | 104 } |
106 Symbol* s = entry->literal(); | 105 Symbol* s = entry->literal(); |
107 memory_total += s->size(); | 106 (*memory_total) += s->size(); |
108 total++; | 107 (*processed)++; |
109 assert(s != NULL, "just checking"); | 108 assert(s != NULL, "just checking"); |
110 // If reference count is zero, remove. | 109 // If reference count is zero, remove. |
111 if (s->refcount() == 0) { | 110 if (s->refcount() == 0) { |
112 assert(!entry->is_shared(), "shared entries should be kept live"); | 111 assert(!entry->is_shared(), "shared entries should be kept live"); |
113 delete s; | 112 delete s; |
114 removed++; | 113 (*removed)++; |
115 *p = entry->next(); | 114 *p = entry->next(); |
116 the_table()->free_entry(entry); | 115 the_table()->free_entry(entry); |
117 } else { | 116 } else { |
118 p = entry->next_addr(); | 117 p = entry->next_addr(); |
119 } | 118 } |
120 // get next entry | 119 // get next entry |
121 entry = (HashtableEntry<Symbol*, mtSymbol>*)HashtableEntry<Symbol*, mtSymbol>::make_ptr(*p); | 120 entry = (HashtableEntry<Symbol*, mtSymbol>*)HashtableEntry<Symbol*, mtSymbol>::make_ptr(*p); |
122 } | 121 } |
123 } | 122 } |
124 symbols_removed += removed; | 123 } |
125 symbols_counted += total; | 124 |
125 // Remove unreferenced symbols from the symbol table | |
126 // This is done late during GC. | |
127 void SymbolTable::unlink(int* processed, int* removed) { | |
128 size_t memory_total = 0; | |
129 buckets_unlink(0, the_table()->table_size(), processed, removed, &memory_total); | |
130 _symbols_removed += *removed; | |
131 _symbols_counted += *processed; | |
126 // Exclude printing for normal PrintGCDetails because people parse | 132 // Exclude printing for normal PrintGCDetails because people parse |
127 // this output. | 133 // this output. |
128 if (PrintGCDetails && Verbose && WizardMode) { | 134 if (PrintGCDetails && Verbose && WizardMode) { |
129 gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", total, | 135 gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", *processed, |
136 (memory_total*HeapWordSize)/1024); | |
137 } | |
138 } | |
139 | |
140 void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { | |
141 const int limit = the_table()->table_size(); | |
142 | |
143 size_t memory_total = 0; | |
144 | |
145 for (;;) { | |
146 // Grab next set of buckets to scan | |
147 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; | |
148 if (start_idx >= limit) { | |
149 // End of table | |
150 break; | |
151 } | |
152 | |
153 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); | |
154 buckets_unlink(start_idx, end_idx, processed, removed, &memory_total); | |
155 } | |
156 Atomic::add(*processed, &_symbols_counted); | |
157 Atomic::add(*removed, &_symbols_removed); | |
158 // Exclude printing for normal PrintGCDetails because people parse | |
159 // this output. | |
160 if (PrintGCDetails && Verbose && WizardMode) { | |
161 gclog_or_tty->print(" [Symbols: scanned=%d removed=%d size=" SIZE_FORMAT "K] ", *processed, *removed, | |
130 (memory_total*HeapWordSize)/1024); | 162 (memory_total*HeapWordSize)/1024); |
131 } | 163 } |
132 } | 164 } |
133 | 165 |
134 // Create a new table and using alternate hash code, populate the new table | 166 // Create a new table and using alternate hash code, populate the new table |
492 } | 524 } |
493 tty->print_cr("Symbol Table:"); | 525 tty->print_cr("Symbol Table:"); |
494 tty->print_cr("Total number of symbols %5d", count); | 526 tty->print_cr("Total number of symbols %5d", count); |
495 tty->print_cr("Total size in memory %5dK", | 527 tty->print_cr("Total size in memory %5dK", |
496 (memory_total*HeapWordSize)/1024); | 528 (memory_total*HeapWordSize)/1024); |
497 tty->print_cr("Total counted %5d", symbols_counted); | 529 tty->print_cr("Total counted %5d", _symbols_counted); |
498 tty->print_cr("Total removed %5d", symbols_removed); | 530 tty->print_cr("Total removed %5d", _symbols_removed); |
499 if (symbols_counted > 0) { | 531 if (_symbols_counted > 0) { |
500 tty->print_cr("Percent removed %3.2f", | 532 tty->print_cr("Percent removed %3.2f", |
501 ((float)symbols_removed/(float)symbols_counted)* 100); | 533 ((float)_symbols_removed/(float)_symbols_counted)* 100); |
502 } | 534 } |
503 tty->print_cr("Reference counts %5d", Symbol::_total_count); | 535 tty->print_cr("Reference counts %5d", Symbol::_total_count); |
504 tty->print_cr("Symbol arena size %5d used %5d", | 536 tty->print_cr("Symbol arena size %5d used %5d", |
505 arena()->size_in_bytes(), arena()->used()); | 537 arena()->size_in_bytes(), arena()->used()); |
506 tty->print_cr("Histogram of symbol length:"); | 538 tty->print_cr("Histogram of symbol length:"); |
737 Handle string; | 769 Handle string; |
738 oop result = intern(string, chars, length, CHECK_NULL); | 770 oop result = intern(string, chars, length, CHECK_NULL); |
739 return result; | 771 return result; |
740 } | 772 } |
741 | 773 |
742 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { | 774 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { |
775 buckets_unlink_or_oops_do(is_alive, f, 0, the_table()->table_size(), processed, removed); | |
776 } | |
777 | |
778 void StringTable::possibly_parallel_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { | |
743 // Readers of the table are unlocked, so we should only be removing | 779 // Readers of the table are unlocked, so we should only be removing |
744 // entries at a safepoint. | 780 // entries at a safepoint. |
745 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); | 781 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); |
746 for (int i = 0; i < the_table()->table_size(); ++i) { | 782 const int limit = the_table()->table_size(); |
783 | |
784 for (;;) { | |
785 // Grab next set of buckets to scan | |
786 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; | |
787 if (start_idx >= limit) { | |
788 // End of table | |
789 break; | |
790 } | |
791 | |
792 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); | |
793 buckets_unlink_or_oops_do(is_alive, f, start_idx, end_idx, processed, removed); | |
794 } | |
795 } | |
796 | |
797 void StringTable::buckets_oops_do(OopClosure* f, int start_idx, int end_idx) { | |
798 const int limit = the_table()->table_size(); | |
799 | |
800 assert(0 <= start_idx && start_idx <= limit, | |
801 err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); | |
802 assert(0 <= end_idx && end_idx <= limit, | |
803 err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); | |
804 assert(start_idx <= end_idx, | |
805 err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, | |
806 start_idx, end_idx)); | |
807 | |
808 for (int i = start_idx; i < end_idx; i += 1) { | |
809 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); | |
810 while (entry != NULL) { | |
811 assert(!entry->is_shared(), "CDS not used for the StringTable"); | |
812 | |
813 f->do_oop((oop*)entry->literal_addr()); | |
814 | |
815 entry = entry->next(); | |
816 } | |
817 } | |
818 } | |
819 | |
820 void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed) { | |
821 const int limit = the_table()->table_size(); | |
822 | |
823 assert(0 <= start_idx && start_idx <= limit, | |
824 err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); | |
825 assert(0 <= end_idx && end_idx <= limit, | |
826 err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); | |
827 assert(start_idx <= end_idx, | |
828 err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, | |
829 start_idx, end_idx)); | |
830 | |
831 for (int i = start_idx; i < end_idx; ++i) { | |
747 HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); | 832 HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); |
748 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); | 833 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); |
749 while (entry != NULL) { | 834 while (entry != NULL) { |
750 assert(!entry->is_shared(), "CDS not used for the StringTable"); | 835 assert(!entry->is_shared(), "CDS not used for the StringTable"); |
751 | 836 |
755 } | 840 } |
756 p = entry->next_addr(); | 841 p = entry->next_addr(); |
757 } else { | 842 } else { |
758 *p = entry->next(); | 843 *p = entry->next(); |
759 the_table()->free_entry(entry); | 844 the_table()->free_entry(entry); |
760 } | 845 (*removed)++; |
846 } | |
847 (*processed)++; | |
761 entry = *p; | 848 entry = *p; |
762 } | 849 } |
763 } | 850 } |
764 } | 851 } |
765 | 852 |
766 void StringTable::buckets_do(OopClosure* f, int start_idx, int end_idx) { | |
767 const int limit = the_table()->table_size(); | |
768 | |
769 assert(0 <= start_idx && start_idx <= limit, | |
770 err_msg("start_idx (" INT32_FORMAT ") oob?", start_idx)); | |
771 assert(0 <= end_idx && end_idx <= limit, | |
772 err_msg("end_idx (" INT32_FORMAT ") oob?", end_idx)); | |
773 assert(start_idx <= end_idx, | |
774 err_msg("Ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, | |
775 start_idx, end_idx)); | |
776 | |
777 for (int i = start_idx; i < end_idx; i += 1) { | |
778 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); | |
779 while (entry != NULL) { | |
780 assert(!entry->is_shared(), "CDS not used for the StringTable"); | |
781 | |
782 f->do_oop((oop*)entry->literal_addr()); | |
783 | |
784 entry = entry->next(); | |
785 } | |
786 } | |
787 } | |
788 | |
789 void StringTable::oops_do(OopClosure* f) { | 853 void StringTable::oops_do(OopClosure* f) { |
790 buckets_do(f, 0, the_table()->table_size()); | 854 buckets_oops_do(f, 0, the_table()->table_size()); |
791 } | 855 } |
792 | 856 |
793 void StringTable::possibly_parallel_oops_do(OopClosure* f) { | 857 void StringTable::possibly_parallel_oops_do(OopClosure* f) { |
794 const int ClaimChunkSize = 32; | |
795 const int limit = the_table()->table_size(); | 858 const int limit = the_table()->table_size(); |
796 | 859 |
797 for (;;) { | 860 for (;;) { |
798 // Grab next set of buckets to scan | 861 // Grab next set of buckets to scan |
799 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; | 862 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; |
801 // End of table | 864 // End of table |
802 break; | 865 break; |
803 } | 866 } |
804 | 867 |
805 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); | 868 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); |
806 buckets_do(f, start_idx, end_idx); | 869 buckets_oops_do(f, start_idx, end_idx); |
807 } | 870 } |
808 } | 871 } |
809 | 872 |
810 // This verification is part of Universe::verify() and needs to be quick. | 873 // This verification is part of Universe::verify() and needs to be quick. |
811 // See StringTable::verify_and_compare() below for exhaustive verification. | 874 // See StringTable::verify_and_compare() below for exhaustive verification. |