Skip to content
Permalink
Browse files

8242365: Shenandoah: use uint16_t instead of jushort for liveness cache

Reviewed-by: rkennke
  • Loading branch information
shipilev committed Apr 8, 2020
1 parent 7b870e7 commit 64aee56add64e908c994c4b9c67e3299208ee699
@@ -817,7 +817,7 @@ void ShenandoahConcurrentMark::mark_loop_prework(uint w, TaskTerminator *t, Refe
bool strdedup) {
ShenandoahObjToScanQueue* q = get_queue(w);

jushort* ld = _heap->get_liveness_cache(w);
ShenandoahLiveData* ld = _heap->get_liveness_cache(w);

// TODO: We can clean up this if we figure out how to do templated oop closures that
// play nice with specialized_oop_iterators.
@@ -863,7 +863,7 @@ void ShenandoahConcurrentMark::mark_loop_prework(uint w, TaskTerminator *t, Refe
}

template <class T, bool CANCELLABLE>
void ShenandoahConcurrentMark::mark_loop_work(T* cl, jushort* live_data, uint worker_id, TaskTerminator *terminator) {
void ShenandoahConcurrentMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator) {
uintx stride = ShenandoahMarkLoopStride;

ShenandoahHeap* heap = ShenandoahHeap::heap();
@@ -46,18 +46,18 @@ class ShenandoahConcurrentMark: public CHeapObj<mtGC> {
//
private:
template <class T>
inline void do_task(ShenandoahObjToScanQueue* q, T* cl, jushort* live_data, ShenandoahMarkTask* task);
inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, ShenandoahMarkTask* task);

template <class T>
inline void do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop array);

template <class T>
inline void do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop array, int chunk, int pow);

inline void count_liveness(jushort* live_data, oop obj);
inline void count_liveness(ShenandoahLiveData* live_data, oop obj);

template <class T, bool CANCELLABLE>
void mark_loop_work(T* cl, jushort* live_data, uint worker_id, TaskTerminator *t);
void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t);

template <bool CANCELLABLE>
void mark_loop_prework(uint worker_id, TaskTerminator *terminator, ReferenceProcessor *rp, bool strdedup);
@@ -37,7 +37,7 @@
#include "runtime/prefetch.inline.hpp"

template <class T>
void ShenandoahConcurrentMark::do_task(ShenandoahObjToScanQueue* q, T* cl, jushort* live_data, ShenandoahMarkTask* task) {
void ShenandoahConcurrentMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, ShenandoahMarkTask* task) {
oop obj = task->obj();

shenandoah_assert_not_forwarded(NULL, obj);
@@ -67,23 +67,22 @@ void ShenandoahConcurrentMark::do_task(ShenandoahObjToScanQueue* q, T* cl, jusho
}
}

