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.