Skip to content

Commit ebc520e

Browse files
author
William Kemper
committedMay 24, 2024
8332841: GenShen: Pull shared members from control thread into common base class
Reviewed-by: ysr
1 parent 236432d commit ebc520e

File tree

5 files changed

+236
-141
lines changed

5 files changed

+236
-141
lines changed
 

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

+7-92
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,21 @@
3535
#include "gc/shenandoah/shenandoahPacer.inline.hpp"
3636
#include "gc/shenandoah/shenandoahUtils.hpp"
3737
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
38+
#include "gc/shenandoah/mode/shenandoahMode.hpp"
39+
#include "logging/log.hpp"
3840
#include "memory/metaspaceUtils.hpp"
3941
#include "memory/metaspaceStats.hpp"
40-
#include "memory/resourceArea.hpp"
41-
#include "runtime/atomic.hpp"
4242

4343
ShenandoahControlThread::ShenandoahControlThread() :
44-
ConcurrentGCThread(),
45-
_alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true),
46-
_gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true),
44+
ShenandoahController(),
4745
_requested_gc_cause(GCCause::_no_cause_specified),
48-
_degen_point(ShenandoahGC::_degenerated_outside_cycle),
49-
_allocs_seen(0) {
46+
_degen_point(ShenandoahGC::_degenerated_outside_cycle) {
5047
set_name("Shenandoah Control Thread");
51-
reset_gc_id();
5248
create_and_start();
5349
}
5450

5551
void ShenandoahControlThread::run_service() {
56-
ShenandoahHeap* heap = ShenandoahHeap::heap();
52+
ShenandoahHeap* const heap = ShenandoahHeap::heap();
5753

5854
const GCMode default_mode = concurrent_normal;
5955
const GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc;
@@ -77,7 +73,7 @@ void ShenandoahControlThread::run_service() {
7773
const GCCause::Cause requested_gc_cause = _requested_gc_cause;
7874

7975
// This control loop iteration has seen this much allocation.
80-
const size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed);
76+
const size_t allocs_seen = reset_allocs_seen();
8177

8278
// Check if we have seen a new target for soft max heap size.
8379
const bool soft_max_changed = heap->check_soft_max_changed();
@@ -106,7 +102,6 @@ void ShenandoahControlThread::run_service() {
106102
policy->record_alloc_failure_to_full();
107103
mode = stw_full;
108104
}
109-
110105
} else if (is_gc_requested) {
111106
cause = requested_gc_cause;
112107
log_info(gc)("Trigger: GC request (%s)", GCCause::to_string(cause));
@@ -239,7 +234,7 @@ void ShenandoahControlThread::run_service() {
239234
heap->pacer()->setup_for_idle();
240235
}
241236
} else {
242-
// Allow allocators to know we have seen this much regions
237+
// Report to pacer that we have seen this many words allocated
243238
if (ShenandoahPacing && (allocs_seen > 0)) {
244239
heap->pacer()->report_alloc(allocs_seen);
245240
}
@@ -407,88 +402,8 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) {
407402
}
408403
}
409404

