1 /* 2 * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 24 #include "precompiled.hpp" 25 26 #include "gc_implementation/shared/suspendibleThreadSet.hpp" 27 #include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp" 28 #include "gc_implementation/shenandoah/shenandoahLogging.hpp" 29 #include "gc_implementation/shenandoah/shenandoahStrDedupQueue.inline.hpp" 30 #include "gc_implementation/shenandoah/shenandoahStrDedupThread.hpp" 31 #include "gc_implementation/shenandoah/shenandoahStringDedup.hpp" 32 #include "gc_implementation/shenandoah/shenandoahUtils.hpp" 33 34 ShenandoahStrDedupThread::ShenandoahStrDedupThread(ShenandoahStrDedupQueueSet* queues) : 35 ConcurrentGCThread(), _queues(queues), _claimed(0) { 36 size_t num_queues = queues->num_queues(); 37 _work_list = NEW_C_HEAP_ARRAY(QueueChunkedList*, num_queues, mtGC); 38 for (size_t index = 0; index < num_queues; index ++) { 39 _work_list[index] = NULL; 40 } 41 42 set_name("%s", "ShenandoahStringDedupTherad"); 43 create_and_start(); 44 } 45 46 ShenandoahStrDedupThread::~ShenandoahStrDedupThread() { 47 ShouldNotReachHere(); 48 } 49 50 void ShenandoahStrDedupThread::run() { 51 for (;;) { 52 ShenandoahStrDedupStats stats; 53 54 assert(is_work_list_empty(), "Work list must be empty"); 55 // Queue has been shutdown 56 if (!poll(&stats)) { 57 assert(queues()->has_terminated(), "Must be terminated"); 58 break; 59 } 60 61 // Include thread in safepoints 62 SuspendibleThreadSetJoiner sts_join; 63 // Process the queue 64 for (uint queue_index = 0; queue_index < queues()->num_queues(); queue_index ++) { 65 QueueChunkedList* cur_list = _work_list[queue_index]; 66 67 while (cur_list != NULL) { 68 stats.mark_exec(); 69 70 while (!cur_list->is_empty()) { 71 oop java_string = cur_list->pop(); 72 stats.inc_inspected(); 73 assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must not at Shenandoah safepoint"); 74 75 if (oopDesc::is_null(java_string) || 76 !ShenandoahStringDedup::is_candidate(java_string)) { 77 stats.inc_skipped(); 78 } else { 79 if (ShenandoahStringDedup::deduplicate(java_string, false /* update counter */)) { 80 stats.inc_deduped(); 81 } else { 82 stats.inc_known(); 83 } 84 } 85 86 // Safepoint this thread if needed 87 if (sts_join.should_yield()) { 88 stats.mark_block(); 89 sts_join.yield(); 90 stats.mark_unblock(); 91 } 92 } 93 94 // Advance list only after processed. Otherwise, we may miss scanning 95 // during safepoints 96 _work_list[queue_index] = cur_list->next(); 97 queues()->release_chunked_list(cur_list); 98 cur_list = _work_list[queue_index]; 99 } 100 } 101 102 stats.mark_done(); 103 104 ShenandoahStringDedup::dedup_stats().update(stats); 105 106 if (ShenandoahLogDebug) { 107 stats.print_statistics(tty); 108 } 109 } 110 111 if (ShenandoahLogDebug) { 112 ShenandoahStringDedup::print_statistics(tty); 113 } 114 } 115 116 void ShenandoahStrDedupThread::stop() { 117 queues()->terminate(); 118 } 119 120 void ShenandoahStrDedupThread::parallel_oops_do(OopClosure* cl) { 121 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 122 size_t claimed_index; 123 while ((claimed_index = claim()) < queues()->num_queues()) { 124 QueueChunkedList* q = _work_list[claimed_index]; 125 while (q != NULL) { 126 q->oops_do(cl); 127 q = q->next(); 128 } 129 } 130 } 131 132 void ShenandoahStrDedupThread::oops_do_slow(OopClosure* cl) { 133 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 134 for (size_t index = 0; index < queues()->num_queues(); index ++) { 135 QueueChunkedList* q = _work_list[index]; 136 while (q != NULL) { 137 q->oops_do(cl); 138 q = q->next(); 139 } 140 } 141 } 142 143 bool ShenandoahStrDedupThread::is_work_list_empty() const { 144 assert(Thread::current() == this, "Only from dedup thread"); 145 for (uint index = 0; index < queues()->num_queues(); index ++) { 146 if (_work_list[index] != NULL) return false; 147 } 148 return true; 149 } 150 151 void ShenandoahStrDedupThread::parallel_cleanup() { 152 ShenandoahStrDedupQueueCleanupClosure cl; 153 parallel_oops_do(&cl); 154 } 155 156 bool ShenandoahStrDedupThread::poll(ShenandoahStrDedupStats* stats) { 157 assert(is_work_list_empty(), "Only poll when work list is empty"); 158 159 while (!_queues->has_terminated()) { 160 { 161 bool has_work = false; 162 stats->mark_exec(); 163 // Include thread in safepoints 164 SuspendibleThreadSetJoiner sts_join; 165 166 for (uint index = 0; index < queues()->num_queues(); index ++) { 167 assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Not at Shenandoah Safepoint"); 168 _work_list[index] = queues()->remove_work_list_atomic(index); 169 if (_work_list[index] != NULL) { 170 has_work = true; 171 } 172 173 // Safepoint this thread if needed 174 if (sts_join.should_yield()) { 175 stats->mark_block(); 176 sts_join.yield(); 177 stats->mark_unblock(); 178 } 179 } 180 181 if (has_work) return true; 182 } 183 184 { 185 stats->mark_idle(); 186 MonitorLockerEx locker(queues()->lock(), Monitor::_no_safepoint_check_flag); 187 locker.wait(Mutex::_no_safepoint_check_flag); 188 } 189 } 190 return false; 191 } 192 193 size_t ShenandoahStrDedupThread::claim() { 194 size_t index = (size_t)Atomic::add(1, (volatile jint*)&_claimed) - 1; 195 return index; 196 }