Skip to content

Commit

Permalink
8325671: Shenandoah: Introduce a ShenandoahGenerationType and templat…
Browse files Browse the repository at this point in the history
…ize certain marking closures with it

In support of eventually supporting a generational version of Shenandoah, we introduce a ShenandoahGenerationType enum which currently has a single NON_GEN value for Shenandoah. The generational extension of Shenandoah will introduce additional enum values when GenShen is integrated. These will be used to specialize certain marking closures via templatization, such that suitable variations of the marking (and in the future other) closures can be used for the generational and non-generational variants of the collector while minimizing interference between the two variants while maximizing code-sharing without affecting correctness or performance.

This ticket introduces the new enum type and templatizes certain existing marking closures.

In effect, this should be semantically a no-op for current (non-generational) Shenandoah and ideally completely performance-neutral (to be established via measurements).

**Testing:**
- [x] jtreg hotspot_gc
- [x] github actions
- [ ] codepipeline perf & stress: in progress

**Performance:**
- [ ] specjbb w/shenandoah
- [ ] codepipeline perf: in progress

Reviewed-by: kdnilsen, shade
  • Loading branch information
Y. Srinivas Ramakrishna committed Mar 2, 2024
1 parent f68a4b9 commit f62f2ad
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 53 deletions.
27 changes: 15 additions & 12 deletions src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "runtime/continuation.hpp"
#include "runtime/threads.hpp"

