src/share/vm/classfile/symbolTable.cpp

changeset 6229
5a32d2a3cc1e
parent 5785
a5ac0873476c
child 6413
595c0f60d50d
     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  

mercurial