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 }
|