template <ShenandoahGenerationType GENERATION>
class ShenandoahConcurrentMarkingTask : public WorkerTask {
private:
ShenandoahConcurrentMark* const _cm;
Expand All @@ -61,8 +62,7 @@ class ShenandoahConcurrentMarkingTask : public WorkerTask {
ShenandoahReferenceProcessor* rp = heap->ref_processor();
assert(rp != nullptr, "need reference processor");
StringDedup::Requests requests;
_cm->mark_loop(worker_id, _terminator, rp,
true /*cancellable*/,
_cm->mark_loop(worker_id, _terminator, rp, GENERATION, true /*cancellable*/,
ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP,
&requests);
}
Expand Down Expand Up @@ -90,6 +90,7 @@ class ShenandoahSATBAndRemarkThreadsClosure : public ThreadClosure {
}
};

template <ShenandoahGenerationType GENERATION>
class ShenandoahFinalMarkingTask : public WorkerTask {
private:
ShenandoahConcurrentMark* _cm;
Expand All @@ -112,18 +113,17 @@ class ShenandoahFinalMarkingTask : public WorkerTask {
{
ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);

ShenandoahSATBBufferClosure cl(q);
ShenandoahSATBBufferClosure<GENERATION> cl(q);
SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set();
while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {}
assert(!heap->has_forwarded_objects(), "Not expected");

ShenandoahMarkRefsClosure mark_cl(q, rp);
ShenandoahMarkRefsClosure<GENERATION> mark_cl(q, rp);
ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set,
ShenandoahIUBarrier ? &mark_cl : nullptr);
Threads::possibly_parallel_threads_do(true /* is_par */, &tc);
}
_cm->mark_loop(worker_id, _terminator, rp,
false /*not cancellable*/,
_cm->mark_loop(worker_id, _terminator, rp, GENERATION, false /*not cancellable*/,
_dedup_string ? ENQUEUE_DEDUP : NO_DEDUP,
&requests);
assert(_cm->task_queues()->is_empty(), "Should be empty");
Expand All @@ -134,6 +134,7 @@ ShenandoahConcurrentMark::ShenandoahConcurrentMark() :
ShenandoahMark() {}

// Mark concurrent roots during concurrent phases
template <ShenandoahGenerationType GENERATION>
class ShenandoahMarkConcurrentRootsTask : public WorkerTask {
private:
SuspendibleThreadSetJoiner _sts_joiner;
Expand All @@ -149,7 +150,8 @@ class ShenandoahMarkConcurrentRootsTask : public WorkerTask {
void work(uint worker_id);
};

ShenandoahMarkConcurrentRootsTask::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
template <ShenandoahGenerationType GENERATION>
ShenandoahMarkConcurrentRootsTask<GENERATION>::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,
ShenandoahReferenceProcessor* rp,
ShenandoahPhaseTimings::Phase phase,
uint nworkers) :
Expand All @@ -160,10 +162,11 @@ ShenandoahMarkConcurrentRootsTask::ShenandoahMarkConcurrentRootsTask(ShenandoahO
assert(!ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected");
}

void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) {
template <ShenandoahGenerationType GENERATION>
void ShenandoahMarkConcurrentRootsTask<GENERATION>::work(uint worker_id) {
ShenandoahConcurrentWorkerSession worker_session(worker_id);
ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
ShenandoahMarkRefsClosure cl(q, _rp);
ShenandoahMarkRefsClosure<GENERATION> cl(q, _rp);
_root_scanner.roots_do(&cl, worker_id);
}

Expand All @@ -176,7 +179,7 @@ void ShenandoahConcurrentMark::mark_concurrent_roots() {
WorkerThreads* workers = heap->workers();
ShenandoahReferenceProcessor* rp = heap->ref_processor();
task_queues()->reserve(workers->active_workers());
ShenandoahMarkConcurrentRootsTask task(task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers());
ShenandoahMarkConcurrentRootsTask<NON_GEN> task(task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers());

workers->run_task(&task);
}
Expand Down Expand Up @@ -204,7 +207,7 @@ void ShenandoahConcurrentMark::concurrent_mark() {
ShenandoahFlushSATBHandshakeClosure flush_satb(qset);
for (uint flushes = 0; flushes < ShenandoahMaxSATBBufferFlushes; flushes++) {
TaskTerminator terminator(nworkers, task_queues());
ShenandoahConcurrentMarkingTask task(this, &terminator);
ShenandoahConcurrentMarkingTask<NON_GEN> task(this, &terminator);
workers->run_task(&task);

if (heap->cancelled_gc()) {
Expand Down Expand Up @@ -254,7 +257,7 @@ void ShenandoahConcurrentMark::finish_mark_work() {

StrongRootsScope scope(nworkers);
TaskTerminator terminator(nworkers, task_queues());
ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());
ShenandoahFinalMarkingTask<NON_GEN> task(this, &terminator, ShenandoahStringDedup::is_enabled());
heap->workers()->run_task(&task);

assert(task_queues()->is_empty(), "Should be empty");
Expand Down
7 changes: 5 additions & 2 deletions src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_HPP
#define SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_HPP

#include "gc/shenandoah/shenandoahGenerationType.hpp"
#include "gc/shenandoah/shenandoahMark.hpp"

template <ShenandoahGenerationType GENERATION>
class ShenandoahConcurrentMarkingTask;
template <ShenandoahGenerationType GENERATION>
class ShenandoahFinalMarkingTask;

class ShenandoahConcurrentMark: public ShenandoahMark {
friend class ShenandoahConcurrentMarkingTask;
friend class ShenandoahFinalMarkingTask;
template <ShenandoahGenerationType GENERATION> friend class ShenandoahConcurrentMarkingTask;
template <ShenandoahGenerationType GENERATION> friend class ShenandoahFinalMarkingTask;

public:
ShenandoahConcurrentMark();
Expand Down
42 changes: 42 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahGenerationType.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Amazon.com Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/

#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONTYPE_HPP
#define SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONTYPE_HPP

enum ShenandoahGenerationType {
NON_GEN // non-generational
};

inline const char* shenandoah_generation_name(ShenandoahGenerationType mode) {
switch (mode) {
case NON_GEN:
return "Non-Generational";
default:
ShouldNotReachHere();
return "Unknown";
}
}

#endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONTYPE_HPP
39 changes: 23 additions & 16 deletions src/hotspot/share/gc/shenandoah/shenandoahMark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void ShenandoahMark::clear() {
ShenandoahBarrierSet::satb_mark_queue_set().abandon_partial_marking();
}

template <bool CANCELLABLE, StringDedupMode STRING_DEDUP>
template <ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahReferenceProcessor *rp, StringDedup::Requests* const req) {
ShenandoahObjToScanQueue* q = get_queue(w);

Expand All @@ -76,48 +76,55 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe
// TODO: We can clean up this if we figure out how to do templated oop closures that
// play nice with specialized_oop_iterators.
if (heap->has_forwarded_objects()) {
using Closure = ShenandoahMarkUpdateRefsClosure;
using Closure = ShenandoahMarkUpdateRefsClosure<GENERATION>;
Closure cl(q, rp);
mark_loop_work<Closure, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req);
mark_loop_work<Closure, GENERATION, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req);
} else {
using Closure = ShenandoahMarkRefsClosure;
using Closure = ShenandoahMarkRefsClosure<GENERATION>;
Closure cl(q, rp);
mark_loop_work<Closure, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req);
mark_loop_work<Closure, GENERATION, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req);
}

heap->flush_liveness_cache(w);
}

template<bool CANCELLABLE, StringDedupMode STRING_DEDUP>
void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp,
bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req) {
ShenandoahGenerationType generation, StringDedup::Requests* const req) {
mark_loop_prework<NON_GEN, CANCELLABLE, STRING_DEDUP>(worker_id, terminator, rp, req);
}

void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp,
ShenandoahGenerationType generation, bool cancellable, StringDedupMode dedup_mode,
StringDedup::Requests* const req) {
if (cancellable) {
switch(dedup_mode) {
case NO_DEDUP:
mark_loop_prework<true, NO_DEDUP>(worker_id, terminator, rp, req);
mark_loop<true, NO_DEDUP>(worker_id, terminator, rp, generation, req);
break;
case ENQUEUE_DEDUP:
mark_loop_prework<true, ENQUEUE_DEDUP>(worker_id, terminator, rp, req);
mark_loop<true, ENQUEUE_DEDUP>(worker_id, terminator, rp, generation, req);
break;
case ALWAYS_DEDUP:
mark_loop_prework<true, ALWAYS_DEDUP>(worker_id, terminator, rp, req);
mark_loop<true, ALWAYS_DEDUP>(worker_id, terminator, rp, generation, req);
break;
}
} else {
switch(dedup_mode) {
case NO_DEDUP:
mark_loop_prework<false, NO_DEDUP>(worker_id, terminator, rp, req);
mark_loop<false, NO_DEDUP>(worker_id, terminator, rp, generation, req);
break;
case ENQUEUE_DEDUP:
mark_loop_prework<false, ENQUEUE_DEDUP>(worker_id, terminator, rp, req);
mark_loop<false, ENQUEUE_DEDUP>(worker_id, terminator, rp, generation, req);
break;
case ALWAYS_DEDUP:
mark_loop_prework<false, ALWAYS_DEDUP>(worker_id, terminator, rp, req);
mark_loop<false, ALWAYS_DEDUP>(worker_id, terminator, rp, generation, req);
break;
}
}
}

