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

Print this page
rev 6141 : [mq]: review_fixes


  52     entry->set_next(_list);
  53     _list = entry;
  54     _length++;
  55   }
  56 
  57   G1StringDedupEntry* remove() {
  58     G1StringDedupEntry* entry = _list;
  59     if (entry != NULL) {
  60       _list = entry->next();
  61       _length--;
  62     }
  63     return entry;
  64   }
  65 
  66   size_t length() {
  67     return _length;
  68   }
  69 };
  70 
  71 //
  72 // Cache of deduplication table enties. This cache provides fast allocation and
  73 // reuse of table entries to lower the preasure on the underlaying allocator.
  74 // But more importantly, it provides fast/deferred freeing of table entries. This
  75 // is important because freeing of table entries is done during stop-the-world
  76 // phases and it is not uncommon for large number of String to be freed at once.
  77 // Tables entries that are freed during these phases are placed onto a freelist in
  78 // the cache. The deduplication thread, which executes in a concurrent phase, will
  79 // later reuse or free the underlaying memory for these entries.
  80 //
  81 // The cache allows for single-threaded allocations and multi-threaded frees.
  82 // Allocations are synchronized by StringDedupTable_lock as part of a table
  83 // modification.
  84 //
  85 class G1StringDedupEntryCache : public CHeapObj<mtGC> {
  86 private:
  87   // One freelist per GC worker to allow lock less freeing of
  88   // entries while doing a parallel scan of the table. Using
  89   // PaddedEnd to avoid false sharing.
  90   PaddedEnd<G1StringDedupEntryFreeList>* _lists;
  91   size_t                                 _nlists;
  92 
  93 public:
  94   G1StringDedupEntryCache();
  95   ~G1StringDedupEntryCache();
  96 
  97   // Get a table entry from the cache freelist, or allocate a new
  98   // entry if the cache is empty.
  99   G1StringDedupEntry* alloc();
 100 
 101   // Insert a table entry into the cache freelist.
 102   void free(G1StringDedupEntry* entry, uint worker_id);
 103 



 104   // If the cache has grown above the given max size, trim it down
 105   // and deallocate the memory occupied by trimmed of entries.
 106   void trim(size_t max_size);
 107 };
 108 
 109 G1StringDedupEntryCache::G1StringDedupEntryCache() {
 110   _nlists = MAX2(ParallelGCThreads, (size_t)1);
 111   _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists);
 112 }
 113 
 114 G1StringDedupEntryCache::~G1StringDedupEntryCache() {
 115   ShouldNotReachHere();
 116 }
 117 
 118 G1StringDedupEntry* G1StringDedupEntryCache::alloc() {
 119   for (size_t i = 0; i < _nlists; i++) {
 120     G1StringDedupEntry* entry = _lists[i].remove();
 121     if (entry != NULL) {
 122       return entry;
 123     }
 124   }
 125   return new G1StringDedupEntry();
 126 }
 127 
 128 void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) {
 129   assert(entry->obj() != NULL, "Double free");
 130   assert(worker_id < _nlists, "Invalid worker id");
 131   entry->set_obj(NULL);
 132   entry->set_hash(0);
 133   _lists[worker_id].add(entry);
 134 }
 135 








 136 void G1StringDedupEntryCache::trim(size_t max_size) {
 137   size_t cache_size = 0;
 138   for (size_t i = 0; i < _nlists; i++) {
 139     G1StringDedupEntryFreeList* list = &_lists[i];
 140     cache_size += list->length();
 141     while (cache_size > max_size) {
 142       G1StringDedupEntry* entry = list->remove();
 143       assert(entry != NULL, "Should not be null");
 144       cache_size--;
 145       delete entry;
 146     }
 147   }
 148 }
 149 
 150 G1StringDedupTable*      G1StringDedupTable::_table = NULL;
 151 G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL;
 152 
 153 const size_t             G1StringDedupTable::_min_size = (1 << 10);   // 1024
 154 const size_t             G1StringDedupTable::_max_size = (1 << 24);   // 16777216
 155 const double             G1StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load


 528         typeArrayOop value2 = (*entry2)->obj();
 529         guarantee(!equals(value1, value2), "Table entries must not have identical arrays");
 530         entry2 = (*entry2)->next_addr();
 531       }
 532       entry1 = (*entry1)->next_addr();
 533     }
 534   }
 535 }
 536 
 537 void G1StringDedupTable::trim_entry_cache() {
 538   MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
 539   size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor);
 540   _entry_cache->trim(max_cache_size);
 541 }
 542 
 543 void G1StringDedupTable::print_statistics(outputStream* st) {
 544   st->print_cr(
 545     "   [Table]\n"
 546     "      [Memory Usage: "G1_STRDEDUP_BYTES_FORMAT_NS"]\n"
 547     "      [Size: "SIZE_FORMAT", Min: "SIZE_FORMAT", Max: "SIZE_FORMAT"]\n"
 548     "      [Entries: "UINTX_FORMAT", Load: "G1_STRDEDUP_PERCENT_FORMAT_NS", Added: "UINTX_FORMAT", Removed: "UINTX_FORMAT"]\n"
 549     "      [Resize Count: "UINTX_FORMAT", Shrink Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS"), Grow Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS")]\n"
 550     "      [Rehash Count: "UINTX_FORMAT", Rehash Threshold: "UINTX_FORMAT", Hash Seed: 0x%x]\n"
 551     "      [Age Threshold: "UINTX_FORMAT"]",
 552     G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + _table->_entries * sizeof(G1StringDedupEntry)),
 553     _table->_size, _min_size, _max_size,
 554     _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entries_added, _entries_removed,
 555     _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0,
 556     _rehash_count, _rehash_threshold, _table->_hash_seed,
 557     StringDeduplicationAgeThreshold);
 558 }


  52     entry->set_next(_list);
  53     _list = entry;
  54     _length++;
  55   }
  56 
  57   G1StringDedupEntry* remove() {
  58     G1StringDedupEntry* entry = _list;
  59     if (entry != NULL) {
  60       _list = entry->next();
  61       _length--;
  62     }
  63     return entry;
  64   }
  65 
  66   size_t length() {
  67     return _length;
  68   }
  69 };
  70 
  71 //
  72 // Cache of deduplication table entries. This cache provides fast allocation and
  73 // reuse of table entries to lower the pressure on the underlying allocator.
  74 // But more importantly, it provides fast/deferred freeing of table entries. This
  75 // is important because freeing of table entries is done during stop-the-world
  76 // phases and it is not uncommon for large number of entries to be freed at once.
  77 // Tables entries that are freed during these phases are placed onto a freelist in
  78 // the cache. The deduplication thread, which executes in a concurrent phase, will
  79 // later reuse or free the underlying memory for these entries.
  80 //
  81 // The cache allows for single-threaded allocations and multi-threaded frees.
  82 // Allocations are synchronized by StringDedupTable_lock as part of a table
  83 // modification.
  84 //
  85 class G1StringDedupEntryCache : public CHeapObj<mtGC> {
  86 private:
  87   // One freelist per GC worker to allow lock less freeing of
  88   // entries while doing a parallel scan of the table. Using
  89   // PaddedEnd to avoid false sharing.
  90   PaddedEnd<G1StringDedupEntryFreeList>* _lists;
  91   size_t                                 _nlists;
  92 
  93 public:
  94   G1StringDedupEntryCache();
  95   ~G1StringDedupEntryCache();
  96 
  97   // Get a table entry from the cache freelist, or allocate a new
  98   // entry if the cache is empty.
  99   G1StringDedupEntry* alloc();
 100 
 101   // Insert a table entry into the cache freelist.
 102   void free(G1StringDedupEntry* entry, uint worker_id);
 103 
 104   // Returns current number of entries in the cache.
 105   size_t size();
 106 
 107   // If the cache has grown above the given max size, trim it down
 108   // and deallocate the memory occupied by trimmed of entries.
 109   void trim(size_t max_size);
 110 };
 111 
 112 G1StringDedupEntryCache::G1StringDedupEntryCache() {
 113   _nlists = MAX2(ParallelGCThreads, (size_t)1);
 114   _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists);
 115 }
 116 
 117 G1StringDedupEntryCache::~G1StringDedupEntryCache() {
 118   ShouldNotReachHere();
 119 }
 120 
 121 G1StringDedupEntry* G1StringDedupEntryCache::alloc() {
 122   for (size_t i = 0; i < _nlists; i++) {
 123     G1StringDedupEntry* entry = _lists[i].remove();
 124     if (entry != NULL) {
 125       return entry;
 126     }
 127   }
 128   return new G1StringDedupEntry();
 129 }
 130 
 131 void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) {
 132   assert(entry->obj() != NULL, "Double free");
 133   assert(worker_id < _nlists, "Invalid worker id");
 134   entry->set_obj(NULL);
 135   entry->set_hash(0);
 136   _lists[worker_id].add(entry);
 137 }
 138 
 139 size_t G1StringDedupEntryCache::size() {
 140   size_t size = 0;
 141   for (size_t i = 0; i < _nlists; i++) {
 142     size += _lists[i].length();
 143   }
 144   return size;
 145 }
 146 
 147 void G1StringDedupEntryCache::trim(size_t max_size) {
 148   size_t cache_size = 0;
 149   for (size_t i = 0; i < _nlists; i++) {
 150     G1StringDedupEntryFreeList* list = &_lists[i];
 151     cache_size += list->length();
 152     while (cache_size > max_size) {
 153       G1StringDedupEntry* entry = list->remove();
 154       assert(entry != NULL, "Should not be null");
 155       cache_size--;
 156       delete entry;
 157     }
 158   }
 159 }
 160 
 161 G1StringDedupTable*      G1StringDedupTable::_table = NULL;
 162 G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL;
 163 
 164 const size_t             G1StringDedupTable::_min_size = (1 << 10);   // 1024
 165 const size_t             G1StringDedupTable::_max_size = (1 << 24);   // 16777216
 166 const double             G1StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load


 539         typeArrayOop value2 = (*entry2)->obj();
 540         guarantee(!equals(value1, value2), "Table entries must not have identical arrays");
 541         entry2 = (*entry2)->next_addr();
 542       }
 543       entry1 = (*entry1)->next_addr();
 544     }
 545   }
 546 }
 547 
 548 void G1StringDedupTable::trim_entry_cache() {
 549   MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
 550   size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor);
 551   _entry_cache->trim(max_cache_size);
 552 }
 553 
 554 void G1StringDedupTable::print_statistics(outputStream* st) {
 555   st->print_cr(
 556     "   [Table]\n"
 557     "      [Memory Usage: "G1_STRDEDUP_BYTES_FORMAT_NS"]\n"
 558     "      [Size: "SIZE_FORMAT", Min: "SIZE_FORMAT", Max: "SIZE_FORMAT"]\n"
 559     "      [Entries: "UINTX_FORMAT", Load: "G1_STRDEDUP_PERCENT_FORMAT_NS", Cached: " UINTX_FORMAT ", Added: "UINTX_FORMAT", Removed: "UINTX_FORMAT"]\n"
 560     "      [Resize Count: "UINTX_FORMAT", Shrink Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS"), Grow Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS")]\n"
 561     "      [Rehash Count: "UINTX_FORMAT", Rehash Threshold: "UINTX_FORMAT", Hash Seed: 0x%x]\n"
 562     "      [Age Threshold: "UINTX_FORMAT"]",
 563     G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)),
 564     _table->_size, _min_size, _max_size,
 565     _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed,
 566     _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0,
 567     _rehash_count, _rehash_threshold, _table->_hash_seed,
 568     StringDeduplicationAgeThreshold);
 569 }