1 /*
   2  * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
   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 #include "gc/shared/gcTraceTime.inline.hpp"
  26 #include "gc/shared/workgroup.hpp"
  27 #include "gc/shared/taskqueue.inline.hpp"
  28 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
  29 #include "gc/shenandoah/shenandoahCollectionSet.hpp"
  30 #include "gc/shenandoah/shenandoahConnectionMatrix.inline.hpp"
  31 #include "gc/shenandoah/shenandoahFreeSet.hpp"
  32 #include "gc/shenandoah/shenandoahHeapRegionSet.hpp"
  33 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  34 #include "gc/shenandoah/shenandoahPartialGC.hpp"
  35 #include "gc/shenandoah/shenandoahRootProcessor.hpp"
  36 #include "gc/shenandoah/shenandoahTaskqueue.hpp"
  37 #include "memory/iterator.hpp"
  38 
  39 class PartialEvacuateUpdateRootsClosure : public OopClosure {
  40   ShenandoahPartialGC* _partial_gc;
  41   Thread* _thread;
  42   SCMObjToScanQueue* _queue;
  43 private:
  44   template <class T>
  45   void do_oop_work(T* p) { _partial_gc->process_oop<T, false>(p, _thread, _queue); }
  46 public:
  47   PartialEvacuateUpdateRootsClosure(SCMObjToScanQueue* q) :
  48     _partial_gc(ShenandoahHeap::heap()->partial_gc()),
  49     _thread(Thread::current()), _queue(q) {}
  50   void do_oop(oop* p) {
  51     assert(! ShenandoahHeap::heap()->is_in_reserved(p), "sanity");
  52     do_oop_work(p);
  53   }
  54   void do_oop(narrowOop* p) { do_oop_work(p); }
  55 };
  56 
  57 class PartialEvacuateUpdateHeapClosure : public ExtendedOopClosure {
  58   ShenandoahPartialGC* _partial_gc;
  59   Thread* _thread;
  60   SCMObjToScanQueue* _queue;
  61 private:
  62   template <class T>
  63   void do_oop_work(T* p) {
  64     _partial_gc->process_oop<T, true>(p, _thread, _queue);
  65   }
  66 public:
  67   PartialEvacuateUpdateHeapClosure(SCMObjToScanQueue* q) :
  68     _partial_gc(ShenandoahHeap::heap()->partial_gc()),
  69     _thread(Thread::current()), _queue(q) {}
  70   void do_oop(oop* p) { do_oop_work(p); }
  71   void do_oop(narrowOop* p) { do_oop_work(p); }
  72 };
  73 
  74 class ShenandoahPartialCollectionTask : public AbstractGangTask {
  75 private:
  76   ShenandoahRootProcessor* _rp;
  77   ParallelTaskTerminator* _terminator;
  78   ShenandoahHeapRegionSet* _root_regions;
  79   ShenandoahHeap* _heap;
  80 public:
  81   ShenandoahPartialCollectionTask(ShenandoahRootProcessor* rp,
  82                                   ParallelTaskTerminator* terminator,
  83                                   ShenandoahHeapRegionSet* root_regions) :
  84     AbstractGangTask("Shenandoah Partial Collection"),
  85     _rp(rp), _terminator(terminator), _root_regions(root_regions),
  86     _heap(ShenandoahHeap::heap()) {}
  87 
  88   void work(uint worker_id) {
  89     ShenandoahConnectionMatrix* matrix = _heap->connection_matrix();
  90     SCMObjToScanQueueSet* queues = _heap->partial_gc()->task_queues();
  91     SCMObjToScanQueue* q = queues->queue(worker_id);
  92 
  93     // Step 1: Process ordinary GC roots.
  94     {
  95       PartialEvacuateUpdateRootsClosure roots_cl(q);
  96       CLDToOopClosure cld_cl(&roots_cl);
  97       MarkingCodeBlobClosure code_cl(&roots_cl, CodeBlobToOopClosure::FixRelocations);
  98       _rp->process_all_roots(&roots_cl, &roots_cl, &cld_cl, &code_cl, worker_id);
  99     }
 100     if (check_and_handle_cancelled_gc()) return;
 101 
 102     PartialEvacuateUpdateHeapClosure cl(q);
 103 
 104     // Step 2: Process all root regions.
 105     {
 106       ShenandoahHeapRegion* r = _root_regions->claim_next();
 107       while (r != NULL) {
 108         assert(r->is_root(), "must be root region");
 109         if (! r->is_humongous_continuation()) {
 110           _heap->marked_object_oop_iterate(r, &cl);
 111         }
 112         r->set_root(false);
 113         if (check_and_handle_cancelled_gc()) return;
 114         r = _root_regions->claim_next();
 115       }
 116     }
 117     if (check_and_handle_cancelled_gc()) return;
 118 
 119     // Step 3: Drain all outstanding work in queues.
 120     {
 121       int seed = 17;
 122       SCMTask task;
 123 
 124       uint stride = ShenandoahMarkLoopStride;
 125 
 126       while (true) {
 127         if (check_and_handle_cancelled_gc()) return;
 128 
 129         for (uint i = 0; i < stride; i++) {
 130           if ((q->pop_buffer(task) ||
 131                q->pop_local(task) ||
 132                q->pop_overflow(task) ||
 133                queues->steal(worker_id, &seed, task))) {
 134             oop obj = task.obj();
 135             assert(!oopDesc::is_null(obj), "must not be null");
 136             obj->oop_iterate(&cl);
 137           } else {
 138             if (_terminator->offer_termination()) return;
 139           }
 140         }
 141       }
 142     }
 143   }
 144 
 145 private:
 146   bool check_and_handle_cancelled_gc() {
 147     if (_heap->cancelled_concgc()) {
 148       ShenandoahCancelledTerminatorTerminator tt;
 149       while (! _terminator->offer_termination(&tt));
 150       return true;
 151     }
 152     return false;
 153   }
 154 };
 155 
 156 ShenandoahPartialGC::ShenandoahPartialGC(ShenandoahHeap* heap, size_t max_regions) :
 157   _heap(heap),
 158   _matrix(heap->connection_matrix()),
 159   _root_regions(new ShenandoahHeapRegionSet(max_regions)),
 160   _task_queues(new SCMObjToScanQueueSet(heap->max_workers())) {
 161 
 162   assert(_matrix != NULL, "need matrix");
 163 
 164   uint num_queues = heap->max_workers();
 165   for (uint i = 0; i < num_queues; ++i) {
 166     SCMObjToScanQueue* task_queue = new SCMObjToScanQueue();
 167     task_queue->initialize();
 168     _task_queues->register_queue(i, task_queue);
 169   }
 170 
 171 }
 172 
 173 void ShenandoahPartialGC::prepare() {
 174 
 175   if (ShenandoahVerify || VerifyShenandoahMatrix) {
 176     log_debug(gc, ergo)("Verifying before partial collection");
 177     _heap->verify_heap_reachable_at_safepoint();
 178     log_debug(gc, ergo)("Verification passed");
 179   }
 180 
 181   _heap->collection_set()->clear();
 182   assert(_heap->collection_set()->count() == 0, "collection set not clear");
 183 
 184   _heap->ensure_parsability(true);
 185 
 186   ShenandoahConnectionMatrix* matrix = _heap->connection_matrix();
 187   ShenandoahHeapRegionSet* regions = _heap->regions();
 188   ShenandoahCollectionSet* collection_set = _heap->collection_set();
 189   ShenandoahFreeSet* free_set = _heap->free_regions();
 190   free_set->clear();
 191   _root_regions->clear();
 192   assert(_root_regions->count() == 0, "must be cleared");
 193   size_t num_regions = _heap->num_regions();
 194 
 195   // First pass: find collection set.
 196   for (uint to_idx = 0; to_idx < num_regions; to_idx++) {
 197     ShenandoahHeapRegion* region = regions->get(to_idx);
 198     region->set_root(false);
 199     guarantee(! region->is_root(), "must not be root here");
 200     if (region->is_humongous() || region->is_empty() || region->is_pinned()) continue;
 201     assert(! _heap->region_in_collection_set(to_idx), "must not be in cset yet");
 202     uint num_incoming = 0;
 203     for (uint from_idx = 0; from_idx < num_regions; from_idx++) {
 204       if (matrix->is_connected(from_idx, to_idx)) {
 205         num_incoming++;
 206       }
 207     }
 208     if (num_incoming < ShenandoahPartialInboundThreshold) {
 209       collection_set->add_region(region);
 210       _heap->set_region_in_collection_set(to_idx, true);
 211     }
 212   }
 213 
 214   if (UseShenandoahMatrix && PrintShenandoahMatrix) {
 215     outputStream* log = Log(gc)::info_stream();
 216     matrix->print_on(log);
 217   }
 218 
 219   // Second pass: find all root regions.
 220   size_t num_cset = collection_set->count();
 221   for (uint idx = 0; idx < num_cset; idx++) {
 222     ShenandoahHeapRegion* region = collection_set->get(idx);
 223     size_t to_idx = region->region_number();
 224     assert(! region->is_humongous() && ! region->is_empty() && ! region->is_pinned(), "sanity");
 225     assert(_heap->region_in_collection_set(to_idx), "more sanity");
 226     for (uint from_idx = 0; from_idx < num_regions; from_idx++) {
 227       if (matrix->is_connected(from_idx, to_idx)) {
 228         ShenandoahHeapRegion* r = regions->get(from_idx);
 229         if (! r->is_root() && ! _heap->region_in_collection_set(from_idx)) {
 230           _root_regions->add_region(r);
 231           r->set_root(true);
 232         }
 233       }
 234     }
 235   }
 236   // Final pass: free regions.
 237   for (uint to_idx = 0; to_idx < num_regions; to_idx++) {
 238     ShenandoahHeapRegion* region = regions->get(to_idx);
 239     if (! region->is_humongous() &&
 240         ! region->is_pinned() &&
 241         ! region->is_root() &&
 242         ! _heap->in_collection_set(region)) {
 243 
 244       free_set->add_region(region);
 245     }
 246     if (region->is_root()) {
 247       // We rebuild the outbound matrix for all roots, thus we can clear them before.
 248       // This makes the matrix more precise.
 249       matrix->clear_region_outbound(region->region_number());
 250     }
 251   }
 252   log_debug(gc, ergo)("got "SIZE_FORMAT" cset regions", collection_set->count());
 253   log_debug(gc, ergo)("got "SIZE_FORMAT" root regions", _root_regions->count());
 254 }
 255 
 256 void ShenandoahPartialGC::do_partial_collection() {
 257 
 258   _heap->gc_timer()->register_gc_start();
 259   ShenandoahCollectorPolicy* policy = _heap->shenandoahPolicy();
 260   policy->record_phase_start(ShenandoahCollectorPolicy::partial_gc);
 261 
 262   {
 263     GCTraceTime(Info, gc) time("Pause Partial", _heap->gc_timer(), GCCause::_no_gc, true);
 264 
 265     assert(_task_queues->is_empty(), "queues must be empty after partial GC");
 266 
 267     COMPILER2_PRESENT(DerivedPointerTable::clear());
 268 
 269     {
 270       ClassLoaderDataGraph::clear_claimed_marks();
 271       uint nworkers = _heap->workers()->active_workers();
 272       ShenandoahRootProcessor rp(_heap, nworkers);
 273 
 274       if (UseShenandoahOWST) {
 275         ShenandoahTaskTerminator terminator(nworkers, task_queues());
 276         ShenandoahPartialCollectionTask partial_task(&rp, &terminator, _root_regions);
 277         _heap->workers()->run_task(&partial_task);
 278       } else {
 279         ParallelTaskTerminator terminator(nworkers, task_queues());
 280         ShenandoahPartialCollectionTask partial_task(&rp, &terminator, _root_regions);
 281         _heap->workers()->run_task(&partial_task);
 282       }
 283     }
 284 
 285     COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
 286 
 287     if (_heap->cancelled_concgc()) {
 288       _task_queues->clear();
 289     }
 290     assert(_task_queues->is_empty(), "queues must be empty after partial GC");
 291 
 292     if (! _heap->cancelled_concgc()) {
 293       if (ShenandoahVerify || VerifyShenandoahMatrix) {
 294         log_debug(gc, ergo)("Verifying after partial collection");
 295         _heap->verify_heap_reachable_at_safepoint();
 296         log_debug(gc, ergo)("Verification passed");
 297       }
 298 
 299       ShenandoahHeap::ShenandoahHeapLock heap_lock(_heap);
 300       size_t num_cset = _heap->collection_set()->count();
 301       for (size_t i = 0; i < num_cset; i++) {
 302         ShenandoahHeapRegion* r = _heap->collection_set()->get(i);
 303         _heap->decrease_used(r->used());
 304         HeapWord* bottom = r->bottom();
 305         HeapWord* top = _heap->complete_top_at_mark_start(r->bottom());
 306         if (top > bottom) {
 307           _heap->complete_mark_bit_map()->clear_range_large(MemRegion(bottom, top));
 308         }
 309         r->recycle();
 310         _heap->free_regions()->add_region(r);
 311       }
 312 
 313       reset();
 314     }
 315   }
 316 
 317   policy->record_phase_end(ShenandoahCollectorPolicy::partial_gc);
 318   _heap->gc_timer()->register_gc_end();
 319 }
 320 
 321 void ShenandoahPartialGC::reset() {
 322   _heap->collection_set()->clear();
 323   _heap->clear_cset_fast_test();
 324   _root_regions->clear();
 325 }
 326 
 327 template <class T, bool UPDATE_MATRIX>
 328 void ShenandoahPartialGC::process_oop(T* p, Thread* thread, SCMObjToScanQueue* queue) {
 329   T o = oopDesc::load_heap_oop(p);
 330   if (! oopDesc::is_null(o)) {
 331     oop obj = oopDesc::decode_heap_oop_not_null(o);
 332     if (_heap->in_collection_set(obj)) {
 333       oop forw = ShenandoahBarrierSet::resolve_oop_static_not_null(obj);
 334       if (oopDesc::unsafe_equals(obj, forw)) {
 335         bool evacuated = false;
 336         forw = _heap->evacuate_object(obj, thread, evacuated);
 337 
 338         // Only the thread that succeeded evacuating this object pushes it to its work queue.
 339         if (evacuated) {
 340           assert(forw->is_oop(), "sanity");
 341           bool succeeded = queue->push(SCMTask(forw));
 342           assert(succeeded, "must succeed to push to task queue");
 343         }
 344       }
 345       assert(! oopDesc::unsafe_equals(obj, forw) || _heap->cancelled_concgc(), "must be evacuated");
 346       // Update reference.
 347       oopDesc::encode_store_heap_oop_not_null(p, forw);
 348       obj = forw; // For matrix update below.
 349     }
 350     if (UPDATE_MATRIX) {
 351 #ifdef ASSERT
 352       oop forw = ShenandoahBarrierSet::resolve_oop_static_not_null(obj);
 353       assert(oopDesc::unsafe_equals(obj, forw) || _heap->cancelled_concgc(), "must not be evacuated: "PTR_FORMAT" -> "PTR_FORMAT, p2i(obj), p2i(forw));
 354 #endif
 355       _matrix->set_connected(p, obj);
 356     }
 357   }
 358 }
 359 
 360 SCMObjToScanQueueSet* ShenandoahPartialGC::task_queues() {
 361   return _task_queues;
 362 }