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   initialize_in_thread();
  52   wait_for_universe_init();
  53 
  54   for (;;) {
  55     ShenandoahStrDedupStats stats;
  56 
  57     assert(is_work_list_empty(), "Work list must be empty");
  58     // Queue has been shutdown
  59     if (!poll(&stats)) {
  60       assert(queues()->has_terminated(), "Must be terminated");
  61       break;
  62     }
  63 
  64     // Include thread in safepoints
  65     SuspendibleThreadSetJoiner sts_join;
  66     // Process the queue
  67     for (uint queue_index = 0; queue_index < queues()->num_queues(); queue_index ++) {
  68       QueueChunkedList* cur_list = _work_list[queue_index];
  69 
  70       while (cur_list != NULL) {
  71         stats.mark_exec();
  72 
  73         while (!cur_list->is_empty()) {
  74           oop java_string = cur_list->pop();
  75           stats.inc_inspected();
  76           assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must not at Shenandoah safepoint");
  77 
  78           if (oopDesc::is_null(java_string) ||
  79               !ShenandoahStringDedup::is_candidate(java_string)) {
  80             stats.inc_skipped();
  81           } else {
  82             if (ShenandoahStringDedup::deduplicate(java_string, false /* update counter */)) {
  83               stats.inc_deduped();
  84             } else {
  85               stats.inc_known();
  86             }
  87           }
  88 
  89           // Safepoint this thread if needed
  90           if (sts_join.should_yield()) {
  91             stats.mark_block();
  92             sts_join.yield();
  93             stats.mark_unblock();
  94           }
  95         }
  96 
  97         // Advance list only after processed. Otherwise, we may miss scanning
  98         // during safepoints
  99         _work_list[queue_index] = cur_list->next();
 100         queues()->release_chunked_list(cur_list);
 101         cur_list = _work_list[queue_index];
 102       }
 103     }
 104 
 105     stats.mark_done();
 106 
 107     ShenandoahStringDedup::dedup_stats().update(stats);
 108 
 109     if (ShenandoahLogDebug) {
 110       stats.print_statistics(tty);
 111     }
 112   }
 113 
 114   if (ShenandoahLogDebug) {
 115     ShenandoahStringDedup::print_statistics(tty);
 116   }
 117 }
 118 
 119 void ShenandoahStrDedupThread::stop() {
 120   queues()->terminate();
 121 }
 122 
 123 void ShenandoahStrDedupThread::parallel_oops_do(OopClosure* cl) {
 124   assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 125   size_t claimed_index;
 126   while ((claimed_index = claim()) < queues()->num_queues()) {
 127     QueueChunkedList* q = _work_list[claimed_index];
 128     while (q != NULL) {
 129       q->oops_do(cl);
 130       q = q->next();
 131     }
 132   }
 133 }
 134 
 135 void ShenandoahStrDedupThread::oops_do_slow(OopClosure* cl) {
 136   assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 137   for (size_t index = 0; index < queues()->num_queues(); index ++) {
 138     QueueChunkedList* q = _work_list[index];
 139     while (q != NULL) {
 140       q->oops_do(cl);
 141       q = q->next();
 142     }
 143   }
 144 }
 145 
 146 bool ShenandoahStrDedupThread::is_work_list_empty() const {
 147   assert(Thread::current() == this, "Only from dedup thread");
 148   for (uint index = 0; index < queues()->num_queues(); index ++) {
 149     if (_work_list[index] != NULL) return false;
 150   }
 151   return true;
 152 }
 153 
 154 void ShenandoahStrDedupThread::parallel_cleanup() {
 155   ShenandoahStrDedupQueueCleanupClosure cl;
 156   parallel_oops_do(&cl);
 157 }
 158 
 159 bool ShenandoahStrDedupThread::poll(ShenandoahStrDedupStats* stats) {
 160   assert(is_work_list_empty(), "Only poll when work list is empty");
 161 
 162   while (!_queues->has_terminated()) {
 163     {
 164       bool has_work = false;
 165       stats->mark_exec();
 166       // Include thread in safepoints
 167       SuspendibleThreadSetJoiner sts_join;
 168 
 169       for (uint index = 0; index < queues()->num_queues(); index ++) {
 170         assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Not at Shenandoah Safepoint");
 171         _work_list[index] = queues()->remove_work_list_atomic(index);
 172         if (_work_list[index] != NULL) {
 173           has_work = true;
 174         }
 175 
 176         // Safepoint this thread if needed
 177         if (sts_join.should_yield()) {
 178           stats->mark_block();
 179           sts_join.yield();
 180           stats->mark_unblock();
 181         }
 182       }
 183 
 184       if (has_work) return true;
 185     }
 186 
 187     {
 188       stats->mark_idle();
 189       MonitorLockerEx locker(queues()->lock(), Monitor::_no_safepoint_check_flag);
 190       locker.wait(Mutex::_no_safepoint_check_flag);
 191     }
 192   }
 193   return false;
 194 }
 195 
 196 size_t ShenandoahStrDedupThread::claim() {
 197   size_t index = (size_t)Atomic::add(1, (volatile jint*)&_claimed) - 1;
 198   return index;
 199 }