1.1 --- a/src/share/vm/classfile/symbolTable.cpp Tue Jan 07 13:31:33 2014 +0100 1.2 +++ b/src/share/vm/classfile/symbolTable.cpp Mon Jan 20 11:47:07 2014 +0100 1.3 @@ -38,6 +38,9 @@ 1.4 1.5 // -------------------------------------------------------------------------- 1.6 1.7 +// the number of buckets a thread claims 1.8 +const int ClaimChunkSize = 32; 1.9 + 1.10 SymbolTable* SymbolTable::_the_table = NULL; 1.11 // Static arena for symbols that are not deallocated 1.12 Arena* SymbolTable::_arena = NULL; 1.13 @@ -83,16 +86,12 @@ 1.14 } 1.15 } 1.16 1.17 -int SymbolTable::symbols_removed = 0; 1.18 -int SymbolTable::symbols_counted = 0; 1.19 +int SymbolTable::_symbols_removed = 0; 1.20 +int SymbolTable::_symbols_counted = 0; 1.21 +volatile int SymbolTable::_parallel_claimed_idx = 0; 1.22 1.23 -// Remove unreferenced symbols from the symbol table 1.24 -// This is done late during GC. 1.25 -void SymbolTable::unlink() { 1.26 - int removed = 0; 1.27 - int total = 0; 1.28 - size_t memory_total = 0; 1.29 - for (int i = 0; i < the_table()->table_size(); ++i) { 1.30 +void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total) { 1.31 + for (int i = start_idx; i < end_idx; ++i) { 1.32 HashtableEntry<Symbol*, mtSymbol>** p = the_table()->bucket_addr(i); 1.33 HashtableEntry<Symbol*, mtSymbol>* entry = the_table()->bucket(i); 1.34 while (entry != NULL) { 1.35 @@ -104,14 +103,14 @@ 1.36 break; 1.37 } 1.38 Symbol* s = entry->literal(); 1.39 - memory_total += s->size(); 1.40 - total++; 1.41 + (*memory_total) += s->size(); 1.42 + (*processed)++; 1.43 assert(s != NULL, "just checking"); 1.44 // If reference count is zero, remove. 1.45 if (s->refcount() == 0) { 1.46 assert(!entry->is_shared(), "shared entries should be kept live"); 1.47 delete s; 1.48 - removed++; 1.49 + (*removed)++; 1.50 *p = entry->next(); 1.51 the_table()->free_entry(entry); 1.52 } else { 1.53 @@ -121,12 +120,45 @@ 1.54 entry = (HashtableEntry<Symbol*, mtSymbol>*)HashtableEntry<Symbol*, mtSymbol>::make_ptr(*p); 1.55 } 1.56 } 1.57 - symbols_removed += removed; 1.58 - symbols_counted += total; 1.59 +} 1.60 + 1.61 +// Remove unreferenced symbols from the symbol table 1.62 +// This is done late during GC. 1.63 +void SymbolTable::unlink(int* processed, int* removed) { 1.64 + size_t memory_total = 0; 1.65 + buckets_unlink(0, the_table()->table_size(), processed, removed, &memory_total); 1.66 + _symbols_removed += *removed; 1.67 + _symbols_counted += *processed; 1.68 // Exclude printing for normal PrintGCDetails because people parse 1.69 // this output. 1.70 if (PrintGCDetails && Verbose && WizardMode) { 1.71 - gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", total, 1.72 + gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", *processed, 1.73 + (memory_total*HeapWordSize)/1024); 1.74 + } 1.75 +} 1.76 + 1.77 +void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { 1.78 + const int limit = the_table()->table_size(); 1.79 + 1.80 + size_t memory_total = 0; 1.81 + 1.82 + for (;;) { 1.83 + // Grab next set of buckets to scan 1.84 + int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; 1.85 + if (start_idx >= limit) { 1.86 + // End of table 1.87 + break; 1.88 + } 1.89 + 1.90 + int end_idx = MIN2(limit, start_idx + ClaimChunkSize); 1.91 + buckets_unlink(start_idx, end_idx, processed, removed, &memory_total); 1.92 + } 1.93 + Atomic::add(*processed, &_symbols_counted); 1.94 + Atomic::add(*removed, &_symbols_removed); 1.95 + // Exclude printing for normal PrintGCDetails because people parse 1.96 + // this output. 1.97 + if (PrintGCDetails && Verbose && WizardMode) { 1.98 + gclog_or_tty->print(" [Symbols: scanned=%d removed=%d size=" SIZE_FORMAT "K] ", *processed, *removed, 1.99 (memory_total*HeapWordSize)/1024); 1.100 } 1.101 } 1.102 @@ -494,11 +526,11 @@ 1.103 tty->print_cr("Total number of symbols %5d", count); 1.104 tty->print_cr("Total size in memory %5dK", 1.105 (memory_total*HeapWordSize)/1024); 1.106 - tty->print_cr("Total counted %5d", symbols_counted); 1.107 - tty->print_cr("Total removed %5d", symbols_removed); 1.108 - if (symbols_counted > 0) { 1.109 + tty->print_cr("Total counted %5d", _symbols_counted); 1.110 + tty->print_cr("Total removed %5d", _symbols_removed); 1.111 + if (_symbols_counted > 0) { 1.112 tty->print_cr("Percent removed %3.2f", 1.113 - ((float)symbols_removed/(float)symbols_counted)* 100); 1.114 + ((float)_symbols_removed/(float)_symbols_counted)* 100); 1.115 } 1.116 tty->print_cr("Reference counts %5d", Symbol::_total_count); 1.117 tty->print_cr("Symbol arena size %5d used %5d", 1.118 @@ -739,39 +771,38 @@ 1.119 return result; 1.120 } 1.121 1.122 -void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { 1.123 +void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { 1.124 + buckets_unlink_or_oops_do(is_alive, f, 0, the_table()->table_size(), processed, removed); 1.125 +} 1.126 + 1.127 +void StringTable::possibly_parallel_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { 1.128 // Readers of the table are unlocked, so we should only be removing 1.129 // entries at a safepoint. 1.130 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); 1.131 - for (int i = 0; i < the_table()->table_size(); ++i) { 1.132 - HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); 1.133 - HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); 1.134 - while (entry != NULL) { 1.135 - assert(!entry->is_shared(), "CDS not used for the StringTable"); 1.136 + const int limit = the_table()->table_size(); 1.137 1.138 - if (is_alive->do_object_b(entry->literal())) { 1.139 - if (f != NULL) { 1.140 - f->do_oop((oop*)entry->literal_addr()); 1.141 - } 1.142 - p = entry->next_addr(); 1.143 - } else { 1.144 - *p = entry->next(); 1.145 - the_table()->free_entry(entry); 1.146 - } 1.147 - entry = *p; 1.148 + for (;;) { 1.149 + // Grab next set of buckets to scan 1.150 + int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; 1.151 + if (start_idx >= limit) { 1.152 + // End of table 1.153 + break; 1.154 } 1.155 + 1.156 + int end_idx = MIN2(limit, start_idx + ClaimChunkSize); 1.157 + buckets_unlink_or_oops_do(is_alive, f, start_idx, end_idx, processed, removed); 1.158 } 1.159 } 1.160 1.161 -void StringTable::buckets_do(OopClosure* f, int start_idx, int end_idx) { 1.162 +void StringTable::buckets_oops_do(OopClosure* f, int start_idx, int end_idx) { 1.163 const int limit = the_table()->table_size(); 1.164 1.165 assert(0 <= start_idx && start_idx <= limit, 1.166 - err_msg("start_idx (" INT32_FORMAT ") oob?", start_idx)); 1.167 + err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); 1.168 assert(0 <= end_idx && end_idx <= limit, 1.169 - err_msg("end_idx (" INT32_FORMAT ") oob?", end_idx)); 1.170 + err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); 1.171 assert(start_idx <= end_idx, 1.172 - err_msg("Ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, 1.173 + err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, 1.174 start_idx, end_idx)); 1.175 1.176 for (int i = start_idx; i < end_idx; i += 1) { 1.177 @@ -786,12 +817,44 @@ 1.178 } 1.179 } 1.180 1.181 +void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed) { 1.182 + const int limit = the_table()->table_size(); 1.183 + 1.184 + assert(0 <= start_idx && start_idx <= limit, 1.185 + err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); 1.186 + assert(0 <= end_idx && end_idx <= limit, 1.187 + err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); 1.188 + assert(start_idx <= end_idx, 1.189 + err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, 1.190 + start_idx, end_idx)); 1.191 + 1.192 + for (int i = start_idx; i < end_idx; ++i) { 1.193 + HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); 1.194 + HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); 1.195 + while (entry != NULL) { 1.196 + assert(!entry->is_shared(), "CDS not used for the StringTable"); 1.197 + 1.198 + if (is_alive->do_object_b(entry->literal())) { 1.199 + if (f != NULL) { 1.200 + f->do_oop((oop*)entry->literal_addr()); 1.201 + } 1.202 + p = entry->next_addr(); 1.203 + } else { 1.204 + *p = entry->next(); 1.205 + the_table()->free_entry(entry); 1.206 + (*removed)++; 1.207 + } 1.208 + (*processed)++; 1.209 + entry = *p; 1.210 + } 1.211 + } 1.212 +} 1.213 + 1.214 void StringTable::oops_do(OopClosure* f) { 1.215 - buckets_do(f, 0, the_table()->table_size()); 1.216 + buckets_oops_do(f, 0, the_table()->table_size()); 1.217 } 1.218 1.219 void StringTable::possibly_parallel_oops_do(OopClosure* f) { 1.220 - const int ClaimChunkSize = 32; 1.221 const int limit = the_table()->table_size(); 1.222 1.223 for (;;) { 1.224 @@ -803,7 +866,7 @@ 1.225 } 1.226 1.227 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); 1.228 - buckets_do(f, start_idx, end_idx); 1.229 + buckets_oops_do(f, start_idx, end_idx); 1.230 } 1.231 } 1.232