410-
void ShenandoahControlThread::handle_alloc_failure(ShenandoahAllocRequest& req, bool block) {
411-
ShenandoahHeap* heap = ShenandoahHeap::heap();
412-
413-
assert(current()->is_Java_thread(), "expect Java thread here");
414-
415-
if (try_set_alloc_failure_gc()) {
416-
// Only report the first allocation failure
417-
log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s",
418-
req.type_string(),
419-
byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize));
420-
421-
// Now that alloc failure GC is scheduled, we can abort everything else
422-
heap->cancel_gc(GCCause::_allocation_failure);
423-
}
424-
425-
426-
if (block) {
427-
MonitorLocker ml(&_alloc_failure_waiters_lock);
428-
while (is_alloc_failure_gc()) {
429-
ml.wait();
430-
}
431-
}
432-
}
433-
434-
void ShenandoahControlThread::handle_alloc_failure_evac(size_t words) {
435-
ShenandoahHeap* heap = ShenandoahHeap::heap();
436-
437-
if (try_set_alloc_failure_gc()) {
438-
// Only report the first allocation failure
439-
log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation",
440-
byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize));
441-
}
442-
443-
// Forcefully report allocation failure
444-
heap->cancel_gc(GCCause::_shenandoah_allocation_failure_evac);
445-
}
446-
447-
void ShenandoahControlThread::notify_alloc_failure_waiters() {
448-
_alloc_failure_gc.unset();
449-
MonitorLocker ml(&_alloc_failure_waiters_lock);
450-
ml.notify_all();
451-
}
452-
453-
bool ShenandoahControlThread::try_set_alloc_failure_gc() {
454-
return _alloc_failure_gc.try_set();
455-
}
456-
457-
bool ShenandoahControlThread::is_alloc_failure_gc() {
458-
return _alloc_failure_gc.is_set();
459-
}
460-
461405
void ShenandoahControlThread::notify_gc_waiters() {
462406
_gc_requested.unset();
463407
MonitorLocker ml(&_gc_waiters_lock);
464408
ml.notify_all();
465409
}
466-
467-
void ShenandoahControlThread::pacing_notify_alloc(size_t words) {
468-
assert(ShenandoahPacing, "should only call when pacing is enabled");
469-
Atomic::add(&_allocs_seen, words, memory_order_relaxed);
470-
}
471-
472-
void ShenandoahControlThread::reset_gc_id() {
473-
Atomic::store(&_gc_id, (size_t)0);
474-
}
475-
476-
void ShenandoahControlThread::update_gc_id() {
477-
Atomic::inc(&_gc_id);
478-
}
479-
480-
size_t ShenandoahControlThread::get_gc_id() {
481-
return Atomic::load(&_gc_id);
482-
}
483-
484-
void ShenandoahControlThread::start() {
485-
create_and_start();
486-
}
487-
488-
void ShenandoahControlThread::prepare_for_graceful_shutdown() {
489-
_graceful_shutdown.set();
490-
}
491-
492-
bool ShenandoahControlThread::in_graceful_shutdown() {
493-
return _graceful_shutdown.is_set();
494-
}

‎src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp

+11-48
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@
2828
#include "gc/shared/gcCause.hpp"
2929
#include "gc/shared/concurrentGCThread.hpp"
3030
#include "gc/shenandoah/shenandoahGC.hpp"
31+
#include "gc/shenandoah/shenandoahController.hpp"
3132
#include "gc/shenandoah/shenandoahPadding.hpp"
3233
#include "gc/shenandoah/shenandoahSharedVariables.hpp"
3334

34-
class ShenandoahControlThread: public ConcurrentGCThread {
35+
class ShenandoahControlThread: public ShenandoahController {
3536
friend class VMStructs;
3637

3738
private:
@@ -42,68 +43,30 @@ class ShenandoahControlThread: public ConcurrentGCThread {
4243
stw_full
4344
} GCMode;
4445

45-
// While we could have a single lock for these, it may risk unblocking
46-
// GC waiters when alloc failure GC cycle finishes. We want instead
47-
// to make complete explicit cycle for for demanding customers.
48-
Monitor _alloc_failure_waiters_lock;
49-
Monitor _gc_waiters_lock;
50-
51-
public:
52-
void run_service();
53-
void stop_service();
54-
55-
private:
5646
ShenandoahSharedFlag _gc_requested;
57-
ShenandoahSharedFlag _alloc_failure_gc;
58-
ShenandoahSharedFlag _graceful_shutdown;
5947
GCCause::Cause _requested_gc_cause;
6048
ShenandoahGC::ShenandoahDegenPoint _degen_point;
6149

62-
shenandoah_padding(0);
63-
volatile size_t _allocs_seen;
64-
shenandoah_padding(1);
65-
volatile size_t _gc_id;
66-
shenandoah_padding(2);
50+
public:
51+
ShenandoahControlThread();
52+
53+
void run_service() override;
54+
void stop_service() override;
55+
56+
void request_gc(GCCause::Cause cause) override;
57+
58+
private:
6759

6860
bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point);
6961
void service_concurrent_normal_cycle(GCCause::Cause cause);
7062
void service_stw_full_cycle(GCCause::Cause cause);
7163
void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point);
7264

