Skip to content

Commit a6ce6a5

Browse files
Lin Zangkstefanj
authored andcommitted
8252103: Parallel heap inspection for ParallelScavengeHeap
Reviewed-by: sjohanss, tschatzl
1 parent cdef186 commit a6ce6a5

File tree

4 files changed

+111
-0
lines changed

4 files changed

+111
-0
lines changed

src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,71 @@ void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) {
539539
old_gen()->object_iterate(cl);
540540
}
541541

542+
// The HeapBlockClaimer is used during parallel iteration over the heap,
543+
// allowing workers to claim heap areas ("blocks"), gaining exclusive rights to these.
544+
// The eden and survivor spaces are treated as single blocks as it is hard to divide
545+
// these spaces.
546+
// The old space is divided into fixed-size blocks.
547+
class HeapBlockClaimer : public StackObj {
548+
size_t _claimed_index;
549+
550+
public:
551+
static const size_t InvalidIndex = SIZE_MAX;
552+
static const size_t EdenIndex = 0;
553+
static const size_t SurvivorIndex = 1;
554+
static const size_t NumNonOldGenClaims = 2;
555+
556+
HeapBlockClaimer() : _claimed_index(EdenIndex) { }
557+
// Claim the block and get the block index.
558+
size_t claim_and_get_block() {
559+
size_t block_index;
560+
block_index = Atomic::fetch_and_add(&_claimed_index, 1u);
561+
562+
PSOldGen* old_gen = ParallelScavengeHeap::heap()->old_gen();
563+
size_t num_claims = old_gen->num_iterable_blocks() + NumNonOldGenClaims;
564+
565+
return block_index < num_claims ? block_index : InvalidIndex;
566+
}
567+
};
568+
569+
void ParallelScavengeHeap::object_iterate_parallel(ObjectClosure* cl,
570+
HeapBlockClaimer* claimer) {
571+
size_t block_index = claimer->claim_and_get_block();
572+
// Iterate until all blocks are claimed
573+
if (block_index == HeapBlockClaimer::EdenIndex) {
574+
young_gen()->eden_space()->object_iterate(cl);
575+
block_index = claimer->claim_and_get_block();
576+
}
577+
if (block_index == HeapBlockClaimer::SurvivorIndex) {
578+
young_gen()->from_space()->object_iterate(cl);
579+
young_gen()->to_space()->object_iterate(cl);
580+
block_index = claimer->claim_and_get_block();
581+
}
582+
while (block_index != HeapBlockClaimer::InvalidIndex) {
583+
old_gen()->object_iterate_block(cl, block_index - HeapBlockClaimer::NumNonOldGenClaims);
584+
block_index = claimer->claim_and_get_block();
585+
}
586+
}
587+
588+
class PSScavengeParallelObjectIterator : public ParallelObjectIterator {
589+
private:
590+
ParallelScavengeHeap* _heap;
591+
HeapBlockClaimer _claimer;
592+
593+
public:
594+
PSScavengeParallelObjectIterator() :
595+
_heap(ParallelScavengeHeap::heap()),
596+
_claimer() {}
597+
598+
virtual void object_iterate(ObjectClosure* cl, uint worker_id) {
599+
_heap->object_iterate_parallel(cl, &_claimer);
600+
}
601+
};
602+
603+
ParallelObjectIterator* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) {
604+
return new PSScavengeParallelObjectIterator();
605+
}
606+
542607
HeapWord* ParallelScavengeHeap::block_start(const void* addr) const {
543608
if (young_gen()->is_in_reserved(addr)) {
544609
assert(young_gen()->is_in(addr),

src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
class AdjoiningGenerations;
4747
class GCHeapSummary;
48+
class HeapBlockClaimer;
4849
class MemoryManager;
4950
class MemoryPool;
5051
class PSAdaptiveSizePolicy;
@@ -207,6 +208,8 @@ class ParallelScavengeHeap : public CollectedHeap {
207208
size_t unsafe_max_tlab_alloc(Thread* thr) const;
208209

209210
void object_iterate(ObjectClosure* cl);
211+
void object_iterate_parallel(ObjectClosure* cl, HeapBlockClaimer* claimer);
212+
virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num);
210213

211214
HeapWord* block_start(const void* addr) const;
212215
bool block_is_obj(const HeapWord* addr) const;

src/hotspot/share/gc/parallel/psOldGen.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,38 @@ HeapWord* PSOldGen::allocate(size_t word_size) {
173173
return res;
174174
}
175175

176+
size_t PSOldGen::num_iterable_blocks() const {
177+
return (object_space()->used_in_bytes() + IterateBlockSize - 1) / IterateBlockSize;
178+
}
179+
180+
void PSOldGen::object_iterate_block(ObjectClosure* cl, size_t block_index) {
181+
size_t block_word_size = IterateBlockSize / HeapWordSize;
182+
assert((block_word_size % (ObjectStartArray::block_size)) == 0,
183+
"Block size not a multiple of start_array block");
184+
185+
MutableSpace *space = object_space();
186+
187+
HeapWord* begin = space->bottom() + block_index * block_word_size;
188+
HeapWord* end = MIN2(space->top(), begin + block_word_size);
189+
190+
if (!start_array()->object_starts_in_range(begin, end)) {
191+
return;
192+
}
193+
194+
// Get object starting at or reaching into this block.
195+
HeapWord* start = start_array()->object_start(begin);
196+
if (start < begin) {
197+
start += oop(start)->size();
198+
}
199+
assert(start >= begin,
200+
"Object address" PTR_FORMAT " must be larger or equal to block address at " PTR_FORMAT,
201+
p2i(start), p2i(begin));
202+
// Iterate all objects until the end.
203+
for (HeapWord* p = start; p < end; p += oop(p)->size()) {
204+
cl->do_object(oop(p));
205+
}
206+
}
207+
176208
HeapWord* PSOldGen::expand_and_allocate(size_t word_size) {
177209
expand(word_size*HeapWordSize);
178210
if (GCExpandToAllocateDelayMillis > 0) {

src/hotspot/share/gc/parallel/psOldGen.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class PSOldGen : public CHeapObj<mtGC> {
5252
const size_t _min_gen_size;
5353
const size_t _max_gen_size;
5454

55+
// Block size for parallel iteration
56+
static const size_t IterateBlockSize = 1024 * 1024;
57+
5558
#ifdef ASSERT
5659
void assert_block_in_covered_region(MemRegion new_memregion) {
5760
// Explictly capture current covered_region in a local
@@ -163,6 +166,14 @@ class PSOldGen : public CHeapObj<mtGC> {
163166
void oop_iterate(OopIterateClosure* cl) { object_space()->oop_iterate(cl); }
164167
void object_iterate(ObjectClosure* cl) { object_space()->object_iterate(cl); }
165168

169+
// Number of blocks to be iterated over in the used part of old gen.
170+
size_t num_iterable_blocks() const;
171+
// Iterate the objects starting in block block_index within [bottom, top) of the
172+
// old gen. The object just reaching into this block is not iterated over.
173+
// A block is an evenly sized non-overlapping part of the old gen of
174+
// IterateBlockSize bytes.
175+
void object_iterate_block(ObjectClosure* cl, size_t block_index);
176+
166177
// Debugging - do not use for time critical operations
167178
void print() const;
168179
virtual void print_on(outputStream* st) const;

0 commit comments

Comments
 (0)