inline void ShenandoahConcurrentMark::count_liveness(jushort* live_data, oop obj) {
inline void ShenandoahConcurrentMark::count_liveness(ShenandoahLiveData* live_data, oop obj) {
size_t region_idx = _heap->heap_region_index_containing(obj);
ShenandoahHeapRegion* region = _heap->get_region(region_idx);
size_t size = obj->size();

if (!region->is_humongous_start()) {
assert(!region->is_humongous(), "Cannot have continuations here");
size_t max = (1 << (sizeof(jushort) * 8)) - 1;
jushort cur = live_data[region_idx];
ShenandoahLiveData cur = live_data[region_idx];
size_t new_val = size + cur;
if (new_val >= max) {
if (new_val >= SHENANDOAH_LIVEDATA_MAX) {
// overflow, flush to region data
region->increase_live_data_gc_words(new_val);
live_data[region_idx] = 0;
} else {
// still good, remember in locals
live_data[region_idx] = (jushort) new_val;
live_data[region_idx] = (ShenandoahLiveData) new_val;
}
} else {
shenandoah_assert_in_correct_region(NULL, obj);
@@ -357,10 +357,10 @@ jint ShenandoahHeap::initialize() {
// Initialize the rest of GC subsystems
//

_liveness_cache = NEW_C_HEAP_ARRAY(jushort*, _max_workers, mtGC);
_liveness_cache = NEW_C_HEAP_ARRAY(ShenandoahLiveData*, _max_workers, mtGC);
for (uint worker = 0; worker < _max_workers; worker++) {
_liveness_cache[worker] = NEW_C_HEAP_ARRAY(jushort, _num_regions, mtGC);
Copy::fill_to_bytes(_liveness_cache[worker], _num_regions * sizeof(jushort));
_liveness_cache[worker] = NEW_C_HEAP_ARRAY(ShenandoahLiveData, _num_regions, mtGC);
Copy::fill_to_bytes(_liveness_cache[worker], _num_regions * sizeof(ShenandoahLiveData));
}

// There should probably be Shenandoah-specific options for these,
@@ -3008,7 +3008,7 @@ const char* ShenandoahHeap::degen_event_message(ShenandoahDegenPoint point) cons
}
}

jushort* ShenandoahHeap::get_liveness_cache(uint worker_id) {
ShenandoahLiveData* ShenandoahHeap::get_liveness_cache(uint worker_id) {
#ifdef ASSERT
assert(_liveness_cache != NULL, "sanity");
assert(worker_id < _max_workers, "sanity");
@@ -3022,9 +3022,9 @@ jushort* ShenandoahHeap::get_liveness_cache(uint worker_id) {
void ShenandoahHeap::flush_liveness_cache(uint worker_id) {
assert(worker_id < _max_workers, "sanity");
assert(_liveness_cache != NULL, "sanity");
jushort* ld = _liveness_cache[worker_id];
ShenandoahLiveData* ld = _liveness_cache[worker_id];
for (uint i = 0; i < num_regions(); i++) {
jushort live = ld[i];
ShenandoahLiveData live = ld[i];
if (live > 0) {
ShenandoahHeapRegion* r = get_region(i);
r->increase_live_data_gc_words(live);
@@ -62,6 +62,16 @@ class ShenandoahVerifier;
class ShenandoahWorkGang;
class VMStructs;

// Used for buffering per-region liveness data.
// Needed since ShenandoahHeapRegion uses atomics to update liveness.
// The ShenandoahHeap array has max-workers elements, each of which is an array of
// uint16_t * max_regions. The choice of uint16_t is not accidental:
// there is a tradeoff between static/dynamic footprint that translates
// into cache pressure (which is already high during marking), and
// too many atomic updates. uint32_t is too large, uint8_t is too small.
typedef uint16_t ShenandoahLiveData;
#define SHENANDOAH_LIVEDATA_MAX ((ShenandoahLiveData)-1)

class ShenandoahRegionIterator : public StackObj {
private:
ShenandoahHeap* _heap;
@@ -613,15 +623,7 @@ class ShenandoahHeap : public CollectedHeap {
bool _bitmap_region_special;
bool _aux_bitmap_region_special;

// Used for buffering per-region liveness data.
// Needed since ShenandoahHeapRegion uses atomics to update liveness.
//
// The array has max-workers elements, each of which is an array of
// jushort * max_regions. The choice of jushort is not accidental:
// there is a tradeoff between static/dynamic footprint that translates
// into cache pressure (which is already high during marking), and
// too many atomic updates. size_t/jint is too large, jbyte is too small.
jushort** _liveness_cache;
ShenandoahLiveData** _liveness_cache;

public:
inline ShenandoahMarkingContext* complete_marking_context() const;
@@ -651,7 +653,7 @@ class ShenandoahHeap : public CollectedHeap {
bool is_bitmap_slice_committed(ShenandoahHeapRegion* r, bool skip_self = false);

// Liveness caching support
jushort* get_liveness_cache(uint worker_id);
ShenandoahLiveData* get_liveness_cache(uint worker_id);
void flush_liveness_cache(uint worker_id);

// ---------- Evacuation support

0 comments on commit 64aee56

Please sign in to comment.