src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp

changeset 8452
04a62a3d51d7
parent 0
f90c822e73f8
child 9327
f96fcd9e1e1b
     1.1 --- a/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp	Mon Jun 27 11:27:57 2016 +0000
     1.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp	Thu Jun 30 17:28:39 2016 +0300
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -28,22 +28,23 @@
    1.11  #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
    1.12  #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
    1.13  #include "gc_implementation/g1/g1StringDedupTable.hpp"
    1.14 +#include "gc_implementation/shared/concurrentGCThread.hpp"
    1.15  #include "memory/gcLocker.hpp"
    1.16  #include "memory/padded.inline.hpp"
    1.17  #include "oops/typeArrayOop.hpp"
    1.18  #include "runtime/mutexLocker.hpp"
    1.19  
    1.20  //
    1.21 -// Freelist in the deduplication table entry cache. Links table
    1.22 +// List of deduplication table entries. Links table
    1.23  // entries together using their _next fields.
    1.24  //
    1.25 -class G1StringDedupEntryFreeList : public CHeapObj<mtGC> {
    1.26 +class G1StringDedupEntryList : public CHeapObj<mtGC> {
    1.27  private:
    1.28    G1StringDedupEntry* _list;
    1.29    size_t              _length;
    1.30  
    1.31  public:
    1.32 -  G1StringDedupEntryFreeList() :
    1.33 +  G1StringDedupEntryList() :
    1.34      _list(NULL),
    1.35      _length(0) {
    1.36    }
    1.37 @@ -63,6 +64,12 @@
    1.38      return entry;
    1.39    }
    1.40  
    1.41 +  G1StringDedupEntry* remove_all() {
    1.42 +    G1StringDedupEntry* list = _list;
    1.43 +    _list = NULL;
    1.44 +    return list;
    1.45 +  }
    1.46 +
    1.47    size_t length() {
    1.48      return _length;
    1.49    }
    1.50 @@ -84,43 +91,53 @@
    1.51  //
    1.52  class G1StringDedupEntryCache : public CHeapObj<mtGC> {
    1.53  private:
    1.54 -  // One freelist per GC worker to allow lock less freeing of
    1.55 -  // entries while doing a parallel scan of the table. Using
    1.56 -  // PaddedEnd to avoid false sharing.
    1.57 -  PaddedEnd<G1StringDedupEntryFreeList>* _lists;
    1.58 -  size_t                                 _nlists;
    1.59 +  // One cache/overflow list per GC worker to allow lock less freeing of
    1.60 +  // entries while doing a parallel scan of the table. Using PaddedEnd to
    1.61 +  // avoid false sharing.
    1.62 +  size_t                             _nlists;
    1.63 +  size_t                             _max_list_length;
    1.64 +  PaddedEnd<G1StringDedupEntryList>* _cached;
    1.65 +  PaddedEnd<G1StringDedupEntryList>* _overflowed;
    1.66  
    1.67  public:
    1.68 -  G1StringDedupEntryCache();
    1.69 +  G1StringDedupEntryCache(size_t max_size);
    1.70    ~G1StringDedupEntryCache();
    1.71  
    1.72 -  // Get a table entry from the cache freelist, or allocate a new
    1.73 -  // entry if the cache is empty.
    1.74 +  // Set max number of table entries to cache.
    1.75 +  void set_max_size(size_t max_size);
    1.76 +
    1.77 +  // Get a table entry from the cache, or allocate a new entry if the cache is empty.
    1.78    G1StringDedupEntry* alloc();
    1.79  
    1.80 -  // Insert a table entry into the cache freelist.
    1.81 +  // Insert a table entry into the cache.
    1.82    void free(G1StringDedupEntry* entry, uint worker_id);
    1.83  
    1.84    // Returns current number of entries in the cache.
    1.85    size_t size();
    1.86  
    1.87 -  // If the cache has grown above the given max size, trim it down
    1.88 -  // and deallocate the memory occupied by trimmed of entries.
    1.89 -  void trim(size_t max_size);
    1.90 +  // Deletes overflowed entries.
    1.91 +  void delete_overflowed();
    1.92  };
    1.93  
    1.94 -G1StringDedupEntryCache::G1StringDedupEntryCache() {
    1.95 -  _nlists = MAX2(ParallelGCThreads, (size_t)1);
    1.96 -  _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists);
    1.97 +G1StringDedupEntryCache::G1StringDedupEntryCache(size_t max_size) :
    1.98 +  _nlists(MAX2(ParallelGCThreads, (size_t)1)),
    1.99 +  _max_list_length(0),
   1.100 +  _cached(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)),
   1.101 +  _overflowed(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)) {
   1.102 +  set_max_size(max_size);
   1.103  }
   1.104  
   1.105  G1StringDedupEntryCache::~G1StringDedupEntryCache() {
   1.106    ShouldNotReachHere();
   1.107  }
   1.108  
   1.109 +void G1StringDedupEntryCache::set_max_size(size_t size) {
   1.110 +  _max_list_length = size / _nlists;
   1.111 +}
   1.112 +
   1.113  G1StringDedupEntry* G1StringDedupEntryCache::alloc() {
   1.114    for (size_t i = 0; i < _nlists; i++) {
   1.115 -    G1StringDedupEntry* entry = _lists[i].remove();
   1.116 +    G1StringDedupEntry* entry = _cached[i].remove();
   1.117      if (entry != NULL) {
   1.118        return entry;
   1.119      }
   1.120 @@ -131,31 +148,55 @@
   1.121  void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) {
   1.122    assert(entry->obj() != NULL, "Double free");
   1.123    assert(worker_id < _nlists, "Invalid worker id");
   1.124 +
   1.125    entry->set_obj(NULL);
   1.126    entry->set_hash(0);
   1.127 -  _lists[worker_id].add(entry);
   1.128 +
   1.129 +  if (_cached[worker_id].length() < _max_list_length) {
   1.130 +    // Cache is not full
   1.131 +    _cached[worker_id].add(entry);
   1.132 +  } else {
   1.133 +    // Cache is full, add to overflow list for later deletion
   1.134 +    _overflowed[worker_id].add(entry);
   1.135 +  }
   1.136  }
   1.137  
   1.138  size_t G1StringDedupEntryCache::size() {
   1.139    size_t size = 0;
   1.140    for (size_t i = 0; i < _nlists; i++) {
   1.141 -    size += _lists[i].length();
   1.142 +    size += _cached[i].length();
   1.143    }
   1.144    return size;
   1.145  }
   1.146  
   1.147 -void G1StringDedupEntryCache::trim(size_t max_size) {
   1.148 -  size_t cache_size = 0;
   1.149 +void G1StringDedupEntryCache::delete_overflowed() {
   1.150 +  double start = os::elapsedTime();
   1.151 +  uintx count = 0;
   1.152 +
   1.153    for (size_t i = 0; i < _nlists; i++) {
   1.154 -    G1StringDedupEntryFreeList* list = &_lists[i];
   1.155 -    cache_size += list->length();
   1.156 -    while (cache_size > max_size) {
   1.157 -      G1StringDedupEntry* entry = list->remove();
   1.158 -      assert(entry != NULL, "Should not be null");
   1.159 -      cache_size--;
   1.160 +    G1StringDedupEntry* entry;
   1.161 +
   1.162 +    {
   1.163 +      // The overflow list can be modified during safepoints, therefore
   1.164 +      // we temporarily join the suspendible thread set while removing
   1.165 +      // all entries from the list.
   1.166 +      SuspendibleThreadSetJoiner sts_join;
   1.167 +      entry = _overflowed[i].remove_all();
   1.168 +    }
   1.169 +
   1.170 +    // Delete all entries
   1.171 +    while (entry != NULL) {
   1.172 +      G1StringDedupEntry* next = entry->next();
   1.173        delete entry;
   1.174 +      entry = next;
   1.175 +      count++;
   1.176      }
   1.177    }
   1.178 +
   1.179 +  double end = os::elapsedTime();
   1.180 +  if (PrintStringDeduplicationStatistics) {
   1.181 +    gclog_or_tty->print_cr("[GC concurrent-string-deduplication, deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT "]", count, end - start);
   1.182 +  }
   1.183  }
   1.184  
   1.185  G1StringDedupTable*      G1StringDedupTable::_table = NULL;
   1.186 @@ -192,7 +233,7 @@
   1.187  
   1.188  void G1StringDedupTable::create() {
   1.189    assert(_table == NULL, "One string deduplication table allowed");
   1.190 -  _entry_cache = new G1StringDedupEntryCache();
   1.191 +  _entry_cache = new G1StringDedupEntryCache((size_t)(_min_size * _max_cache_factor));
   1.192    _table = new G1StringDedupTable(_min_size);
   1.193  }
   1.194  
   1.195 @@ -375,6 +416,9 @@
   1.196    // Update statistics
   1.197    _resize_count++;
   1.198  
   1.199 +  // Update max cache size
   1.200 +  _entry_cache->set_max_size((size_t)(size * _max_cache_factor));
   1.201 +
   1.202    // Allocate the new table. The new table will be populated by workers
   1.203    // calling unlink_or_oops_do() and finally installed by finish_resize().
   1.204    return new G1StringDedupTable(size, _table->_hash_seed);
   1.205 @@ -427,7 +471,7 @@
   1.206      removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id);
   1.207    }
   1.208  
   1.209 -  // Delayed update avoid contention on the table lock
   1.210 +  // Delayed update to avoid contention on the table lock
   1.211    if (removed > 0) {
   1.212      MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
   1.213      _table->_entries -= removed;
   1.214 @@ -545,10 +589,8 @@
   1.215    }
   1.216  }
   1.217  
   1.218 -void G1StringDedupTable::trim_entry_cache() {
   1.219 -  MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
   1.220 -  size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor);
   1.221 -  _entry_cache->trim(max_cache_size);
   1.222 +void G1StringDedupTable::clean_entry_cache() {
   1.223 +  _entry_cache->delete_overflowed();
   1.224  }
   1.225  
   1.226  void G1StringDedupTable::print_statistics(outputStream* st) {

mercurial