Skip to content

Commit

Permalink
8268372: ZGC: dynamically select the number of concurrent GC threads …
Browse files Browse the repository at this point in the history
…used

Co-authored-by: Per Liden <pliden@openjdk.org>
Reviewed-by: pliden, eosterlund
  • Loading branch information
albertnetymk and pliden committed Jun 9, 2021
1 parent 4388959 commit dd34a4c
Show file tree
Hide file tree
Showing 29 changed files with 594 additions and 371 deletions.
8 changes: 7 additions & 1 deletion src/hotspot/share/gc/z/zArguments.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -72,6 +72,12 @@ void ZArguments::initialize() {
vm_exit_during_initialization("The flag -XX:+UseZGC can not be combined with -XX:ConcGCThreads=0");
}

// The heuristics used when UseDynamicNumberOfGCThreads is
// enabled defaults to using a ZAllocationSpikeTolerance of 1.
if (UseDynamicNumberOfGCThreads && FLAG_IS_DEFAULT(ZAllocationSpikeTolerance)) {
FLAG_SET_DEFAULT(ZAllocationSpikeTolerance, 1);
}

#ifdef COMPILER2
// Enable loop strip mining by default
if (FLAG_IS_DEFAULT(UseCountedLoopSafepoints)) {
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/gc/z/zCollectedHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ ZCollectedHeap::ZCollectedHeap() :
_barrier_set(),
_initialize(&_barrier_set),
_heap(),
_director(new ZDirector()),
_driver(new ZDriver()),
_director(new ZDirector(_driver)),
_stat(new ZStat()),
_runtime_workers() {}

Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/gc/z/zCollectedHeap.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -44,8 +44,8 @@ class ZCollectedHeap : public CollectedHeap {
ZBarrierSet _barrier_set;
ZInitialize _initialize;
ZHeap _heap;
ZDirector* _director;
ZDriver* _driver;
ZDirector* _director;
ZStat* _stat;
ZRuntimeWorkers _runtime_workers;

Expand Down
347 changes: 257 additions & 90 deletions src/hotspot/share/gc/z/zDirector.cpp

Large diffs are not rendered by default.

22 changes: 6 additions & 16 deletions src/hotspot/share/gc/z/zDirector.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -25,31 +25,21 @@
#define SHARE_GC_Z_ZDIRECTOR_HPP

#include "gc/shared/concurrentGCThread.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/z/zMetronome.hpp"

class ZDriver;

class ZDirector : public ConcurrentGCThread {
private:
static const double one_in_1000;

const size_t _relocation_headroom;
ZMetronome _metronome;

void sample_allocation_rate() const;

bool rule_timer() const;
bool rule_warmup() const;
bool rule_allocation_rate() const;
bool rule_proactive() const;
bool rule_high_usage() const;
GCCause::Cause make_gc_decision() const;
ZDriver* const _driver;
ZMetronome _metronome;

protected:
virtual void run_service();
virtual void stop_service();

public:
ZDirector();
ZDirector(ZDriver* driver);
};

#endif // SHARE_GC_Z_ZDIRECTOR_HPP
163 changes: 94 additions & 69 deletions src/hotspot/share/gc/z/zDriver.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -54,6 +54,28 @@ static const ZStatPhaseConcurrent ZPhaseConcurrentRelocated("Concurrent Relocate
static const ZStatCriticalPhase ZCriticalPhaseGCLockerStall("GC Locker Stall", false /* verbose */);
static const ZStatSampler ZSamplerJavaThreads("System", "Java Threads", ZStatUnitThreads);

ZDriverRequest::ZDriverRequest() :
ZDriverRequest(GCCause::_no_gc) {}

ZDriverRequest::ZDriverRequest(GCCause::Cause cause) :
ZDriverRequest(cause, ConcGCThreads) {}

ZDriverRequest::ZDriverRequest(GCCause::Cause cause, uint nworkers) :
_cause(cause),
_nworkers(nworkers) {}

bool ZDriverRequest::operator==(const ZDriverRequest& other) const {
return _cause == other._cause;
}

GCCause::Cause ZDriverRequest::cause() const {
return _cause;
}

uint ZDriverRequest::nworkers() const {
return _nworkers;
}

class VM_ZOperation : public VM_Operation {
private:
const uint _gc_id;
Expand Down Expand Up @@ -118,47 +140,6 @@ class VM_ZOperation : public VM_Operation {
}
};

static bool should_clear_soft_references() {
// Clear if one or more allocations have stalled
const bool stalled = ZHeap::heap()->is_alloc_stalled();
if (stalled) {
// Clear
return true;
}

// Clear if implied by the GC cause
const GCCause::Cause cause = ZCollectedHeap::heap()->gc_cause();
if (cause == GCCause::_wb_full_gc ||
cause == GCCause::_metadata_GC_clear_soft_refs) {
// Clear
return true;
}

// Don't clear
return false;
}

static bool should_boost_worker_threads() {
// Boost worker threads if one or more allocations have stalled
const bool stalled = ZHeap::heap()->is_alloc_stalled();
if (stalled) {
// Boost
return true;
}

// Boost worker threads if implied by the GC cause
const GCCause::Cause cause = ZCollectedHeap::heap()->gc_cause();
if (cause == GCCause::_wb_full_gc ||
cause == GCCause::_java_lang_system_gc ||
cause == GCCause::_metadata_GC_clear_soft_refs) {
// Boost
return true;
}

// Don't boost
return false;
}

class VM_ZMarkStart : public VM_ZOperation {
public:
virtual VMOp_Type type() const {
Expand All @@ -173,14 +154,6 @@ class VM_ZMarkStart : public VM_ZOperation {
ZStatTimer timer(ZPhasePauseMarkStart);
ZServiceabilityPauseTracer tracer;

// Set up soft reference policy
const bool clear = should_clear_soft_references();
ZHeap::heap()->set_soft_reference_policy(clear);

// Set up boost mode
const bool boost = should_boost_worker_threads();
ZHeap::heap()->set_boost_worker_threads(boost);

ZCollectedHeap::heap()->increment_total_collections(true /* full */);

ZHeap::heap()->mark_start();
Expand Down Expand Up @@ -241,8 +214,12 @@ ZDriver::ZDriver() :
create_and_start();
}

void ZDriver::collect(GCCause::Cause cause) {
switch (cause) {
bool ZDriver::is_busy() const {
return _gc_cycle_port.is_busy();
}

void ZDriver::collect(const ZDriverRequest& request) {
switch (request.cause()) {
case GCCause::_wb_young_gc:
case GCCause::_wb_conc_mark:
case GCCause::_wb_full_gc:
Expand All @@ -253,7 +230,7 @@ void ZDriver::collect(GCCause::Cause cause) {
case GCCause::_jvmti_force_gc:
case GCCause::_metadata_GC_clear_soft_refs:
// Start synchronous GC
_gc_cycle_port.send_sync(cause);
_gc_cycle_port.send_sync(request);
break;

case GCCause::_z_timer:
Expand All @@ -264,7 +241,7 @@ void ZDriver::collect(GCCause::Cause cause) {
case GCCause::_z_high_usage:
case GCCause::_metadata_GC_threshold:
// Start asynchronous GC
_gc_cycle_port.send_async(cause);
_gc_cycle_port.send_async(request);
break;

case GCCause::_gc_locker:
Expand All @@ -274,12 +251,12 @@ void ZDriver::collect(GCCause::Cause cause) {

case GCCause::_wb_breakpoint:
ZBreakpoint::start_gc();
_gc_cycle_port.send_async(cause);
_gc_cycle_port.send_async(request);
break;

default:
// Other causes not supported
fatal("Unsupported GC cause (%s)", GCCause::to_string(cause));
fatal("Unsupported GC cause (%s)", GCCause::to_string(request.cause()));
break;
}
}
Expand Down Expand Up @@ -369,6 +346,50 @@ void ZDriver::check_out_of_memory() {
ZHeap::heap()->check_out_of_memory();
}

static bool should_clear_soft_references(const ZDriverRequest& request) {
// Clear soft references if implied by the GC cause
if (request.cause() == GCCause::_wb_full_gc ||
request.cause() == GCCause::_metadata_GC_clear_soft_refs ||
request.cause() == GCCause::_z_allocation_stall) {
// Clear
return true;
}

// Don't clear
return false;
}

static uint select_active_worker_threads_dynamic(const ZDriverRequest& request) {
// Use requested number of worker threads
return request.nworkers();
}

static uint select_active_worker_threads_static(const ZDriverRequest& request) {
const GCCause::Cause cause = request.cause();
const uint nworkers = request.nworkers();

// Boost number of worker threads if implied by the GC cause
if (cause == GCCause::_wb_full_gc ||
cause == GCCause::_java_lang_system_gc ||
cause == GCCause::_metadata_GC_clear_soft_refs ||
cause == GCCause::_z_allocation_stall) {
// Boost
const uint boosted_nworkers = MAX2(nworkers, ParallelGCThreads);
return boosted_nworkers;
}

// Use requested number of worker threads
return nworkers;
}

static uint select_active_worker_threads(const ZDriverRequest& request) {
if (UseDynamicNumberOfGCThreads) {
return select_active_worker_threads_dynamic(request);
} else {
return select_active_worker_threads_static(request);
}
}

class ZDriverGCScope : public StackObj {
private:
GCIdMark _gc_id;
Expand All @@ -378,23 +399,27 @@ class ZDriverGCScope : public StackObj {
ZServiceabilityCycleTracer _tracer;

public:
ZDriverGCScope(GCCause::Cause cause) :
ZDriverGCScope(const ZDriverRequest& request) :
_gc_id(),
_gc_cause(cause),
_gc_cause_setter(ZCollectedHeap::heap(), cause),
_gc_cause(request.cause()),
_gc_cause_setter(ZCollectedHeap::heap(), _gc_cause),
_timer(ZPhaseCycle),
_tracer() {
// Update statistics
ZStatCycle::at_start();

// Set up soft reference policy
const bool clear = should_clear_soft_references(request);
ZHeap::heap()->set_soft_reference_policy(clear);

// Select number of worker threads to use
const uint nworkers = select_active_worker_threads(request);
ZHeap::heap()->set_active_workers(nworkers);
}

~ZDriverGCScope() {
// Calculate boost factor
const double boost_factor = (double)ZHeap::heap()->nconcurrent_worker_threads() /
(double)ZHeap::heap()->nconcurrent_no_boost_worker_threads();

// Update statistics
ZStatCycle::at_end(_gc_cause, boost_factor);
ZStatCycle::at_end(_gc_cause, ZHeap::heap()->active_workers());

// Update data used by soft reference policy
Universe::heap()->update_capacity_and_used_at_gc();
Expand All @@ -417,8 +442,8 @@ class ZDriverGCScope : public StackObj {
} \
} while (false)

void ZDriver::gc(GCCause::Cause cause) {
ZDriverGCScope scope(cause);
void ZDriver::gc(const ZDriverRequest& request) {
ZDriverGCScope scope(request);

// Phase 1: Pause Mark Start
pause_mark_start();
Expand Down Expand Up @@ -458,15 +483,15 @@ void ZDriver::run_service() {
// Main loop
while (!should_terminate()) {
// Wait for GC request
const GCCause::Cause cause = _gc_cycle_port.receive();
if (cause == GCCause::_no_gc) {
const ZDriverRequest request = _gc_cycle_port.receive();
if (request.cause() == GCCause::_no_gc) {
continue;
}

ZBreakpoint::at_before_gc();

// Run GC
gc(cause);
gc(request);

// Notify GC completed
_gc_cycle_port.ack();
Expand Down
Loading

1 comment on commit dd34a4c

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.