src/hotspot/share/gc/shenandoah/shenandoahStrDedupQueue.cpp
changeset 52925 9c18c9d839d3
child 53383 5dc89efc08f0
equal deleted inserted replaced
52924:420ff459906f 52925:9c18c9d839d3
       
     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/shared/stringdedup/stringDedup.hpp"
       
    27 #include "gc/shared/stringdedup/stringDedupThread.hpp"
       
    28 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
       
    29 #include "gc/shenandoah/shenandoahStrDedupQueue.hpp"
       
    30 #include "gc/shenandoah/shenandoahStrDedupQueue.inline.hpp"
       
    31 #include "gc/shenandoah/shenandoahStringDedup.hpp"
       
    32 #include "logging/log.hpp"
       
    33 #include "runtime/mutex.hpp"
       
    34 #include "runtime/mutexLocker.hpp"
       
    35 
       
    36 ShenandoahStrDedupQueue::ShenandoahStrDedupQueue() :
       
    37   _consumer_queue(NULL),
       
    38   _num_producer_queue(ShenandoahHeap::heap()->max_workers()),
       
    39   _published_queues(NULL),
       
    40   _free_list(NULL),
       
    41   _num_free_buffer(0),
       
    42   _max_free_buffer(ShenandoahHeap::heap()->max_workers() * 2),
       
    43   _cancel(false),
       
    44   _total_buffers(0) {
       
    45   _producer_queues = NEW_C_HEAP_ARRAY(ShenandoahQueueBuffer*, _num_producer_queue, mtGC);
       
    46   for (size_t index = 0; index < _num_producer_queue; index ++) {
       
    47     _producer_queues[index] = NULL;
       
    48   }
       
    49 }
       
    50 
       
    51 ShenandoahStrDedupQueue::~ShenandoahStrDedupQueue() {
       
    52   MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
       
    53   for (size_t index = 0; index < num_queues(); index ++) {
       
    54     release_buffers(queue_at(index));
       
    55   }
       
    56 
       
    57   release_buffers(_free_list);
       
    58   FREE_C_HEAP_ARRAY(ShenandoahQueueBuffer*, _producer_queues);
       
    59 }
       
    60 
       
    61 void ShenandoahStrDedupQueue::wait_impl() {
       
    62   MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
       
    63   while (_consumer_queue == NULL && !_cancel) {
       
    64     ml.wait(Mutex::_no_safepoint_check_flag);
       
    65     assert(_consumer_queue == NULL, "Why wait?");
       
    66     _consumer_queue = _published_queues;
       
    67     _published_queues = NULL;
       
    68   }
       
    69 }
       
    70 
       
    71 void ShenandoahStrDedupQueue::cancel_wait_impl() {
       
    72   MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
       
    73   _cancel = true;
       
    74   ml.notify();
       
    75 }
       
    76 
       
    77 void ShenandoahStrDedupQueue::unlink_or_oops_do_impl(StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) {
       
    78   ShenandoahQueueBuffer* q = queue_at(queue);
       
    79   while (q != NULL) {
       
    80     q->unlink_or_oops_do(cl);
       
    81     q = q->next();
       
    82   }
       
    83 }
       
    84 
       
    85 ShenandoahQueueBuffer* ShenandoahStrDedupQueue::queue_at(size_t queue_id) const {
       
    86   assert(queue_id <= num_queues(), "Invalid queue id");
       
    87   if (queue_id < _num_producer_queue) {
       
    88     return _producer_queues[queue_id];
       
    89   } else if (queue_id == _num_producer_queue) {
       
    90     return _consumer_queue;
       
    91   } else {
       
    92     assert(queue_id == _num_producer_queue + 1, "Must be");
       
    93     return _published_queues;
       
    94   }
       
    95 }
       
    96 
       
    97 void ShenandoahStrDedupQueue::set_producer_buffer(ShenandoahQueueBuffer* buf, size_t queue_id) {
       
    98   assert(queue_id < _num_producer_queue, "Not a producer queue id");
       
    99   _producer_queues[queue_id] = buf;
       
   100 }
       
   101 
       
   102 void ShenandoahStrDedupQueue::push_impl(uint worker_id, oop string_oop) {
       
   103   assert(worker_id < _num_producer_queue, "Invalid queue id. Can only push to producer queue");
       
   104   assert(ShenandoahStringDedup::is_candidate(string_oop), "Not a candidate");
       
   105 
       
   106   ShenandoahQueueBuffer* buf = queue_at((size_t)worker_id);
       
   107 
       
   108   if (buf == NULL) {
       
   109     MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
       
   110     buf = new_buffer();
       
   111     set_producer_buffer(buf, worker_id);
       
   112   } else if (buf->is_full()) {
       
   113     MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
       
   114     buf->set_next(_published_queues);
       
   115     _published_queues = buf;
       
   116     buf = new_buffer();
       
   117     set_producer_buffer(buf, worker_id);
       
   118     ml.notify();
       
   119   }
       
   120 
       
   121   assert(!buf->is_full(), "Sanity");
       
   122   buf->push(string_oop);
       
   123 }
       
   124 
       
   125 oop ShenandoahStrDedupQueue::pop_impl() {
       
   126   assert(Thread::current() == StringDedupThread::thread(), "Must be dedup thread");
       
   127   while (true) {
       
   128     if (_consumer_queue == NULL) {
       
   129       MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
       
   130       _consumer_queue = _published_queues;
       
   131       _published_queues = NULL;
       
   132     }
       
   133 
       
   134     // there is nothing
       
   135     if (_consumer_queue == NULL) {
       
   136       return NULL;
       
   137     }
       
   138 
       
   139     oop obj = NULL;
       
   140     if (pop_candidate(obj)) {
       
   141       assert(ShenandoahStringDedup::is_candidate(obj), "Must be a candidate");
       
   142       return obj;
       
   143     }
       
   144     assert(obj == NULL, "No more candidate");
       
   145   }
       
   146 }
       
   147 
       
   148 bool ShenandoahStrDedupQueue::pop_candidate(oop& obj) {
       
   149   ShenandoahQueueBuffer* to_release = NULL;
       
   150   bool suc = true;
       
   151   do {
       
   152     if (_consumer_queue->is_empty()) {
       
   153       ShenandoahQueueBuffer* buf = _consumer_queue;
       
   154       _consumer_queue = _consumer_queue->next();
       
   155       buf->set_next(to_release);
       
   156       to_release = buf;
       
   157 
       
   158       if (_consumer_queue == NULL) {
       
   159         suc = false;
       
   160         break;
       
   161       }
       
   162     }
       
   163     obj = _consumer_queue->pop();
       
   164   } while (obj == NULL);
       
   165 
       
   166   if (to_release != NULL) {
       
   167     MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
       
   168     release_buffers(to_release);
       
   169   }
       
   170 
       
   171   return suc;
       
   172 }
       
   173 
       
   174 ShenandoahQueueBuffer* ShenandoahStrDedupQueue::new_buffer() {
       
   175   assert_lock_strong(StringDedupQueue_lock);
       
   176   if (_free_list != NULL) {
       
   177     assert(_num_free_buffer > 0, "Sanity");
       
   178     ShenandoahQueueBuffer* buf = _free_list;
       
   179     _free_list = _free_list->next();
       
   180     _num_free_buffer --;
       
   181     buf->reset();
       
   182     return buf;
       
   183   } else {
       
   184     assert(_num_free_buffer == 0, "Sanity");
       
   185     _total_buffers ++;
       
   186     return new ShenandoahQueueBuffer;
       
   187   }
       
   188 }
       
   189 
       
   190 void ShenandoahStrDedupQueue::release_buffers(ShenandoahQueueBuffer* list) {
       
   191   assert_lock_strong(StringDedupQueue_lock);
       
   192   while (list != NULL) {
       
   193     ShenandoahQueueBuffer* tmp = list;
       
   194     list = list->next();
       
   195     if (_num_free_buffer < _max_free_buffer) {
       
   196       tmp->set_next(_free_list);
       
   197       _free_list = tmp;
       
   198       _num_free_buffer ++;
       
   199     } else {
       
   200       _total_buffers --;
       
   201       delete tmp;
       
   202     }
       
   203   }
       
   204 }
       
   205 
       
   206 void ShenandoahStrDedupQueue::print_statistics_impl() {
       
   207   Log(gc, stringdedup) log;
       
   208   log.debug("  Queue:");
       
   209   log.debug("    Total buffers: " SIZE_FORMAT " (" SIZE_FORMAT " K). " SIZE_FORMAT " buffers are on free list",
       
   210     _total_buffers, (_total_buffers * sizeof(ShenandoahQueueBuffer) / K), _num_free_buffer);
       
   211 }
       
   212 
       
   213 class VerifyQueueClosure : public OopClosure {
       
   214 private:
       
   215   ShenandoahHeap* _heap;
       
   216 public:
       
   217   VerifyQueueClosure();
       
   218 
       
   219   void do_oop(oop* o);
       
   220   void do_oop(narrowOop* o) {
       
   221     ShouldNotCallThis();
       
   222   }
       
   223 };
       
   224 
       
   225 VerifyQueueClosure::VerifyQueueClosure() :
       
   226   _heap(ShenandoahHeap::heap()) {
       
   227 }
       
   228 
       
   229 void VerifyQueueClosure::do_oop(oop* o) {
       
   230   if (*o != NULL) {
       
   231     oop obj = *o;
       
   232     shenandoah_assert_correct(o, obj);
       
   233     assert(java_lang_String::is_instance(obj), "Object must be a String");
       
   234   }
       
   235 }
       
   236 
       
   237 void ShenandoahStrDedupQueue::verify_impl() {
       
   238   VerifyQueueClosure vcl;
       
   239   for (size_t index = 0; index < num_queues(); index ++) {
       
   240     ShenandoahQueueBuffer* buf = queue_at(index);
       
   241     while (buf != NULL) {
       
   242       buf->oops_do(&vcl);
       
   243       buf = buf->next();
       
   244     }
       
   245   }
       
   246 }