73-
bool try_set_alloc_failure_gc();
74-
void notify_alloc_failure_waiters();
75-
bool is_alloc_failure_gc();
76-
77-
void reset_gc_id();
78-
void update_gc_id();
79-
size_t get_gc_id();
80-
8165
void notify_gc_waiters();
8266

8367
// Handle GC request.
8468
// Blocks until GC is over.
8569
void handle_requested_gc(GCCause::Cause cause);
86-
87-
public:
88-
// Constructor
89-
ShenandoahControlThread();
90-
91-
// Handle allocation failure from a mutator allocation.
92-
// Optionally blocks while collector is handling the failure. If the GC
93-
// threshold has been exceeded, the mutator allocation will not block so
94-
// that the out of memory error can be raised promptly.
95-
void handle_alloc_failure(ShenandoahAllocRequest& req, bool block = true);
96-
97-
// Handle allocation failure from evacuation path.
98-
void handle_alloc_failure_evac(size_t words);
99-
100-
void request_gc(GCCause::Cause cause);
101-
102-
void pacing_notify_alloc(size_t words);
103-
104-
void start();
105-
void prepare_for_graceful_shutdown();
106-
bool in_graceful_shutdown();
10770
};
10871

10972
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLTHREAD_HPP
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
#include "precompiled.hpp"
25+
26+
#include "gc/shared/gc_globals.hpp"
27+
#include "gc/shenandoah/shenandoahController.hpp"
28+
#include "gc/shenandoah/shenandoahHeap.hpp"
29+
#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
30+
31+
void ShenandoahController::pacing_notify_alloc(size_t words) {
32+
assert(ShenandoahPacing, "should only call when pacing is enabled");
33+
Atomic::add(&_allocs_seen, words, memory_order_relaxed);
34+
}
35+
36+
size_t ShenandoahController::reset_allocs_seen() {
37+
return Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed);
38+
}
39+
40+
void ShenandoahController::prepare_for_graceful_shutdown() {
41+
_graceful_shutdown.set();
42+
}
43+
44+
bool ShenandoahController::in_graceful_shutdown() {
45+
return _graceful_shutdown.is_set();
46+
}
47+
48+
void ShenandoahController::update_gc_id() {
49+
Atomic::inc(&_gc_id);
50+
}
51+
52+
size_t ShenandoahController::get_gc_id() {
53+
return Atomic::load(&_gc_id);
54+
}
55+
56+
void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, bool block) {
57+
ShenandoahHeap* heap = ShenandoahHeap::heap();
58+
59+
assert(current()->is_Java_thread(), "expect Java thread here");
60+
bool is_humongous = req.size() > ShenandoahHeapRegion::humongous_threshold_words();
61+
62+
if (try_set_alloc_failure_gc(is_humongous)) {
63+
// Only report the first allocation failure
64+
log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s",
65+
req.type_string(),
66+
byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize));
67+
68+
// Now that alloc failure GC is scheduled, we can abort everything else
69+
heap->cancel_gc(GCCause::_allocation_failure);
70+
}
71+
72+
73+
if (block) {
74+
MonitorLocker ml(&_alloc_failure_waiters_lock);
75+
while (is_alloc_failure_gc()) {
76+
ml.wait();
77+
}
78+
}
79+
}
80+
81+
void ShenandoahController::handle_alloc_failure_evac(size_t words) {
82+
ShenandoahHeap* heap = ShenandoahHeap::heap();
83+
bool is_humongous = (words > ShenandoahHeapRegion::region_size_words());
84+
85+
if (try_set_alloc_failure_gc(is_humongous)) {
86+
// Only report the first allocation failure
87+
log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation",
88+
byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize));
89+
}
90+
91+
// Forcefully report allocation failure
92+
heap->cancel_gc(GCCause::_shenandoah_allocation_failure_evac);
93+
}
94+
95+
void ShenandoahController::notify_alloc_failure_waiters() {
96+
_alloc_failure_gc.unset();
97+
_humongous_alloc_failure_gc.unset();
98+
MonitorLocker ml(&_alloc_failure_waiters_lock);
99+
ml.notify_all();
100+
}
101+
102+
bool ShenandoahController::try_set_alloc_failure_gc(bool is_humongous) {
103+
if (is_humongous) {
104+
_humongous_alloc_failure_gc.try_set();
105+
}
106+
return _alloc_failure_gc.try_set();
107+
}
108+
109+
bool ShenandoahController::is_alloc_failure_gc() {
110+
return _alloc_failure_gc.is_set();
111+
}
112+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#ifndef LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP
26+
#define LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP
27+
28+
#include "gc/shared/gcCause.hpp"
29+
#include "gc/shared/concurrentGCThread.hpp"
30+
#include "gc/shenandoah/shenandoahAllocRequest.hpp"
31+
#include "gc/shenandoah/shenandoahSharedVariables.hpp"
32+
33+
/**
34+
* This interface exposes methods necessary for the heap to interact
35+
* with the threads responsible for driving the collection cycle.
36+
*/
37+
class ShenandoahController: public ConcurrentGCThread {
38+
private:
39+
ShenandoahSharedFlag _graceful_shutdown;
40+
41+
shenandoah_padding(0);
42+
volatile size_t _allocs_seen;
43+
shenandoah_padding(1);
44+
volatile size_t _gc_id;
45+
shenandoah_padding(2);
46+
47+
protected:
48+
ShenandoahSharedFlag _alloc_failure_gc;
49+
ShenandoahSharedFlag _humongous_alloc_failure_gc;
50+
51+
// While we could have a single lock for these, it may risk unblocking
52+
// GC waiters when alloc failure GC cycle finishes. We want instead
53+
// to make complete explicit cycle for demanding customers.
54+
Monitor _alloc_failure_waiters_lock;
55+
Monitor _gc_waiters_lock;
56+
57+
public:
58+
ShenandoahController():
59+
ConcurrentGCThread(),
60+
_allocs_seen(0),
61+
_gc_id(0),
62+
_alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true),
63+
_gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true)
64+
{ }
65+
66+
// Request a collection cycle. This handles "explicit" gc requests
67+
// like System.gc and "implicit" gc requests, like metaspace oom.
68+
virtual void request_gc(GCCause::Cause cause) = 0;
69+
70+
// This cancels the collection cycle and has an option to block
71+
// until another cycle runs and clears the alloc failure gc flag.
72+
void handle_alloc_failure(ShenandoahAllocRequest& req, bool block);
73+
74+
// Invoked for allocation failures during evacuation. This cancels
75+
// the collection cycle without blocking.
76+
void handle_alloc_failure_evac(size_t words);
77+
78+
// Return true if setting the flag which indicates allocation failure succeeds.
79+
bool try_set_alloc_failure_gc(bool is_humongous);
80+
81+
// Notify threads waiting for GC to complete.
82+
void notify_alloc_failure_waiters();
83+
84+
// True if allocation failure flag has been set.
85+
bool is_alloc_failure_gc();
86+
87+
// This is called for every allocation. The control thread accumulates
88+
// this value when idle. During the gc cycle, the control resets it
89+
// and reports it to the pacer.
90+
void pacing_notify_alloc(size_t words);
91+
size_t reset_allocs_seen();
92+
93+
// These essentially allows to cancel a collection cycle for the
94+
// purpose of shutting down the JVM, without trying to start a degenerated
95+
// cycle.
96+
void prepare_for_graceful_shutdown();
97+
bool in_graceful_shutdown();
98+
99+
100+
// Returns the internal gc count used by the control thread. Probably
101+
// doesn't need to be exposed.
102+
size_t get_gc_id();
103+
void update_gc_id();
104+
};
105+
#endif //LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP

‎src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) {
955955
size_t original_count = shenandoah_policy()->full_gc_count();
956956
while (result == nullptr
957957
&& (get_gc_no_progress_count() == 0 || original_count == shenandoah_policy()->full_gc_count())) {
958-
control_thread()->handle_alloc_failure(req);
958+
control_thread()->handle_alloc_failure(req, true);
959959
result = allocate_memory_under_lock(req, in_new_region);
960960
}
961961

0 commit comments

Comments
 (0)
Please sign in to comment.