template <class T, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
template <class T, ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req) {
uintx stride = ShenandoahMarkLoopStride;

Expand Down Expand Up @@ -146,7 +153,7 @@ void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint w

for (uint i = 0; i < stride; i++) {
if (q->pop(t)) {
do_task<T, STRING_DEDUP>(q, cl, live_data, req, &t);
do_task<T, GENERATION, STRING_DEDUP>(q, cl, live_data, req, &t);
} else {
assert(q->is_empty(), "Must be empty");
q = queues->claim_next();
Expand All @@ -156,7 +163,7 @@ void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint w
}
q = get_queue(worker_id);

ShenandoahSATBBufferClosure drain_satb(q);
ShenandoahSATBBufferClosure<GENERATION> drain_satb(q);
SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set();

/*
Expand All @@ -175,7 +182,7 @@ void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint w
for (uint i = 0; i < stride; i++) {
if (q->pop(t) ||
queues->steal(worker_id, t)) {
do_task<T, STRING_DEDUP>(q, cl, live_data, req, &t);
do_task<T, GENERATION, STRING_DEDUP>(q, cl, live_data, req, &t);
work++;
} else {
break;
Expand Down
15 changes: 10 additions & 5 deletions src/hotspot/share/gc/shenandoah/shenandoahMark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "gc/shared/stringdedup/stringDedup.hpp"
#include "gc/shared/taskTerminator.hpp"
#include "gc/shenandoah/shenandoahGenerationType.hpp"
#include "gc/shenandoah/shenandoahHeap.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.hpp"

Expand All @@ -50,7 +51,7 @@ class ShenandoahMark: public StackObj {
ShenandoahMark();

public:
template<class T>
template<class T, ShenandoahGenerationType GENERATION>
static inline void mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak);

static void clear();
Expand All @@ -65,7 +66,7 @@ class ShenandoahMark: public StackObj {

// ---------- Marking loop and tasks
private:
template <class T, StringDedupMode STRING_DEDUP>
template <class T, ShenandoahGenerationType GENERATION, StringDedupMode STRING_DEDUP>
inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task);

template <class T>
Expand All @@ -74,19 +75,23 @@ class ShenandoahMark: public StackObj {
template <class T>
inline void do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop array, int chunk, int pow, bool weak);

template <ShenandoahGenerationType GENERATION>
inline void count_liveness(ShenandoahLiveData* live_data, oop obj);

template <class T, bool CANCELLABLE,StringDedupMode STRING_DEDUP>
template <class T, ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req);

template <bool CANCELLABLE, StringDedupMode STRING_DEDUP>
template <ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
void mark_loop_prework(uint worker_id, TaskTerminator *terminator, ShenandoahReferenceProcessor *rp, StringDedup::Requests* const req);

template <StringDedupMode STRING_DEDUP>
inline void dedup_string(oop obj, StringDedup::Requests* const req);
protected:
template<bool CANCELLABLE, StringDedupMode STRING_DEDUP>
void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp,
bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req);
ShenandoahGenerationType generation, StringDedup::Requests* const req);
void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp,
ShenandoahGenerationType generation, bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req);
};

#endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARK_HPP
10 changes: 6 additions & 4 deletions src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) {
}
}

template <class T, StringDedupMode STRING_DEDUP>
template <class T, ShenandoahGenerationType GENERATION, StringDedupMode STRING_DEDUP>
void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task) {
oop obj = task->obj();

Expand Down Expand Up @@ -95,14 +95,15 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD
// Avoid double-counting objects that are visited twice due to upgrade
// from final- to strong mark.
if (task->count_liveness()) {
count_liveness(live_data, obj);
count_liveness<GENERATION>(live_data, obj);
}
} else {
// Case 4: Array chunk, has sensible chunk id. Process it.
do_chunked_array<T>(q, cl, obj, task->chunk(), task->pow(), weak);
}
}

template <ShenandoahGenerationType GENERATION>
inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj) {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
size_t region_idx = heap->heap_region_index_containing(obj);
Expand Down Expand Up @@ -230,6 +231,7 @@ inline void ShenandoahMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl,
array->oop_iterate_range(cl, from, to);
}

template <ShenandoahGenerationType GENERATION>
class ShenandoahSATBBufferClosure : public SATBBufferClosure {
private:
ShenandoahObjToScanQueue* _queue;
Expand All @@ -247,12 +249,12 @@ class ShenandoahSATBBufferClosure : public SATBBufferClosure {
assert(size == 0 || !_heap->has_forwarded_objects(), "Forwarded objects are not expected here");
for (size_t i = 0; i < size; ++i) {
oop *p = (oop *) &buffer[i];
ShenandoahMark::mark_through_ref<oop>(p, _queue, _mark_context, false);
ShenandoahMark::mark_through_ref<oop, GENERATION>(p, _queue, _mark_context, false);
}
}
};

template<class T>
template<class T, ShenandoahGenerationType GENERATION>
inline void ShenandoahMark::mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak) {
T o = RawAccess<>::oop_load(p);
if (!CompressedOops::is_null(o)) {
Expand Down

1 comment on commit f62f2ad

@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.