< prev index next >

src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp

Print this page

   1 /*
   2  * Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved.
   3  * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.

   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #include "precompiled.hpp"
  27 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
  28 #include "gc/shenandoah/shenandoahConcurrentGC.hpp"
  29 #include "gc/shenandoah/shenandoahControlThread.hpp"
  30 #include "gc/shenandoah/shenandoahDegeneratedGC.hpp"

  31 #include "gc/shenandoah/shenandoahFreeSet.hpp"
  32 #include "gc/shenandoah/shenandoahFullGC.hpp"




  33 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
  34 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  35 #include "gc/shenandoah/shenandoahMark.inline.hpp"
  36 #include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
  37 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"

  38 #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
  39 #include "gc/shenandoah/shenandoahUtils.hpp"
  40 #include "gc/shenandoah/shenandoahVMOperations.hpp"
  41 #include "gc/shenandoah/shenandoahWorkerPolicy.hpp"
  42 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"

  43 #include "memory/iterator.hpp"
  44 #include "memory/metaspaceUtils.hpp"
  45 #include "memory/metaspaceStats.hpp"
  46 #include "memory/universe.hpp"
  47 #include "runtime/atomic.hpp"
  48 
  49 ShenandoahControlThread::ShenandoahControlThread() :
  50   ConcurrentGCThread(),
  51   _alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true),
  52   _gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true),


  53   _periodic_task(this),
  54   _requested_gc_cause(GCCause::_no_cause_specified),

  55   _degen_point(ShenandoahGC::_degenerated_outside_cycle),
  56   _allocs_seen(0) {


  57   set_name("Shenandoah Control Thread");
  58   reset_gc_id();
  59   create_and_start();
  60   _periodic_task.enroll();
  61   if (ShenandoahPacing) {
  62     _periodic_pacer_notify_task.enroll();
  63   }
  64 }
  65 
  66 ShenandoahControlThread::~ShenandoahControlThread() {
  67   // This is here so that super is called.
  68 }
  69 
  70 void ShenandoahPeriodicTask::task() {
  71   _thread->handle_force_counters_update();
  72   _thread->handle_counters_update();
  73 }
  74 
  75 void ShenandoahPeriodicPacerNotify::task() {
  76   assert(ShenandoahPacing, "Should not be here otherwise");
  77   ShenandoahHeap::heap()->pacer()->notify_waiters();
  78 }
  79 
  80 void ShenandoahControlThread::run_service() {
  81   ShenandoahHeap* heap = ShenandoahHeap::heap();
  82 
  83   GCMode default_mode = concurrent_normal;

  84   GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc;
  85   int sleep = ShenandoahControlIntervalMin;
  86 
  87   double last_shrink_time = os::elapsedTime();
  88   double last_sleep_adjust_time = os::elapsedTime();
  89 
  90   // Shrink period avoids constantly polling regions for shrinking.
  91   // Having a period 10x lower than the delay would mean we hit the
  92   // shrinking with lag of less than 1/10-th of true delay.
  93   // ShenandoahUncommitDelay is in msecs, but shrink_period is in seconds.
  94   double shrink_period = (double)ShenandoahUncommitDelay / 1000 / 10;
  95 
  96   ShenandoahCollectorPolicy* policy = heap->shenandoah_policy();
  97   ShenandoahHeuristics* heuristics = heap->heuristics();






  98   while (!in_graceful_shutdown() && !should_terminate()) {
  99     // Figure out if we have pending requests.
 100     bool alloc_failure_pending = _alloc_failure_gc.is_set();
 101     bool is_gc_requested = _gc_requested.is_set();
 102     GCCause::Cause requested_gc_cause = _requested_gc_cause;
 103     bool explicit_gc_requested = is_gc_requested && is_explicit_gc(requested_gc_cause);
 104     bool implicit_gc_requested = is_gc_requested && !is_explicit_gc(requested_gc_cause);
 105 
 106     // This control loop iteration have seen this much allocations.
 107     size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed);
 108 
 109     // Check if we have seen a new target for soft max heap size.
 110     bool soft_max_changed = check_soft_max_changed();
 111 
 112     // Choose which GC mode to run in. The block below should select a single mode.
 113     GCMode mode = none;
 114     GCCause::Cause cause = GCCause::_last_gc_cause;
 115     ShenandoahGC::ShenandoahDegenPoint degen_point = ShenandoahGC::_degenerated_unset;
 116 
 117     if (alloc_failure_pending) {
 118       // Allocation failure takes precedence: we have to deal with it first thing
 119       log_info(gc)("Trigger: Handle Allocation Failure");
 120 
 121       cause = GCCause::_allocation_failure;
 122 
 123       // Consume the degen point, and seed it with default value
 124       degen_point = _degen_point;
 125       _degen_point = ShenandoahGC::_degenerated_outside_cycle;
 126 
 127       if (ShenandoahDegeneratedGC && heuristics->should_degenerate_cycle()) {












 128         heuristics->record_allocation_failure_gc();
 129         policy->record_alloc_failure_to_degenerated(degen_point);
 130         mode = stw_degenerated;
 131       } else {
 132         heuristics->record_allocation_failure_gc();
 133         policy->record_alloc_failure_to_full();
 134         mode = stw_full;

 135       }
 136 
 137     } else if (explicit_gc_requested) {
 138       cause = requested_gc_cause;

 139       log_info(gc)("Trigger: Explicit GC request (%s)", GCCause::to_string(cause));
 140 
 141       heuristics->record_requested_gc();
 142 
 143       if (ExplicitGCInvokesConcurrent) {
 144         policy->record_explicit_to_concurrent();
 145         mode = default_mode;
 146         // Unload and clean up everything
 147         heap->set_unload_classes(heuristics->can_unload_classes());
 148       } else {
 149         policy->record_explicit_to_full();
 150         mode = stw_full;
 151       }
 152     } else if (implicit_gc_requested) {
 153       cause = requested_gc_cause;

 154       log_info(gc)("Trigger: Implicit GC request (%s)", GCCause::to_string(cause));
 155 
 156       heuristics->record_requested_gc();
 157 
 158       if (ShenandoahImplicitGCInvokesConcurrent) {
 159         policy->record_implicit_to_concurrent();
 160         mode = default_mode;
 161 
 162         // Unload and clean up everything
 163         heap->set_unload_classes(heuristics->can_unload_classes());
 164       } else {
 165         policy->record_implicit_to_full();
 166         mode = stw_full;
 167       }
 168     } else {
 169       // Potential normal cycle: ask heuristics if it wants to act
 170       if (heuristics->should_start_gc()) {
 171         mode = default_mode;
 172         cause = default_cause;
 173       }

























 174 
 175       // Ask policy if this cycle wants to process references or unload classes
 176       heap->set_unload_classes(heuristics->should_unload_classes());




















 177     }
 178 
 179     // Blow all soft references on this cycle, if handling allocation failure,
 180     // either implicit or explicit GC request,  or we are requested to do so unconditionally.
 181     if (alloc_failure_pending || implicit_gc_requested || explicit_gc_requested || ShenandoahAlwaysClearSoftRefs) {
 182       heap->soft_ref_policy()->set_should_clear_all_soft_refs(true);
 183     }
 184 
 185     bool gc_requested = (mode != none);
 186     assert (!gc_requested || cause != GCCause::_last_gc_cause, "GC cause should be set");
 187 
 188     if (gc_requested) {
 189       // GC is starting, bump the internal ID
 190       update_gc_id();
 191 
 192       heap->reset_bytes_allocated_since_gc_start();
 193 
 194       MetaspaceCombinedStats meta_sizes = MetaspaceUtils::get_combined_statistics();
 195 
 196       // If GC was requested, we are sampling the counters even without actual triggers
 197       // from allocation machinery. This captures GC phases more accurately.
 198       set_forced_counters_update(true);
 199 
 200       // If GC was requested, we better dump freeset data for performance debugging
 201       {
 202         ShenandoahHeapLocker locker(heap->lock());
 203         heap->free_set()->log_status();
 204       }
 205 
 206       switch (mode) {
 207         case concurrent_normal:
 208           service_concurrent_normal_cycle(cause);












 209           break;
 210         case stw_degenerated:
 211           service_stw_degenerated_cycle(cause, degen_point);





 212           break;
 213         case stw_full:





 214           service_stw_full_cycle(cause);
 215           break;







 216         default:
 217           ShouldNotReachHere();
 218       }
 219 
 220       // If this was the requested GC cycle, notify waiters about it
 221       if (explicit_gc_requested || implicit_gc_requested) {
 222         notify_gc_waiters();
 223       }
 224 
 225       // If this was the allocation failure GC cycle, notify waiters about it
 226       if (alloc_failure_pending) {
 227         notify_alloc_failure_waiters();
 228       }
 229 
 230       // Report current free set state at the end of cycle, whether
 231       // it is a normal completion, or the abort.
 232       {
 233         ShenandoahHeapLocker locker(heap->lock());
 234         heap->free_set()->log_status();
 235 
 236         // Notify Universe about new heap usage. This has implications for
 237         // global soft refs policy, and we better report it every time heap
 238         // usage goes down.
 239         Universe::heap()->update_capacity_and_used_at_gc();
 240 
 241         // Signal that we have completed a visit to all live objects.
 242         Universe::heap()->record_whole_heap_examined_timestamp();
 243       }
 244 
 245       // Disable forced counters update, and update counters one more time
 246       // to capture the state at the end of GC session.
 247       handle_force_counters_update();
 248       set_forced_counters_update(false);
 249 
 250       // Retract forceful part of soft refs policy
 251       heap->soft_ref_policy()->set_should_clear_all_soft_refs(false);
 252 
 253       // Clear metaspace oom flag, if current cycle unloaded classes
 254       if (heap->unload_classes()) {
 255         heuristics->clear_metaspace_oom();
 256       }
 257 
 258       // Commit worker statistics to cycle data
 259       heap->phase_timings()->flush_par_workers_to_cycle();
 260       if (ShenandoahPacing) {
 261         heap->pacer()->flush_stats_to_cycle();
 262       }
 263 
 264       // Print GC stats for current cycle
 265       {
 266         LogTarget(Info, gc, stats) lt;
 267         if (lt.is_enabled()) {
 268           ResourceMark rm;
 269           LogStream ls(lt);
 270           heap->phase_timings()->print_cycle_on(&ls);
 271           if (ShenandoahPacing) {
 272             heap->pacer()->print_cycle_on(&ls);
 273           }
 274         }
 275       }
 276 
 277       // Commit statistics to globals
 278       heap->phase_timings()->flush_cycle_to_global();
 279 
 280       // Print Metaspace change following GC (if logging is enabled).
 281       MetaspaceUtils::print_metaspace_change(meta_sizes);
 282 
 283       // GC is over, we are at idle now
 284       if (ShenandoahPacing) {
 285         heap->pacer()->setup_for_idle();
 286       }
 287     } else {
 288       // Allow allocators to know we have seen this much regions
 289       if (ShenandoahPacing && (allocs_seen > 0)) {
 290         heap->pacer()->report_alloc(allocs_seen);
 291       }
 292     }
 293 
 294     double current = os::elapsedTime();
 295 
 296     if (ShenandoahUncommit && (explicit_gc_requested || soft_max_changed || (current - last_shrink_time > shrink_period))) {
 297       // Explicit GC tries to uncommit everything down to min capacity.
 298       // Soft max change tries to uncommit everything down to target capacity.
 299       // Periodic uncommit tries to uncommit suitable regions down to min capacity.
 300 
 301       double shrink_before = (explicit_gc_requested || soft_max_changed) ?
 302                              current :
 303                              current - (ShenandoahUncommitDelay / 1000.0);
 304 
 305       size_t shrink_until = soft_max_changed ?
 306                              heap->soft_max_capacity() :
 307                              heap->min_capacity();
 308 
 309       service_uncommit(shrink_before, shrink_until);
 310       heap->phase_timings()->flush_cycle_to_global();
 311       last_shrink_time = current;
 312     }
 313 
 314     // Wait before performing the next action. If allocation happened during this wait,
 315     // we exit sooner, to let heuristics re-evaluate new conditions. If we are at idle,
 316     // back off exponentially.
 317     if (_heap_changed.try_unset()) {
 318       sleep = ShenandoahControlIntervalMin;
 319     } else if ((current - last_sleep_adjust_time) * 1000 > ShenandoahControlIntervalAdjustPeriod){
 320       sleep = MIN2<int>(ShenandoahControlIntervalMax, MAX2(1, sleep * 2));
 321       last_sleep_adjust_time = current;






 322     }
 323     os::naked_short_sleep(sleep);
 324   }
 325 
 326   // Wait for the actual stop(), can't leave run_service() earlier.
 327   while (!should_terminate()) {
 328     os::naked_short_sleep(ShenandoahControlIntervalMin);
 329   }
 330 }
 331 
































































































































































































































 332 bool ShenandoahControlThread::check_soft_max_changed() const {
 333   ShenandoahHeap* heap = ShenandoahHeap::heap();
 334   size_t new_soft_max = Atomic::load(&SoftMaxHeapSize);
 335   size_t old_soft_max = heap->soft_max_capacity();
 336   if (new_soft_max != old_soft_max) {
 337     new_soft_max = MAX2(heap->min_capacity(), new_soft_max);
 338     new_soft_max = MIN2(heap->max_capacity(), new_soft_max);
 339     if (new_soft_max != old_soft_max) {
 340       log_info(gc)("Soft Max Heap Size: " SIZE_FORMAT "%s -> " SIZE_FORMAT "%s",
 341                    byte_size_in_proper_unit(old_soft_max), proper_unit_for_byte_size(old_soft_max),
 342                    byte_size_in_proper_unit(new_soft_max), proper_unit_for_byte_size(new_soft_max)
 343       );
 344       heap->set_soft_max_capacity(new_soft_max);
 345       return true;
 346     }
 347   }
 348   return false;
 349 }
 350 
 351 void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) {
 352   // Normal cycle goes via all concurrent phases. If allocation failure (af) happens during
 353   // any of the concurrent phases, it first degrades to Degenerated GC and completes GC there.
 354   // If second allocation failure happens during Degenerated GC cycle (for example, when GC
 355   // tries to evac something and no memory is available), cycle degrades to Full GC.
 356   //
 357   // There are also a shortcut through the normal cycle: immediate garbage shortcut, when
 358   // heuristics says there are no regions to compact, and all the collection comes from immediately
 359   // reclaimable regions.
 360   //
 361   // ................................................................................................
 362   //
 363   //                                    (immediate garbage shortcut)                Concurrent GC
 364   //                             /-------------------------------------------\
 365   //                             |                                           |
 366   //                             |                                           |
 367   //                             |                                           |
 368   //                             |                                           v
 369   // [START] ----> Conc Mark ----o----> Conc Evac --o--> Conc Update-Refs ---o----> [END]
 370   //                   |                    |                 |              ^
 371   //                   | (af)               | (af)            | (af)         |
 372   // ..................|....................|.................|..............|.......................
 373   //                   |                    |                 |              |
 374   //                   |                    |                 |              |      Degenerated GC
 375   //                   v                    v                 v              |
 376   //               STW Mark ----------> STW Evac ----> STW Update-Refs ----->o
 377   //                   |                    |                 |              ^
 378   //                   | (af)               | (af)            | (af)         |
 379   // ..................|....................|.................|..............|.......................
 380   //                   |                    |                 |              |
 381   //                   |                    v                 |              |      Full GC
 382   //                   \------------------->o<----------------/              |
 383   //                                        |                                |
 384   //                                        v                                |
 385   //                                      Full GC  --------------------------/
 386   //
 387   ShenandoahHeap* heap = ShenandoahHeap::heap();
 388   if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return;
 389 
 390   GCIdMark gc_id_mark;
 391   ShenandoahGCSession session(cause);
 392 
 393   TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
 394 
 395   ShenandoahConcurrentGC gc;







 396   if (gc.collect(cause)) {
 397     // Cycle is complete
 398     heap->heuristics()->record_success_concurrent();
 399     heap->shenandoah_policy()->record_success_concurrent();
 400   } else {
 401     assert(heap->cancelled_gc(), "Must have been cancelled");
 402     check_cancellation_or_degen(gc.degen_point());




 403   }


























 404 }
 405 
 406 bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) {
 407   ShenandoahHeap* heap = ShenandoahHeap::heap();
 408   if (heap->cancelled_gc()) {
 409     assert (is_alloc_failure_gc() || in_graceful_shutdown(), "Cancel GC either for alloc failure GC, or gracefully exiting");
 410     if (!in_graceful_shutdown()) {
 411       assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle,
 412               "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point));
 413       _degen_point = point;
 414     }
 415     return true;
 416   }
























 417   return false;
 418 }
 419 
 420 void ShenandoahControlThread::stop_service() {
 421   // Nothing to do here.
 422 }
 423 
 424 void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) {


 425   GCIdMark gc_id_mark;
 426   ShenandoahGCSession session(cause);
 427 
 428   ShenandoahFullGC gc;
 429   gc.collect(cause);
 430 
 431   ShenandoahHeap* const heap = ShenandoahHeap::heap();
 432   heap->heuristics()->record_success_full();
 433   heap->shenandoah_policy()->record_success_full();
 434 }
 435 
 436 void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point) {
 437   assert (point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set");


 438 
 439   GCIdMark gc_id_mark;
 440   ShenandoahGCSession session(cause);
 441 
 442   ShenandoahDegenGC gc(point);
 443   gc.collect(cause);
 444 
 445   ShenandoahHeap* const heap = ShenandoahHeap::heap();
 446   heap->heuristics()->record_success_degenerated();











 447   heap->shenandoah_policy()->record_success_degenerated();

 448 }
 449 
 450 void ShenandoahControlThread::service_uncommit(double shrink_before, size_t shrink_until) {
 451   ShenandoahHeap* heap = ShenandoahHeap::heap();
 452 
 453   // Determine if there is work to do. This avoids taking heap lock if there is
 454   // no work available, avoids spamming logs with superfluous logging messages,
 455   // and minimises the amount of work while locks are taken.
 456 
 457   if (heap->committed() <= shrink_until) return;
 458 
 459   bool has_work = false;
 460   for (size_t i = 0; i < heap->num_regions(); i++) {
 461     ShenandoahHeapRegion *r = heap->get_region(i);
 462     if (r->is_empty_committed() && (r->empty_time() < shrink_before)) {
 463       has_work = true;
 464       break;
 465     }
 466   }
 467 
 468   if (has_work) {
 469     heap->entry_uncommit(shrink_before, shrink_until);
 470   }
 471 }
 472 
 473 bool ShenandoahControlThread::is_explicit_gc(GCCause::Cause cause) const {
 474   return GCCause::is_user_requested_gc(cause) ||
 475          GCCause::is_serviceability_requested_gc(cause);
 476 }
 477 





 478 void ShenandoahControlThread::request_gc(GCCause::Cause cause) {
 479   assert(GCCause::is_user_requested_gc(cause) ||
 480          GCCause::is_serviceability_requested_gc(cause) ||
 481          cause == GCCause::_metadata_GC_clear_soft_refs ||
 482          cause == GCCause::_codecache_GC_aggressive ||
 483          cause == GCCause::_codecache_GC_threshold ||
 484          cause == GCCause::_full_gc_alot ||
 485          cause == GCCause::_wb_young_gc ||
 486          cause == GCCause::_wb_full_gc ||
 487          cause == GCCause::_wb_breakpoint ||
 488          cause == GCCause::_scavenge_alot,
 489          "only requested GCs here: %s", GCCause::to_string(cause));
 490 
 491   if (is_explicit_gc(cause)) {
 492     if (!DisableExplicitGC) {
 493       handle_requested_gc(cause);
 494     }
 495   } else {
 496     handle_requested_gc(cause);
 497   }
 498 }
 499 








































 500 void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) {
 501   // Make sure we have at least one complete GC cycle before unblocking
 502   // from the explicit GC request.
 503   //
 504   // This is especially important for weak references cleanup and/or native
 505   // resources (e.g. DirectByteBuffers) machinery: when explicit GC request
 506   // comes very late in the already running cycle, it would miss lots of new
 507   // opportunities for cleanup that were made available before the caller
 508   // requested the GC.
 509 
 510   MonitorLocker ml(&_gc_waiters_lock);
 511   size_t current_gc_id = get_gc_id();
 512   size_t required_gc_id = current_gc_id + 1;
 513   while (current_gc_id < required_gc_id) {
 514     // Although setting gc request is under _gc_waiters_lock, but read side (run_service())
 515     // does not take the lock. We need to enforce following order, so that read side sees
 516     // latest requested gc cause when the flag is set.
 517     _requested_gc_cause = cause;
 518     _gc_requested.set();
 519 
 520     if (cause != GCCause::_wb_breakpoint) {
 521       ml.wait();
 522     }
 523     current_gc_id = get_gc_id();
 524   }
 525 }
 526 
 527 void ShenandoahControlThread::handle_alloc_failure(ShenandoahAllocRequest& req) {
 528   ShenandoahHeap* heap = ShenandoahHeap::heap();
 529 
 530   assert(current()->is_Java_thread(), "expect Java thread here");
 531 
 532   if (try_set_alloc_failure_gc()) {
 533     // Only report the first allocation failure
 534     log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s",
 535                  req.type_string(),
 536                  byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize));
 537 
 538     // Now that alloc failure GC is scheduled, we can abort everything else
 539     heap->cancel_gc(GCCause::_allocation_failure);
 540   }
 541 
 542   MonitorLocker ml(&_alloc_failure_waiters_lock);
 543   while (is_alloc_failure_gc()) {
 544     ml.wait();
 545   }
 546 }
 547 
 548 void ShenandoahControlThread::handle_alloc_failure_evac(size_t words) {
 549   ShenandoahHeap* heap = ShenandoahHeap::heap();
 550 
 551   if (try_set_alloc_failure_gc()) {
 552     // Only report the first allocation failure
 553     log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation",
 554                  byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize));
 555   }
 556 
 557   // Forcefully report allocation failure

 583     _do_counters_update.unset();
 584     ShenandoahHeap::heap()->monitoring_support()->update_counters();
 585   }
 586 }
 587 
 588 void ShenandoahControlThread::handle_force_counters_update() {
 589   if (_force_counters_update.is_set()) {
 590     _do_counters_update.unset(); // reset these too, we do update now!
 591     ShenandoahHeap::heap()->monitoring_support()->update_counters();
 592   }
 593 }
 594 
 595 void ShenandoahControlThread::notify_heap_changed() {
 596   // This is called from allocation path, and thus should be fast.
 597 
 598   // Update monitoring counters when we took a new region. This amortizes the
 599   // update costs on slow path.
 600   if (_do_counters_update.is_unset()) {
 601     _do_counters_update.set();
 602   }
 603   // Notify that something had changed.
 604   if (_heap_changed.is_unset()) {
 605     _heap_changed.set();
 606   }
 607 }
 608 
 609 void ShenandoahControlThread::pacing_notify_alloc(size_t words) {
 610   assert(ShenandoahPacing, "should only call when pacing is enabled");
 611   Atomic::add(&_allocs_seen, words, memory_order_relaxed);
 612 }
 613 
 614 void ShenandoahControlThread::set_forced_counters_update(bool value) {
 615   _force_counters_update.set_cond(value);
 616 }
 617 
 618 void ShenandoahControlThread::reset_gc_id() {
 619   Atomic::store(&_gc_id, (size_t)0);
 620 }
 621 
 622 void ShenandoahControlThread::update_gc_id() {
 623   Atomic::inc(&_gc_id);
 624 }
 625 
 626 size_t ShenandoahControlThread::get_gc_id() {
 627   return Atomic::load(&_gc_id);
 628 }
 629 
 630 void ShenandoahControlThread::start() {
 631   create_and_start();
 632 }
 633 
 634 void ShenandoahControlThread::prepare_for_graceful_shutdown() {
 635   _graceful_shutdown.set();
 636 }
 637 
 638 bool ShenandoahControlThread::in_graceful_shutdown() {
 639   return _graceful_shutdown.is_set();
 640 }






























   1 /*
   2  * Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved.
   3  * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
   4  * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  *
  25  */
  26 
  27 #include "precompiled.hpp"
  28 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
  29 #include "gc/shenandoah/shenandoahConcurrentGC.hpp"
  30 #include "gc/shenandoah/shenandoahControlThread.hpp"
  31 #include "gc/shenandoah/shenandoahDegeneratedGC.hpp"
  32 #include "gc/shenandoah/shenandoahEvacTracker.hpp"
  33 #include "gc/shenandoah/shenandoahFreeSet.hpp"
  34 #include "gc/shenandoah/shenandoahFullGC.hpp"
  35 #include "gc/shenandoah/shenandoahGeneration.hpp"
  36 #include "gc/shenandoah/shenandoahGlobalGeneration.hpp"
  37 #include "gc/shenandoah/shenandoahYoungGeneration.hpp"
  38 #include "gc/shenandoah/shenandoahOldGeneration.hpp"
  39 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
  40 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  41 #include "gc/shenandoah/shenandoahMark.inline.hpp"
  42 #include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
  43 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
  44 #include "gc/shenandoah/shenandoahOldGC.hpp"
  45 #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
  46 #include "gc/shenandoah/shenandoahUtils.hpp"
  47 #include "gc/shenandoah/shenandoahVMOperations.hpp"
  48 #include "gc/shenandoah/shenandoahWorkerPolicy.hpp"
  49 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
  50 #include "gc/shenandoah/mode/shenandoahMode.hpp"
  51 #include "memory/iterator.hpp"
  52 #include "memory/metaspaceUtils.hpp"
  53 #include "memory/metaspaceStats.hpp"
  54 #include "memory/universe.hpp"
  55 #include "runtime/atomic.hpp"
  56 
  57 ShenandoahControlThread::ShenandoahControlThread() :
  58   ConcurrentGCThread(),
  59   _alloc_failure_waiters_lock(Mutex::safepoint - 2, "ShenandoahAllocFailureGC_lock", true),
  60   _gc_waiters_lock(Mutex::safepoint - 2, "ShenandoahRequestedGC_lock", true),
  61   _control_lock(Mutex::nosafepoint - 2, "ShenandoahControlGC_lock", true),
  62   _regulator_lock(Mutex::nosafepoint - 2, "ShenandoahRegulatorGC_lock", true),
  63   _periodic_task(this),
  64   _requested_gc_cause(GCCause::_no_cause_specified),
  65   _requested_generation(select_global_generation()),
  66   _degen_point(ShenandoahGC::_degenerated_outside_cycle),
  67   _degen_generation(nullptr),
  68   _allocs_seen(0),
  69   _mode(none) {
  70   set_name("Shenandoah Control Thread");
  71   reset_gc_id();
  72   create_and_start();
  73   _periodic_task.enroll();
  74   if (ShenandoahPacing) {
  75     _periodic_pacer_notify_task.enroll();
  76   }
  77 }
  78 
  79 ShenandoahControlThread::~ShenandoahControlThread() {
  80   // This is here so that super is called.
  81 }
  82 
  83 void ShenandoahPeriodicTask::task() {
  84   _thread->handle_force_counters_update();
  85   _thread->handle_counters_update();
  86 }
  87 
  88 void ShenandoahPeriodicPacerNotify::task() {
  89   assert(ShenandoahPacing, "Should not be here otherwise");
  90   ShenandoahHeap::heap()->pacer()->notify_waiters();
  91 }
  92 
  93 void ShenandoahControlThread::run_service() {
  94   ShenandoahHeap* heap = ShenandoahHeap::heap();
  95 
  96   GCMode default_mode = concurrent_normal;
  97   ShenandoahGenerationType generation = select_global_generation();
  98   GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc;

  99 
 100   double last_shrink_time = os::elapsedTime();
 101   uint age_period = 0;
 102 
 103   // Shrink period avoids constantly polling regions for shrinking.
 104   // Having a period 10x lower than the delay would mean we hit the
 105   // shrinking with lag of less than 1/10-th of true delay.
 106   // ShenandoahUncommitDelay is in msecs, but shrink_period is in seconds.
 107   double shrink_period = (double)ShenandoahUncommitDelay / 1000 / 10;
 108 
 109   ShenandoahCollectorPolicy* policy = heap->shenandoah_policy();
 110 
 111   // Heuristics are notified of allocation failures here and other outcomes
 112   // of the cycle. They're also used here to control whether the Nth consecutive
 113   // degenerated cycle should be 'promoted' to a full cycle. The decision to
 114   // trigger a cycle or not is evaluated on the regulator thread.
 115   ShenandoahHeuristics* global_heuristics = heap->global_generation()->heuristics();
 116   bool old_bootstrap_requested = false;
 117   while (!in_graceful_shutdown() && !should_terminate()) {
 118     // Figure out if we have pending requests.
 119     bool alloc_failure_pending = _alloc_failure_gc.is_set();
 120     bool is_gc_requested = _gc_requested.is_set();
 121     GCCause::Cause requested_gc_cause = _requested_gc_cause;
 122     bool explicit_gc_requested = is_gc_requested && is_explicit_gc(requested_gc_cause);
 123     bool implicit_gc_requested = is_gc_requested && is_implicit_gc(requested_gc_cause);
 124 
 125     // This control loop iteration have seen this much allocations.
 126     size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed);
 127 
 128     // Check if we have seen a new target for soft max heap size.
 129     bool soft_max_changed = check_soft_max_changed();
 130 
 131     // Choose which GC mode to run in. The block below should select a single mode.
 132     set_gc_mode(none);
 133     GCCause::Cause cause = GCCause::_last_gc_cause;
 134     ShenandoahGC::ShenandoahDegenPoint degen_point = ShenandoahGC::_degenerated_unset;
 135 
 136     if (alloc_failure_pending) {
 137       // Allocation failure takes precedence: we have to deal with it first thing
 138       log_info(gc)("Trigger: Handle Allocation Failure");
 139 
 140       cause = GCCause::_allocation_failure;
 141 
 142       // Consume the degen point, and seed it with default value
 143       degen_point = _degen_point;
 144       _degen_point = ShenandoahGC::_degenerated_outside_cycle;
 145 
 146       if (degen_point == ShenandoahGC::_degenerated_outside_cycle) {
 147         _degen_generation = heap->mode()->is_generational() ?
 148                 heap->young_generation() : heap->global_generation();
 149       } else {
 150         assert(_degen_generation != nullptr, "Need to know which generation to resume");
 151       }
 152 
 153       ShenandoahHeuristics* heuristics = _degen_generation->heuristics();
 154       generation = _degen_generation->type();
 155       bool old_gen_evacuation_failed = heap->clear_old_evacuation_failure();
 156 
 157       // Do not bother with degenerated cycle if old generation evacuation failed
 158       if (ShenandoahDegeneratedGC && heuristics->should_degenerate_cycle() && !old_gen_evacuation_failed) {
 159         heuristics->record_allocation_failure_gc();
 160         policy->record_alloc_failure_to_degenerated(degen_point);
 161         set_gc_mode(stw_degenerated);
 162       } else {
 163         heuristics->record_allocation_failure_gc();
 164         policy->record_alloc_failure_to_full();
 165         generation = select_global_generation();
 166         set_gc_mode(stw_full);
 167       }

 168     } else if (explicit_gc_requested) {
 169       cause = requested_gc_cause;
 170       generation = select_global_generation();
 171       log_info(gc)("Trigger: Explicit GC request (%s)", GCCause::to_string(cause));
 172 
 173       global_heuristics->record_requested_gc();
 174 
 175       if (ExplicitGCInvokesConcurrent) {
 176         policy->record_explicit_to_concurrent();
 177         set_gc_mode(default_mode);
 178         // Unload and clean up everything
 179         heap->set_unload_classes(global_heuristics->can_unload_classes());
 180       } else {
 181         policy->record_explicit_to_full();
 182         set_gc_mode(stw_full);
 183       }
 184     } else if (implicit_gc_requested) {
 185       cause = requested_gc_cause;
 186       generation = select_global_generation();
 187       log_info(gc)("Trigger: Implicit GC request (%s)", GCCause::to_string(cause));
 188 
 189       global_heuristics->record_requested_gc();
 190 
 191       if (ShenandoahImplicitGCInvokesConcurrent) {
 192         policy->record_implicit_to_concurrent();
 193         set_gc_mode(default_mode);
 194 
 195         // Unload and clean up everything
 196         heap->set_unload_classes(global_heuristics->can_unload_classes());
 197       } else {
 198         policy->record_implicit_to_full();
 199         set_gc_mode(stw_full);
 200       }
 201     } else {
 202       // We should only be here if the regulator requested a cycle or if
 203       // there is an old generation mark in progress.
 204       if (_requested_gc_cause == GCCause::_shenandoah_concurrent_gc) {
 205         if (_requested_generation == OLD && heap->doing_mixed_evacuations()) {
 206           // If a request to start an old cycle arrived while an old cycle was running, but _before_
 207           // it chose any regions for evacuation we don't want to start a new old cycle. Rather, we want
 208           // the heuristic to run a young collection so that we can evacuate some old regions.
 209           assert(!heap->is_concurrent_old_mark_in_progress(), "Should not be running mixed collections and concurrent marking");
 210           generation = YOUNG;
 211         } else if (_requested_generation == OLD && !old_bootstrap_requested) {
 212           // Arrange to perform a young GC immediately followed by a bootstrap OLD GC.  OLD GC typically requires more
 213           // than twice the time required for YOUNG GC, so we run a YOUNG GC to replenish the YOUNG allocation pool before
 214           // we start the longer OLD GC effort.
 215           old_bootstrap_requested = true;
 216           generation = YOUNG;
 217         } else {
 218           // if (old_bootstrap_requested && (_requested_generation == OLD)), this starts the bootstrap GC that
 219           //  immediately follows the preparatory young GC.
 220           // But we will abandon the planned bootstrap GC if a GLOBAL GC has been now been requested.
 221           generation = _requested_generation;
 222           old_bootstrap_requested = false;
 223         }
 224         // preemption was requested or this is a regular cycle
 225         cause = GCCause::_shenandoah_concurrent_gc;
 226         set_gc_mode(default_mode);
 227 
 228         // Don't start a new old marking if there is one already in progress
 229         if (generation == OLD && heap->is_concurrent_old_mark_in_progress()) {
 230           set_gc_mode(servicing_old);
 231         }
 232 
 233         if (generation == select_global_generation()) {
 234           heap->set_unload_classes(global_heuristics->should_unload_classes());
 235         } else {
 236           heap->set_unload_classes(false);
 237         }
 238 
 239         // Don't want to spin in this loop and start a cycle every time, so
 240         // clear requested gc cause. This creates a race with callers of the
 241         // blocking 'request_gc' method, but there it loops and resets the
 242         // '_requested_gc_cause' until a full cycle is completed.
 243         _requested_gc_cause = GCCause::_no_gc;
 244       } else if (heap->is_concurrent_old_mark_in_progress() || heap->is_prepare_for_old_mark_in_progress()) {
 245         // Nobody asked us to do anything, but we have an old-generation mark or old-generation preparation for
 246         // mixed evacuation in progress, so resume working on that.
 247         log_info(gc)("Resume old GC: marking is%s in progress, preparing is%s in progress",
 248                      heap->is_concurrent_old_mark_in_progress() ? "" : " NOT",
 249                      heap->is_prepare_for_old_mark_in_progress() ? "" : " NOT");
 250 
 251         cause = GCCause::_shenandoah_concurrent_gc;
 252         generation = OLD;
 253         set_gc_mode(servicing_old);
 254       }
 255     }
 256 
 257     // Blow all soft references on this cycle, if handling allocation failure,
 258     // either implicit or explicit GC request, or we are requested to do so unconditionally.
 259     if (generation == select_global_generation() && (alloc_failure_pending || implicit_gc_requested || explicit_gc_requested || ShenandoahAlwaysClearSoftRefs)) {
 260       heap->soft_ref_policy()->set_should_clear_all_soft_refs(true);
 261     }
 262 
 263     bool gc_requested = (_mode != none);
 264     assert (!gc_requested || cause != GCCause::_last_gc_cause, "GC cause should be set");
 265 
 266     if (gc_requested) {
 267       // GC is starting, bump the internal ID
 268       update_gc_id();
 269 
 270       heap->reset_bytes_allocated_since_gc_start();
 271 
 272       MetaspaceCombinedStats meta_sizes = MetaspaceUtils::get_combined_statistics();
 273 
 274       // If GC was requested, we are sampling the counters even without actual triggers
 275       // from allocation machinery. This captures GC phases more accurately.
 276       set_forced_counters_update(true);
 277 
 278       // If GC was requested, we better dump freeset data for performance debugging
 279       {
 280         ShenandoahHeapLocker locker(heap->lock());
 281         heap->free_set()->log_status();
 282       }
 283       // In case this is a degenerated cycle, remember whether original cycle was aging.
 284       bool was_aging_cycle = heap->is_aging_cycle();
 285       heap->set_aging_cycle(false);
 286 
 287       switch (_mode) {
 288         case concurrent_normal: {
 289           // At this point:
 290           //  if (generation == YOUNG), this is a normal YOUNG cycle
 291           //  if (generation == OLD), this is a bootstrap OLD cycle
 292           //  if (generation == GLOBAL), this is a GLOBAL cycle triggered by System.gc()
 293           // In all three cases, we want to age old objects if this is an aging cycle
 294           if (age_period-- == 0) {
 295              heap->set_aging_cycle(true);
 296              age_period = ShenandoahAgingCyclePeriod - 1;
 297           }
 298           service_concurrent_normal_cycle(heap, generation, cause);
 299           break;
 300         }
 301         case stw_degenerated: {
 302           heap->set_aging_cycle(was_aging_cycle);
 303           if (!service_stw_degenerated_cycle(cause, degen_point)) {
 304             // The degenerated GC was upgraded to a Full GC
 305             generation = select_global_generation();
 306           }
 307           break;
 308         }
 309         case stw_full: {
 310           if (age_period-- == 0) {
 311             heap->set_aging_cycle(true);
 312             age_period = ShenandoahAgingCyclePeriod - 1;
 313           }
 314           service_stw_full_cycle(cause);
 315           break;
 316         }
 317         case servicing_old: {
 318           assert(generation == OLD, "Expected old generation here");
 319           GCIdMark gc_id_mark;
 320           service_concurrent_old_cycle(heap, cause);
 321           break;
 322         }
 323         default:
 324           ShouldNotReachHere();
 325       }
 326 
 327       // If this was the requested GC cycle, notify waiters about it
 328       if (explicit_gc_requested || implicit_gc_requested) {
 329         notify_gc_waiters();
 330       }
 331 
 332       // If this was the allocation failure GC cycle, notify waiters about it
 333       if (alloc_failure_pending) {
 334         notify_alloc_failure_waiters();
 335       }
 336 
 337       // Report current free set state at the end of cycle, whether
 338       // it is a normal completion, or the abort.
 339       {
 340         ShenandoahHeapLocker locker(heap->lock());
 341         heap->free_set()->log_status();
 342 
 343         // Notify Universe about new heap usage. This has implications for
 344         // global soft refs policy, and we better report it every time heap
 345         // usage goes down.
 346         Universe::heap()->update_capacity_and_used_at_gc();
 347 
 348         // Signal that we have completed a visit to all live objects.
 349         Universe::heap()->record_whole_heap_examined_timestamp();
 350       }
 351 
 352       // Disable forced counters update, and update counters one more time
 353       // to capture the state at the end of GC session.
 354       handle_force_counters_update();
 355       set_forced_counters_update(false);
 356 
 357       // Retract forceful part of soft refs policy
 358       heap->soft_ref_policy()->set_should_clear_all_soft_refs(false);
 359 
 360       // Clear metaspace oom flag, if current cycle unloaded classes
 361       if (heap->unload_classes()) {
 362         assert(generation == select_global_generation(), "Only unload classes during GLOBAL cycle");
 363         global_heuristics->clear_metaspace_oom();





 364       }
 365 
 366       process_phase_timings(heap);














 367 
 368       // Print Metaspace change following GC (if logging is enabled).
 369       MetaspaceUtils::print_metaspace_change(meta_sizes);
 370 
 371       // GC is over, we are at idle now
 372       if (ShenandoahPacing) {
 373         heap->pacer()->setup_for_idle();
 374       }
 375     } else {
 376       // Allow allocators to know we have seen this much regions
 377       if (ShenandoahPacing && (allocs_seen > 0)) {
 378         heap->pacer()->report_alloc(allocs_seen);
 379       }
 380     }
 381 
 382     double current = os::elapsedTime();
 383 
 384     if (ShenandoahUncommit && (explicit_gc_requested || soft_max_changed || (current - last_shrink_time > shrink_period))) {
 385       // Explicit GC tries to uncommit everything down to min capacity.
 386       // Soft max change tries to uncommit everything down to target capacity.
 387       // Periodic uncommit tries to uncommit suitable regions down to min capacity.
 388 
 389       double shrink_before = (explicit_gc_requested || soft_max_changed) ?
 390                              current :
 391                              current - (ShenandoahUncommitDelay / 1000.0);
 392 
 393       size_t shrink_until = soft_max_changed ?
 394                              heap->soft_max_capacity() :
 395                              heap->min_capacity();
 396 
 397       service_uncommit(shrink_before, shrink_until);
 398       heap->phase_timings()->flush_cycle_to_global();
 399       last_shrink_time = current;
 400     }
 401 
 402     // Don't wait around if there was an allocation failure - start the next cycle immediately.
 403     if (!is_alloc_failure_gc()) {
 404       if (old_bootstrap_requested) {
 405         _requested_generation = OLD;
 406         _requested_gc_cause = GCCause::_shenandoah_concurrent_gc;
 407       } else {
 408         // The timed wait is necessary because this thread has a responsibility to send
 409         // 'alloc_words' to the pacer when it does not perform a GC.
 410         MonitorLocker lock(&_control_lock, Mutex::_no_safepoint_check_flag);
 411         lock.wait(ShenandoahControlIntervalMax);
 412       }
 413     } else {
 414       // in case of alloc_failure, abandon any plans to do immediate OLD Bootstrap
 415       old_bootstrap_requested = false;
 416     }

 417   }
 418 
 419   // Wait for the actual stop(), can't leave run_service() earlier.
 420   while (!should_terminate()) {
 421     os::naked_short_sleep(ShenandoahControlIntervalMin);
 422   }
 423 }
 424 
 425 void ShenandoahControlThread::process_phase_timings(const ShenandoahHeap* heap) {
 426   // Commit worker statistics to cycle data
 427   heap->phase_timings()->flush_par_workers_to_cycle();
 428   if (ShenandoahPacing) {
 429     heap->pacer()->flush_stats_to_cycle();
 430   }
 431 
 432   ShenandoahCycleStats evac_stats = heap->evac_tracker()->flush_cycle_to_global();
 433 
 434   // Print GC stats for current cycle
 435   {
 436     LogTarget(Info, gc, stats) lt;
 437     if (lt.is_enabled()) {
 438       ResourceMark rm;
 439       LogStream ls(lt);
 440       heap->phase_timings()->print_cycle_on(&ls);
 441       ShenandoahEvacuationTracker::print_evacuations_on(&ls, &evac_stats.workers,
 442                                                         &evac_stats.mutators);
 443       if (ShenandoahPacing) {
 444         heap->pacer()->print_cycle_on(&ls);
 445       }
 446     }
 447   }
 448 
 449   // Commit statistics to globals
 450   heap->phase_timings()->flush_cycle_to_global();
 451 }
 452 
 453 // Young and old concurrent cycles are initiated by the regulator. Implicit
 454 // and explicit GC requests are handled by the controller thread and always
 455 // run a global cycle (which is concurrent by default, but may be overridden
 456 // by command line options). Old cycles always degenerate to a global cycle.
 457 // Young cycles are degenerated to complete the young cycle.  Young
 458 // and old degen may upgrade to Full GC.  Full GC may also be
 459 // triggered directly by a System.gc() invocation.
 460 //
 461 //
 462 //      +-----+ Idle +-----+-----------+---------------------+
 463 //      |         +        |           |                     |
 464 //      |         |        |           |                     |
 465 //      |         |        v           |                     |
 466 //      |         |  Bootstrap Old +-- | ------------+       |
 467 //      |         |   +                |             |       |
 468 //      |         |   |                |             |       |
 469 //      |         v   v                v             v       |
 470 //      |    Resume Old <----------+ Young +--> Young Degen  |
 471 //      |     +  +   ^                            +  +       |
 472 //      v     |  |   |                            |  |       |
 473 //   Global <-+  |   +----------------------------+  |       |
 474 //      +        |                                   |       |
 475 //      |        v                                   v       |
 476 //      +--->  Global Degen +--------------------> Full <----+
 477 //
 478 void ShenandoahControlThread::service_concurrent_normal_cycle(ShenandoahHeap* heap,
 479                                                               const ShenandoahGenerationType generation,
 480                                                               GCCause::Cause cause) {
 481   GCIdMark gc_id_mark;
 482   ShenandoahGeneration* the_generation = nullptr;
 483   switch (generation) {
 484     case YOUNG: {
 485       // Run a young cycle. This might or might not, have interrupted an ongoing
 486       // concurrent mark in the old generation. We need to think about promotions
 487       // in this case. Promoted objects should be above the TAMS in the old regions
 488       // they end up in, but we have to be sure we don't promote into any regions
 489       // that are in the cset.
 490       log_info(gc, ergo)("Start GC cycle (YOUNG)");
 491       the_generation = heap->young_generation();
 492       service_concurrent_cycle(the_generation, cause, false);
 493       break;
 494     }
 495     case OLD: {
 496       log_info(gc, ergo)("Start GC cycle (OLD)");
 497       the_generation = heap->old_generation();
 498       service_concurrent_old_cycle(heap, cause);
 499       break;
 500     }
 501     case GLOBAL_GEN: {
 502       log_info(gc, ergo)("Start GC cycle (GLOBAL)");
 503       the_generation = heap->global_generation();
 504       service_concurrent_cycle(the_generation, cause, false);
 505       break;
 506     }
 507     case GLOBAL_NON_GEN: {
 508       log_info(gc, ergo)("Start GC cycle");
 509       the_generation = heap->global_generation();
 510       service_concurrent_cycle(the_generation, cause, false);
 511       break;
 512     }
 513     default:
 514       ShouldNotReachHere();
 515   }
 516 }
 517 
 518 void ShenandoahControlThread::service_concurrent_old_cycle(ShenandoahHeap* heap, GCCause::Cause &cause) {
 519   ShenandoahOldGeneration* old_generation = heap->old_generation();
 520   ShenandoahYoungGeneration* young_generation = heap->young_generation();
 521   ShenandoahOldGeneration::State original_state = old_generation->state();
 522 
 523   TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
 524 
 525   switch (original_state) {
 526     case ShenandoahOldGeneration::WAITING_FOR_FILL:
 527     case ShenandoahOldGeneration::IDLE: {
 528       assert(!heap->is_concurrent_old_mark_in_progress(), "Old already in progress");
 529       assert(old_generation->task_queues()->is_empty(), "Old mark queues should be empty");
 530     }
 531     case ShenandoahOldGeneration::FILLING: {
 532       _allow_old_preemption.set();
 533       ShenandoahGCSession session(cause, old_generation);
 534       old_generation->prepare_gc();
 535       _allow_old_preemption.unset();
 536 
 537       if (heap->is_prepare_for_old_mark_in_progress()) {
 538         // Coalescing threads detected the cancellation request and aborted. Stay
 539         // in this state so control thread may resume the coalescing work.
 540         assert(old_generation->state() == ShenandoahOldGeneration::FILLING, "Prepare for mark should be in progress");
 541         return;
 542       }
 543 
 544       // It is possible for a young generation request to preempt this nascent old
 545       // collection cycle _after_ we've finished making the old regions parseable (filling),
 546       // but _before_ we have unset the preemption flag. It is also possible for an
 547       // allocation failure to occur after the threads have finished filling. We must
 548       // check if we have been cancelled before we start a bootstrap cycle.
 549       if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) {
 550         if (heap->cancelled_gc()) {
 551           // If this was a preemption request, the cancellation would have been cleared
 552           // so that we run a concurrent young cycle. If the cancellation is still set,
 553           // then this is an allocation failure and we need to run a degenerated cycle.
 554           // If this is a preemption request, we're just going to fall through and run
 555           // the bootstrap cycle to start the old generation cycle (the bootstrap cycle is
 556           // a concurrent young cycle - which is what we're being asked to do in that case).
 557           // If the cycle is cancelled for any other reason, we return from here and let
 558           // the control thread return to the top of its decision loop.
 559           log_info(gc)("Preparation for old generation cycle was cancelled");
 560           return;
 561         }
 562       }
 563       old_generation->transition_to(ShenandoahOldGeneration::BOOTSTRAPPING);
 564     }
 565     case ShenandoahOldGeneration::BOOTSTRAPPING: {
 566       // Configure the young generation's concurrent mark to put objects in
 567       // old regions into the concurrent mark queues associated with the old
 568       // generation. The young cycle will run as normal except that rather than
 569       // ignore old references it will mark and enqueue them in the old concurrent
 570       // task queues but it will not traverse them.
 571       set_gc_mode(bootstrapping_old);
 572       young_generation->set_old_gen_task_queues(old_generation->task_queues());
 573       ShenandoahGCSession session(cause, young_generation);
 574       service_concurrent_cycle(heap, young_generation, cause, true);
 575       process_phase_timings(heap);
 576       if (heap->cancelled_gc()) {
 577         // Young generation bootstrap cycle has failed. Concurrent mark for old generation
 578         // is going to resume after degenerated bootstrap cycle completes.
 579         log_info(gc)("Bootstrap cycle for old generation was cancelled");
 580         return;
 581       }
 582 
 583       // Reset the degenerated point. Normally this would happen at the top
 584       // of the control loop, but here we have just completed a young cycle
 585       // which has bootstrapped the old concurrent marking.
 586       _degen_point = ShenandoahGC::_degenerated_outside_cycle;
 587 
 588       // From here we will 'resume' the old concurrent mark. This will skip reset
 589       // and init mark for the concurrent mark. All of that work will have been
 590       // done by the bootstrapping young cycle.
 591       set_gc_mode(servicing_old);
 592       old_generation->transition_to(ShenandoahOldGeneration::MARKING);
 593     }
 594     case ShenandoahOldGeneration::MARKING: {
 595       ShenandoahGCSession session(cause, old_generation);
 596       bool marking_complete = resume_concurrent_old_cycle(old_generation, cause);
 597       if (marking_complete) {
 598         assert(old_generation->state() != ShenandoahOldGeneration::MARKING, "Should not still be marking");
 599         if (original_state == ShenandoahOldGeneration::MARKING) {
 600           heap->mmu_tracker()->record_old_marking_increment(old_generation, GCId::current(), true,
 601                                                             heap->collection_set()->has_old_regions());
 602           heap->log_heap_status("At end of Concurrent Old Marking finishing increment");
 603         }
 604       } else if (original_state == ShenandoahOldGeneration::MARKING) {
 605         heap->mmu_tracker()->record_old_marking_increment(old_generation, GCId::current(), false,
 606                                                           heap->collection_set()->has_old_regions());
 607         heap->log_heap_status("At end of Concurrent Old Marking increment");
 608       }
 609       break;
 610     }
 611     default:
 612       fatal("Unexpected state for old GC: %s", ShenandoahOldGeneration::state_name(old_generation->state()));
 613   }
 614 }
 615 
 616 bool ShenandoahControlThread::resume_concurrent_old_cycle(ShenandoahGeneration* generation, GCCause::Cause cause) {
 617   assert(ShenandoahHeap::heap()->is_concurrent_old_mark_in_progress(), "Old mark should be in progress");
 618   log_debug(gc)("Resuming old generation with " UINT32_FORMAT " marking tasks queued", generation->task_queues()->tasks());
 619 
 620   ShenandoahHeap* heap = ShenandoahHeap::heap();
 621 
 622   // We can only tolerate being cancelled during concurrent marking or during preparation for mixed
 623   // evacuation. This flag here (passed by reference) is used to control precisely where the regulator
 624   // is allowed to cancel a GC.
 625   ShenandoahOldGC gc(generation, _allow_old_preemption);
 626   if (gc.collect(cause)) {
 627     generation->record_success_concurrent(false);
 628   }
 629 
 630   if (heap->cancelled_gc()) {
 631     // It's possible the gc cycle was cancelled after the last time
 632     // the collection checked for cancellation. In which case, the
 633     // old gc cycle is still completed, and we have to deal with this
 634     // cancellation. We set the degeneration point to be outside
 635     // the cycle because if this is an allocation failure, that is
 636     // what must be done (there is no degenerated old cycle). If the
 637     // cancellation was due to a heuristic wanting to start a young
 638     // cycle, then we are not actually going to a degenerated cycle,
 639     // so the degenerated point doesn't matter here.
 640     check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle);
 641     if (_requested_gc_cause == GCCause::_shenandoah_concurrent_gc) {
 642       heap->shenandoah_policy()->record_interrupted_old();
 643     }
 644     return false;
 645   }
 646   return true;
 647 }
 648 
 649 bool ShenandoahControlThread::check_soft_max_changed() const {
 650   ShenandoahHeap* heap = ShenandoahHeap::heap();
 651   size_t new_soft_max = Atomic::load(&SoftMaxHeapSize);
 652   size_t old_soft_max = heap->soft_max_capacity();
 653   if (new_soft_max != old_soft_max) {
 654     new_soft_max = MAX2(heap->min_capacity(), new_soft_max);
 655     new_soft_max = MIN2(heap->max_capacity(), new_soft_max);
 656     if (new_soft_max != old_soft_max) {
 657       log_info(gc)("Soft Max Heap Size: " SIZE_FORMAT "%s -> " SIZE_FORMAT "%s",
 658                    byte_size_in_proper_unit(old_soft_max), proper_unit_for_byte_size(old_soft_max),
 659                    byte_size_in_proper_unit(new_soft_max), proper_unit_for_byte_size(new_soft_max)
 660       );
 661       heap->set_soft_max_capacity(new_soft_max);
 662       return true;
 663     }
 664   }
 665   return false;
 666 }
 667 
 668 void ShenandoahControlThread::service_concurrent_cycle(ShenandoahGeneration* generation, GCCause::Cause cause, bool do_old_gc_bootstrap) {
 669   // Normal cycle goes via all concurrent phases. If allocation failure (af) happens during
 670   // any of the concurrent phases, it first degrades to Degenerated GC and completes GC there.
 671   // If second allocation failure happens during Degenerated GC cycle (for example, when GC
 672   // tries to evac something and no memory is available), cycle degrades to Full GC.
 673   //
 674   // There are also a shortcut through the normal cycle: immediate garbage shortcut, when
 675   // heuristics says there are no regions to compact, and all the collection comes from immediately
 676   // reclaimable regions.
 677   //
 678   // ................................................................................................
 679   //
 680   //                                    (immediate garbage shortcut)                Concurrent GC
 681   //                             /-------------------------------------------\
 682   //                             |                                           |
 683   //                             |                                           |
 684   //                             |                                           |
 685   //                             |                                           v
 686   // [START] ----> Conc Mark ----o----> Conc Evac --o--> Conc Update-Refs ---o----> [END]
 687   //                   |                    |                 |              ^
 688   //                   | (af)               | (af)            | (af)         |
 689   // ..................|....................|.................|..............|.......................
 690   //                   |                    |                 |              |
 691   //                   |                    |                 |              |      Degenerated GC
 692   //                   v                    v                 v              |
 693   //               STW Mark ----------> STW Evac ----> STW Update-Refs ----->o
 694   //                   |                    |                 |              ^
 695   //                   | (af)               | (af)            | (af)         |
 696   // ..................|....................|.................|..............|.......................
 697   //                   |                    |                 |              |
 698   //                   |                    v                 |              |      Full GC
 699   //                   \------------------->o<----------------/              |
 700   //                                        |                                |
 701   //                                        v                                |
 702   //                                      Full GC  --------------------------/
 703   //

 704   if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return;
 705 
 706   ShenandoahHeap* heap = ShenandoahHeap::heap();
 707   ShenandoahGCSession session(cause, generation);

 708   TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
 709 
 710   service_concurrent_cycle(heap, generation, cause, do_old_gc_bootstrap);
 711 }
 712 
 713 void ShenandoahControlThread::service_concurrent_cycle(ShenandoahHeap* heap,
 714                                                        ShenandoahGeneration* generation,
 715                                                        GCCause::Cause& cause,
 716                                                        bool do_old_gc_bootstrap) {
 717   ShenandoahConcurrentGC gc(generation, do_old_gc_bootstrap);
 718   if (gc.collect(cause)) {
 719     // Cycle is complete
 720     generation->record_success_concurrent(gc.abbreviated());

 721   } else {
 722     assert(heap->cancelled_gc(), "Must have been cancelled");
 723     check_cancellation_or_degen(gc.degen_point());
 724     assert(!generation->is_old(), "Old GC takes a different control path");
 725     // Concurrent young-gen collection degenerates to young
 726     // collection.  Same for global collections.
 727     _degen_generation = generation;
 728   }
 729   const char* msg;
 730   if (heap->mode()->is_generational()) {
 731     if (heap->cancelled_gc()) {
 732       msg = (generation->is_young()) ? "At end of Interrupted Concurrent Young GC" :
 733                                        "At end of Interrupted Concurrent Bootstrap GC";
 734     } else {
 735       msg = (generation->is_young()) ? "At end of Concurrent Young GC" :
 736                                        "At end of Concurrent Bootstrap GC";
 737       // We only record GC results if GC was successful
 738       ShenandoahMmuTracker* mmu_tracker = heap->mmu_tracker();
 739       if (generation->is_young()) {
 740         if (heap->collection_set()->has_old_regions()) {
 741           bool mixed_is_done = (heap->old_heuristics()->unprocessed_old_collection_candidates() == 0);
 742           mmu_tracker->record_mixed(generation, get_gc_id(), mixed_is_done);
 743         } else {
 744           mmu_tracker->record_young(generation, get_gc_id());
 745         }
 746       } else {
 747         mmu_tracker->record_bootstrap(generation, get_gc_id(), heap->collection_set()->has_old_regions());
 748       }
 749     }
 750   } else {
 751     msg = heap->cancelled_gc() ? "At end of cancelled GC" :
 752                                  "At end of GC";
 753   }
 754   heap->log_heap_status(msg);
 755 }
 756 
 757 bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) {
 758   ShenandoahHeap* heap = ShenandoahHeap::heap();
 759   if (!heap->cancelled_gc()) {
 760     return false;
 761   }
 762 
 763   if (in_graceful_shutdown()) {


 764     return true;
 765   }
 766 
 767   assert(_degen_point == ShenandoahGC::_degenerated_outside_cycle,
 768          "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point));
 769 
 770   if (is_alloc_failure_gc()) {
 771     _degen_point = point;
 772     return true;
 773   }
 774 
 775   if (_preemption_requested.is_set()) {
 776     assert(_requested_generation == YOUNG, "Only young GCs may preempt old.");
 777     _preemption_requested.unset();
 778 
 779     // Old generation marking is only cancellable during concurrent marking.
 780     // Once final mark is complete, the code does not check again for cancellation.
 781     // If old generation was cancelled for an allocation failure, we wouldn't
 782     // make it to this case. The calling code is responsible for forcing a
 783     // cancellation due to allocation failure into a degenerated cycle.
 784     _degen_point = point;
 785     heap->clear_cancelled_gc(false /* clear oom handler */);
 786     return true;
 787   }
 788 
 789   fatal("Cancel GC either for alloc failure GC, or gracefully exiting, or to pause old generation marking");
 790   return false;
 791 }
 792 
 793 void ShenandoahControlThread::stop_service() {
 794   // Nothing to do here.
 795 }
 796 
 797 void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) {
 798   ShenandoahHeap* const heap = ShenandoahHeap::heap();
 799 
 800   GCIdMark gc_id_mark;
 801   ShenandoahGCSession session(cause, heap->global_generation());
 802 
 803   ShenandoahFullGC gc;
 804   gc.collect(cause);
 805 
 806   heap->global_generation()->heuristics()->record_success_full();

 807   heap->shenandoah_policy()->record_success_full();
 808 }
 809 
 810 bool ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause,
 811                                                             ShenandoahGC::ShenandoahDegenPoint point) {
 812   assert(point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set");
 813   ShenandoahHeap* const heap = ShenandoahHeap::heap();
 814 
 815   GCIdMark gc_id_mark;
 816   ShenandoahGCSession session(cause, _degen_generation);
 817 
 818   ShenandoahDegenGC gc(point, _degen_generation);
 819   gc.collect(cause);
 820 
 821   assert(heap->young_generation()->task_queues()->is_empty(), "Unexpected young generation marking tasks");
 822   if (_degen_generation->is_global()) {
 823     assert(heap->old_generation()->task_queues()->is_empty(), "Unexpected old generation marking tasks");
 824     assert(heap->global_generation()->task_queues()->is_empty(), "Unexpected global generation marking tasks");
 825   } else {
 826     assert(_degen_generation->is_young(), "Expected degenerated young cycle, if not global.");
 827     ShenandoahOldGeneration* old = heap->old_generation();
 828     if (old->state() == ShenandoahOldGeneration::BOOTSTRAPPING && !gc.upgraded_to_full()) {
 829       old->transition_to(ShenandoahOldGeneration::MARKING);
 830     }
 831   }
 832 
 833   _degen_generation->heuristics()->record_success_degenerated();
 834   heap->shenandoah_policy()->record_success_degenerated();
 835   return !gc.upgraded_to_full();
 836 }
 837 
 838 void ShenandoahControlThread::service_uncommit(double shrink_before, size_t shrink_until) {
 839   ShenandoahHeap* heap = ShenandoahHeap::heap();
 840 
 841   // Determine if there is work to do. This avoids taking heap lock if there is
 842   // no work available, avoids spamming logs with superfluous logging messages,
 843   // and minimises the amount of work while locks are taken.
 844 
 845   if (heap->committed() <= shrink_until) return;
 846 
 847   bool has_work = false;
 848   for (size_t i = 0; i < heap->num_regions(); i++) {
 849     ShenandoahHeapRegion *r = heap->get_region(i);
 850     if (r->is_empty_committed() && (r->empty_time() < shrink_before)) {
 851       has_work = true;
 852       break;
 853     }
 854   }
 855 
 856   if (has_work) {
 857     heap->entry_uncommit(shrink_before, shrink_until);
 858   }
 859 }
 860 
 861 bool ShenandoahControlThread::is_explicit_gc(GCCause::Cause cause) const {
 862   return GCCause::is_user_requested_gc(cause) ||
 863          GCCause::is_serviceability_requested_gc(cause);
 864 }
 865 
 866 bool ShenandoahControlThread::is_implicit_gc(GCCause::Cause cause) const {
 867   return !is_explicit_gc(cause) &&
 868           (cause != GCCause::_shenandoah_concurrent_gc);
 869 }
 870 
 871 void ShenandoahControlThread::request_gc(GCCause::Cause cause) {
 872   assert(GCCause::is_user_requested_gc(cause) ||
 873          GCCause::is_serviceability_requested_gc(cause) ||
 874          cause == GCCause::_metadata_GC_clear_soft_refs ||
 875          cause == GCCause::_codecache_GC_aggressive ||
 876          cause == GCCause::_codecache_GC_threshold ||
 877          cause == GCCause::_full_gc_alot ||
 878          cause == GCCause::_wb_young_gc ||
 879          cause == GCCause::_wb_full_gc ||
 880          cause == GCCause::_wb_breakpoint ||
 881          cause == GCCause::_scavenge_alot,
 882          "only requested GCs here: %s", GCCause::to_string(cause));
 883 
 884   if (is_explicit_gc(cause)) {
 885     if (!DisableExplicitGC) {
 886       handle_requested_gc(cause);
 887     }
 888   } else {
 889     handle_requested_gc(cause);
 890   }
 891 }
 892 
 893 bool ShenandoahControlThread::request_concurrent_gc(ShenandoahGenerationType generation) {
 894   if (_preemption_requested.is_set() || _gc_requested.is_set() || ShenandoahHeap::heap()->cancelled_gc()) {
 895     // Ignore subsequent requests from the heuristics
 896     return false;
 897   }
 898 
 899   if (_mode == none) {
 900     _requested_gc_cause = GCCause::_shenandoah_concurrent_gc;
 901     _requested_generation = generation;
 902     notify_control_thread();
 903     MonitorLocker ml(&_regulator_lock, Mutex::_no_safepoint_check_flag);
 904     ml.wait();
 905     return true;
 906   }
 907 
 908   if (preempt_old_marking(generation)) {
 909     log_info(gc)("Preempting old generation mark to allow %s GC", shenandoah_generation_name(generation));
 910     _requested_gc_cause = GCCause::_shenandoah_concurrent_gc;
 911     _requested_generation = generation;
 912     _preemption_requested.set();
 913     ShenandoahHeap::heap()->cancel_gc(GCCause::_shenandoah_concurrent_gc);
 914     notify_control_thread();
 915 
 916     MonitorLocker ml(&_regulator_lock, Mutex::_no_safepoint_check_flag);
 917     ml.wait();
 918     return true;
 919   }
 920 
 921   return false;
 922 }
 923 
 924 void ShenandoahControlThread::notify_control_thread() {
 925   MonitorLocker locker(&_control_lock, Mutex::_no_safepoint_check_flag);
 926   _control_lock.notify();
 927 }
 928 
 929 bool ShenandoahControlThread::preempt_old_marking(ShenandoahGenerationType generation) {
 930   return (generation == YOUNG) && _allow_old_preemption.try_unset();
 931 }
 932 
 933 void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) {
 934   // Make sure we have at least one complete GC cycle before unblocking
 935   // from the explicit GC request.
 936   //
 937   // This is especially important for weak references cleanup and/or native
 938   // resources (e.g. DirectByteBuffers) machinery: when explicit GC request
 939   // comes very late in the already running cycle, it would miss lots of new
 940   // opportunities for cleanup that were made available before the caller
 941   // requested the GC.
 942 
 943   MonitorLocker ml(&_gc_waiters_lock);
 944   size_t current_gc_id = get_gc_id();
 945   size_t required_gc_id = current_gc_id + 1;
 946   while (current_gc_id < required_gc_id) {
 947     // Although setting gc request is under _gc_waiters_lock, but read side (run_service())
 948     // does not take the lock. We need to enforce following order, so that read side sees
 949     // latest requested gc cause when the flag is set.
 950     _requested_gc_cause = cause;
 951     _gc_requested.set();
 952     notify_control_thread();
 953     if (cause != GCCause::_wb_breakpoint) {
 954       ml.wait();
 955     }
 956     current_gc_id = get_gc_id();
 957   }
 958 }
 959 
 960 void ShenandoahControlThread::handle_alloc_failure(ShenandoahAllocRequest& req) {
 961   ShenandoahHeap* heap = ShenandoahHeap::heap();
 962 
 963   assert(current()->is_Java_thread(), "expect Java thread here");
 964 
 965   if (try_set_alloc_failure_gc()) {
 966     // Only report the first allocation failure
 967     log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s",
 968                  req.type_string(),
 969                  byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize));

 970     // Now that alloc failure GC is scheduled, we can abort everything else
 971     heap->cancel_gc(GCCause::_allocation_failure);
 972   }
 973 
 974   MonitorLocker ml(&_alloc_failure_waiters_lock);
 975   while (is_alloc_failure_gc()) {
 976     ml.wait();
 977   }
 978 }
 979 
 980 void ShenandoahControlThread::handle_alloc_failure_evac(size_t words) {
 981   ShenandoahHeap* heap = ShenandoahHeap::heap();
 982 
 983   if (try_set_alloc_failure_gc()) {
 984     // Only report the first allocation failure
 985     log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation",
 986                  byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize));
 987   }
 988 
 989   // Forcefully report allocation failure

1015     _do_counters_update.unset();
1016     ShenandoahHeap::heap()->monitoring_support()->update_counters();
1017   }
1018 }
1019 
1020 void ShenandoahControlThread::handle_force_counters_update() {
1021   if (_force_counters_update.is_set()) {
1022     _do_counters_update.unset(); // reset these too, we do update now!
1023     ShenandoahHeap::heap()->monitoring_support()->update_counters();
1024   }
1025 }
1026 
1027 void ShenandoahControlThread::notify_heap_changed() {
1028   // This is called from allocation path, and thus should be fast.
1029 
1030   // Update monitoring counters when we took a new region. This amortizes the
1031   // update costs on slow path.
1032   if (_do_counters_update.is_unset()) {
1033     _do_counters_update.set();
1034   }




1035 }
1036 
1037 void ShenandoahControlThread::pacing_notify_alloc(size_t words) {
1038   assert(ShenandoahPacing, "should only call when pacing is enabled");
1039   Atomic::add(&_allocs_seen, words, memory_order_relaxed);
1040 }
1041 
1042 void ShenandoahControlThread::set_forced_counters_update(bool value) {
1043   _force_counters_update.set_cond(value);
1044 }
1045 
1046 void ShenandoahControlThread::reset_gc_id() {
1047   Atomic::store(&_gc_id, (size_t)0);
1048 }
1049 
1050 void ShenandoahControlThread::update_gc_id() {
1051   Atomic::inc(&_gc_id);
1052 }
1053 
1054 size_t ShenandoahControlThread::get_gc_id() {
1055   return Atomic::load(&_gc_id);
1056 }
1057 
1058 void ShenandoahControlThread::start() {
1059   create_and_start();
1060 }
1061 
1062 void ShenandoahControlThread::prepare_for_graceful_shutdown() {
1063   _graceful_shutdown.set();
1064 }
1065 
1066 bool ShenandoahControlThread::in_graceful_shutdown() {
1067   return _graceful_shutdown.is_set();
1068 }
1069 
1070 const char* ShenandoahControlThread::gc_mode_name(ShenandoahControlThread::GCMode mode) {
1071   switch (mode) {
1072     case none:              return "idle";
1073     case concurrent_normal: return "normal";
1074     case stw_degenerated:   return "degenerated";
1075     case stw_full:          return "full";
1076     case servicing_old:     return "old";
1077     case bootstrapping_old: return "bootstrap";
1078     default:                return "unknown";
1079   }
1080 }
1081 
1082 void ShenandoahControlThread::set_gc_mode(ShenandoahControlThread::GCMode new_mode) {
1083   if (_mode != new_mode) {
1084     log_info(gc)("Transition from: %s to: %s", gc_mode_name(_mode), gc_mode_name(new_mode));
1085     _mode = new_mode;
1086     MonitorLocker ml(&_regulator_lock, Mutex::_no_safepoint_check_flag);
1087     ml.notify_all();
1088   }
1089 }
1090 
1091 ShenandoahGenerationType ShenandoahControlThread::select_global_generation() {
1092   if (ShenandoahHeap::heap()->mode()->is_generational()) {
1093     return GLOBAL_GEN;
1094   } else {
1095     return GLOBAL_NON_GEN;
1096   }
1097 }
< prev index next >