Skip to content

Commit 6e07965

Browse files
author
Xiaolong Peng
committed
8385606: Shenandoah: Remove PLAB card-table alignment and per-object register_object during old-gen allocation
Reviewed-by: wkemper, kdnilsen
1 parent b66dcc9 commit 6e07965

8 files changed

Lines changed: 20 additions & 195 deletions

src/hotspot/share/gc/shenandoah/shenandoahAffiliation.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHAFFILIATION_HPP
2626
#define SHARE_GC_SHENANDOAH_SHENANDOAHAFFILIATION_HPP
2727

28+
#include "utilities/debug.hpp"
29+
2830
enum ShenandoahAffiliation {
2931
FREE,
3032
YOUNG_GENERATION,

src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp

Lines changed: 10 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,55 +1478,6 @@ HeapWord* ShenandoahFreeSet::try_allocate_from_mutator(ShenandoahAllocRequest& r
14781478
return nullptr;
14791479
}
14801480

1481-
// This work method takes an argument corresponding to the number of bytes
1482-
// free in a region, and returns the largest amount in heapwords that can be allocated
1483-
// such that both of the following conditions are satisfied:
1484-
//
1485-
// 1. it is a multiple of card size
1486-
// 2. any remaining shard may be filled with a filler object
1487-
//
1488-
// The idea is that the allocation starts and ends at card boundaries. Because
1489-
// a region ('s end) is card-aligned, the remainder shard that must be filled is
1490-
// at the start of the free space.
1491-
//
1492-
// This is merely a helper method to use for the purpose of such a calculation.
1493-
size_t ShenandoahFreeSet::get_usable_free_words(size_t free_bytes) const {
1494-
// e.g. card_size is 512, card_shift is 9, min_fill_size() is 8
1495-
// free is 514
1496-
// usable_free is 512, which is decreased to 0
1497-
size_t usable_free = (free_bytes / CardTable::card_size()) << CardTable::card_shift();
1498-
assert(usable_free <= free_bytes, "Sanity check");
1499-
if ((free_bytes != usable_free) && (free_bytes - usable_free < ShenandoahHeap::min_fill_size() * HeapWordSize)) {
1500-
// After aligning to card multiples, the remainder would be smaller than
1501-
// the minimum filler object, so we'll need to take away another card's
1502-
// worth to construct a filler object.
1503-
if (usable_free >= CardTable::card_size()) {
1504-
usable_free -= CardTable::card_size();
1505-
} else {
1506-
assert(usable_free == 0, "usable_free is a multiple of card_size and card_size > min_fill_size");
1507-
}
1508-
}
1509-
1510-
return usable_free / HeapWordSize;
1511-
}
1512-
1513-
// Given a size argument, which is a multiple of card size, a request struct
1514-
// for a PLAB, and an old region, return a pointer to the allocated space for
1515-
// a PLAB which is card-aligned and where any remaining shard in the region
1516-
// has been suitably filled by a filler object.
1517-
// It is assumed (and assertion-checked) that such an allocation is always possible.
1518-
HeapWord* ShenandoahFreeSet::allocate_aligned_plab(size_t size, ShenandoahAllocRequest& req, ShenandoahHeapRegion* r) {
1519-
assert(_heap->mode()->is_generational(), "PLABs are only for generational mode");
1520-
assert(r->is_old(), "All PLABs reside in old-gen");
1521-
assert(!req.is_mutator_alloc(), "PLABs should not be allocated by mutators.");
1522-
assert(is_aligned(size, CardTable::card_size_in_words()), "Align by design");
1523-
1524-
HeapWord* result = r->allocate_aligned(size, req, CardTable::card_size());
1525-
assert(result != nullptr, "Allocation cannot fail");
1526-
assert(r->top() <= r->end(), "Allocation cannot span end of region");
1527-
assert(is_aligned(result, CardTable::card_size_in_words()), "Align by design");
1528-
return result;
1529-
}
15301481

15311482
HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, ShenandoahAllocRequest& req, bool& in_new_region) {
15321483
assert (has_alloc_capacity(r), "Performance: should avoid full regions on this path: %zu", r->index());
@@ -1578,44 +1529,17 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah
15781529
// req.size() is in words, r->free() is in bytes.
15791530
if (req.is_lab_alloc()) {
15801531
size_t adjusted_size = req.size();
1581-
size_t free = r->free(); // free represents bytes available within region r
1582-
if (req.is_old()) {
1583-
// This is a PLAB allocation(lab alloc in old gen)
1584-
assert(_heap->mode()->is_generational(), "PLABs are only for generational mode");
1585-
assert(_partitions.in_free_set(ShenandoahFreeSetPartitionId::OldCollector, r->index()),
1586-
"PLABS must be allocated in old_collector_free regions");
1587-
1588-
// Need to assure that plabs are aligned on multiple of card region
1589-
// Convert free from unaligned bytes to aligned number of words
1590-
size_t usable_free = get_usable_free_words(free);
1591-
if (adjusted_size > usable_free) {
1592-
adjusted_size = usable_free;
1593-
}
1594-
adjusted_size = align_down(adjusted_size, CardTable::card_size_in_words());
1595-
if (adjusted_size >= req.min_size()) {
1596-
result = allocate_aligned_plab(adjusted_size, req, r);
1597-
assert(result != nullptr, "allocate must succeed");
1598-
req.set_actual_size(adjusted_size);
1599-
} else {
1600-
// Otherwise, leave result == nullptr because the adjusted size is smaller than min size.
1601-
log_trace(gc, free)("Failed to shrink PLAB request (%zu) in region %zu to %zu"
1602-
" because min_size() is %zu", req.size(), r->index(), adjusted_size, req.min_size());
1603-
}
1532+
size_t free = align_down(r->free() >> LogHeapWordSize, MinObjAlignment);
1533+
if (adjusted_size > free) {
1534+
adjusted_size = free;
1535+
}
1536+
if (adjusted_size >= req.min_size()) {
1537+
result = r->allocate(adjusted_size, req);
1538+
assert (result != nullptr, "Allocation must succeed: free %zu, actual %zu", free, adjusted_size);
1539+
req.set_actual_size(adjusted_size);
16041540
} else {
1605-
// This is a GCLAB or a TLAB allocation
1606-
// Convert free from unaligned bytes to aligned number of words
1607-
free = align_down(free >> LogHeapWordSize, MinObjAlignment);
1608-
if (adjusted_size > free) {
1609-
adjusted_size = free;
1610-
}
1611-
if (adjusted_size >= req.min_size()) {
1612-
result = r->allocate(adjusted_size, req);
1613-
assert (result != nullptr, "Allocation must succeed: free %zu, actual %zu", free, adjusted_size);
1614-
req.set_actual_size(adjusted_size);
1615-
} else {
1616-
log_trace(gc, free)("Failed to shrink TLAB or GCLAB request (%zu) in region %zu to %zu"
1617-
" because min_size() is %zu", req.size(), r->index(), adjusted_size, req.min_size());
1618-
}
1541+
log_trace(gc, free)("Failed to shrink LAB request (%zu) in region %zu to %zu"
1542+
" because min_size() is %zu", req.size(), r->index(), adjusted_size, req.min_size());
16191543
}
16201544
} else {
16211545
size_t size = req.size();

src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,6 @@ using idx_t = ShenandoahSimpleBitMap::idx_t;
453453
// locks will acquire them in the same order: first the global heap lock and then the rebuild lock.
454454
ShenandoahRebuildLock _rebuild_lock;
455455

456-
HeapWord* allocate_aligned_plab(size_t size, ShenandoahAllocRequest& req, ShenandoahHeapRegion* r);
457456

458457
size_t _total_humongous_waste;
459458

@@ -639,7 +638,6 @@ using idx_t = ShenandoahSimpleBitMap::idx_t;
639638

640639
// Determine whether we prefer to allocate from left to right or from right to left within the OldCollector free-set.
641640
void establish_old_collector_alloc_bias();
642-
size_t get_usable_free_words(size_t free_bytes) const;
643641

644642
void reduce_young_reserve(size_t adjusted_young_reserve, size_t requested_young_reserve);
645643
void reduce_old_reserve(size_t adjusted_old_reserve, size_t requested_old_reserve);

src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,11 @@ class ShenandoahGenerationalInitLogger : public ShenandoahInitLogger {
6565
};
6666

6767
size_t ShenandoahGenerationalHeap::calculate_min_plab() {
68-
return align_up(PLAB::min_size(), CardTable::card_size_in_words());
68+
return PLAB::min_size();
6969
}
7070

7171
size_t ShenandoahGenerationalHeap::calculate_max_plab() {
72-
size_t MaxTLABSizeWords = ShenandoahHeapRegion::max_tlab_size_words();
73-
return align_down(MaxTLABSizeWords, CardTable::card_size_in_words());
72+
return ShenandoahHeapRegion::max_tlab_size_words();
7473
}
7574

7675
// Returns size in bytes
@@ -86,8 +85,6 @@ ShenandoahGenerationalHeap::ShenandoahGenerationalHeap(ShenandoahCollectorPolicy
8685
_regulator_thread(nullptr),
8786
_young_gen_memory_pool(nullptr),
8887
_old_gen_memory_pool(nullptr) {
89-
assert(is_aligned(_min_plab_size, CardTable::card_size_in_words()), "min_plab_size must be aligned");
90-
assert(is_aligned(_max_plab_size, CardTable::card_size_in_words()), "max_plab_size must be aligned");
9188
}
9289

9390
void ShenandoahGenerationalHeap::initialize_generations() {

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

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,6 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req
10351035
// memory.
10361036
HeapWord* result = _free_set->allocate(req, in_new_region);
10371037

1038-
// Record the plab configuration for this result and register the object.
10391038
if (result != nullptr) {
10401039
if (req.is_mutator_alloc()) {
10411040
_alloc_rate.allocated((req.actual_size() + req.waste()) * HeapWordSize);
@@ -1044,33 +1043,10 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req
10441043
if (req.is_old()) {
10451044
if (req.is_lab_alloc()) {
10461045
old_generation()->configure_plab_for_current_thread(req);
1047-
} else {
1048-
// Register the newly allocated object while we're holding the global lock since there's no synchronization
1049-
// built in to the implementation of register_object(). There are potential races when multiple independent
1050-
// threads are allocating objects, some of which might span the same card region. For example, consider
1051-
// a card table's memory region within which three objects are being allocated by three different threads:
1052-
//
1053-
// objects being "concurrently" allocated:
1054-
// [-----a------][-----b-----][--------------c------------------]
1055-
// [---- card table memory range --------------]
1056-
//
1057-
// Before any objects are allocated, this card's memory range holds no objects. Note that allocation of object a
1058-
// wants to set the starts-object, first-start, and last-start attributes of the preceding card region.
1059-
// Allocation of object b wants to set the starts-object, first-start, and last-start attributes of this card region.
1060-
// Allocation of object c also wants to set the starts-object, first-start, and last-start attributes of this
1061-
// card region.
1062-
//
1063-
// The thread allocating b and the thread allocating c can "race" in various ways, resulting in confusion, such as
1064-
// last-start representing object b while first-start represents object c. This is why we need to require all
1065-
// register_object() invocations to be "mutually exclusive" with respect to each card's memory range.
1066-
old_generation()->card_scan()->register_object(result);
1067-
1068-
if (req.is_promotion()) {
1069-
// Shared promotion.
1070-
const size_t actual_size = req.actual_size() * HeapWordSize;
1071-
log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size);
1072-
old_generation()->expend_promoted(actual_size);
1073-
}
1046+
} else if (req.is_promotion()) {
1047+
const size_t actual_size = req.actual_size() * HeapWordSize;
1048+
log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size);
1049+
old_generation()->expend_promoted(actual_size);
10741050
}
10751051
}
10761052
}

src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,12 +386,6 @@ class ShenandoahHeapRegion {
386386
HeapWord* get_top_at_evac_start() const { return _top_at_evac_start; }
387387
void record_top_at_evac_start() { _top_at_evac_start = _top; }
388388

389-
// If next available memory is not aligned on address that is multiple of alignment, fill the empty space
390-
// so that returned object is aligned on an address that is a multiple of alignment_in_bytes. Requested
391-
// size is in words. It is assumed that this->is_old(). A pad object is allocated, filled, and registered
392-
// if necessary to assure the new allocation is properly aligned. Return nullptr if memory is not available.
393-
inline HeapWord* allocate_aligned(size_t word_size, ShenandoahAllocRequest &req, size_t alignment_in_bytes);
394-
395389
// Allocation (return nullptr if full)
396390
inline HeapWord* allocate(size_t word_size, const ShenandoahAllocRequest& req);
397391

src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -33,59 +33,6 @@
3333
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
3434
#include "gc/shenandoah/shenandoahOldGeneration.hpp"
3535

36-
HeapWord* ShenandoahHeapRegion::allocate_aligned(size_t size, ShenandoahAllocRequest &req, size_t alignment_in_bytes) {
37-
shenandoah_assert_heaplocked_or_safepoint();
38-
assert(req.is_lab_alloc(), "allocate_aligned() only applies to LAB allocations");
39-
assert(is_object_aligned(size), "alloc size breaks alignment: %zu", size);
40-
assert(is_old(), "aligned allocations are only taken from OLD regions to support PLABs");
41-
assert(is_aligned(alignment_in_bytes, HeapWordSize), "Expect heap word alignment");
42-
43-
HeapWord* orig_top = top();
44-
size_t alignment_in_words = alignment_in_bytes / HeapWordSize;
45-
46-
// unalignment_words is the amount by which current top() exceeds the desired alignment point. We subtract this amount
47-
// from alignment_in_words to determine padding required to next alignment point.
48-
49-
HeapWord* aligned_obj = (HeapWord*) align_up(orig_top, alignment_in_bytes);
50-
size_t pad_words = aligned_obj - orig_top;
51-
if ((pad_words > 0) && (pad_words < ShenandoahHeap::min_fill_size())) {
52-
pad_words += alignment_in_words;
53-
aligned_obj += alignment_in_words;
54-
}
55-
56-
if (pointer_delta(end(), aligned_obj) < size) {
57-
// Shrink size to fit within available space and align it
58-
size = pointer_delta(end(), aligned_obj);
59-
size = align_down(size, alignment_in_words);
60-
}
61-
62-
// Both originally requested size and adjusted size must be properly aligned
63-
assert (is_aligned(size, alignment_in_words), "Size must be multiple of alignment constraint");
64-
if (size >= req.min_size()) {
65-
// Even if req.min_size() may not be a multiple of card size, we know that size is.
66-
if (pad_words > 0) {
67-
assert(pad_words >= ShenandoahHeap::min_fill_size(), "pad_words expanded above to meet size constraint");
68-
ShenandoahHeap::fill_with_object(orig_top, pad_words);
69-
ShenandoahGenerationalHeap::heap()->old_generation()->card_scan()->register_object(orig_top);
70-
}
71-
72-
make_regular_allocation(req.affiliation());
73-
adjust_alloc_metadata(req, size);
74-
75-
HeapWord* new_top = aligned_obj + size;
76-
assert(new_top <= end(), "PLAB cannot span end of heap region");
77-
set_top(new_top);
78-
// We do not req.set_actual_size() here. The caller sets it.
79-
req.set_waste(pad_words);
80-
assert(is_object_aligned(new_top), "new top breaks alignment: " PTR_FORMAT, p2i(new_top));
81-
assert(is_aligned(aligned_obj, alignment_in_bytes), "obj is not aligned: " PTR_FORMAT, p2i(aligned_obj));
82-
return aligned_obj;
83-
} else {
84-
// The aligned size that fits in this region is smaller than min_size, so don't align top and don't allocate. Return failure.
85-
return nullptr;
86-
}
87-
}
88-
8936
HeapWord* ShenandoahHeapRegion::allocate_fill(size_t size) {
9037
shenandoah_assert_heaplocked_or_safepoint();
9138
assert(is_object_aligned(size), "alloc size breaks alignment: %zu", size);

src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
*
2323
*/
2424

25-
#include "gc/shared/cardTable.hpp"
2625
#include "gc/shenandoah/shenandoahAllocRequest.hpp"
2726
#include "gc/shenandoah/shenandoahGenerationalHeap.hpp"
2827
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
@@ -43,7 +42,7 @@ ShenandoahPLAB::ShenandoahPLAB() :
4342
_allows_promotion(false),
4443
_retries_enabled(false),
4544
_heap(ShenandoahGenerationalHeap::heap()) {
46-
_plab = new PLAB(align_up(PLAB::min_size(), CardTable::card_size_in_words()));
45+
_plab = new PLAB(PLAB::min_size());
4746
}
4847

4948
ShenandoahPLAB::~ShenandoahPLAB() {
@@ -93,10 +92,8 @@ HeapWord* ShenandoahPLAB::allocate(size_t size, bool is_promotion) {
9392
HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) {
9493
assert(_heap->mode()->is_generational(), "PLABs only relevant to generational GC");
9594

96-
// PLABs are aligned to card boundaries to avoid synchronization with concurrent
97-
// allocations in other PLABs.
9895
const size_t plab_min_size = _heap->plab_min_size();
99-
const size_t min_size = (size > plab_min_size)? align_up(size, CardTable::card_size_in_words()): plab_min_size;
96+
const size_t min_size = (size > plab_min_size) ? size : plab_min_size;
10097

10198
// Figure out size of new PLAB, using value determined at last refill.
10299
size_t cur_size = _desired_size;
@@ -105,12 +102,7 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) {
105102
}
106103

107104
// Expand aggressively, doubling at each refill in this epoch, ceiling at plab_max_size()
108-
// Doubling, starting at a card-multiple, should give us a card-multiple. (Ceiling and floor
109-
// are card multiples.)
110105
const size_t future_size = MIN2(cur_size * 2, _heap->plab_max_size());
111-
assert(is_aligned(future_size, CardTable::card_size_in_words()), "Card multiple by construction, future_size: %zu"
112-
", card_size: %u, cur_size: %zu, max: %zu",
113-
future_size, CardTable::card_size_in_words(), cur_size, _heap->plab_max_size());
114106

115107
// Record new heuristic value even if we take any shortcut. This captures
116108
// the case when moderately-sized objects always take a shortcut. At some point,
@@ -128,8 +120,6 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) {
128120

129121
if (_plab->words_remaining() < plab_min_size) {
130122
// Retire current PLAB. This takes care of any PLAB book-keeping.
131-
// retire_plab() registers the remnant filler object with the remembered set scanner without a lock.
132-
// Since PLABs are card-aligned, concurrent registrations in other PLABs don't interfere.
133123
retire();
134124

135125
size_t actual_size = 0;
@@ -157,7 +147,6 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) {
157147
Copy::fill_to_words(plab_buf + hdr_size, actual_size - hdr_size, badHeapWordVal);
158148
#endif
159149
}
160-
assert(is_aligned(actual_size, CardTable::card_size_in_words()), "Align by design");
161150
_plab->set_buf(plab_buf, actual_size);
162151
if (is_promotion && !_allows_promotion) {
163152
return nullptr;
@@ -173,7 +162,6 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) {
173162
}
174163

175164
HeapWord* ShenandoahPLAB::allocate_new_plab(size_t min_size, size_t word_size, size_t* actual_size) {
176-
assert(is_aligned(min_size, CardTable::card_size_in_words()), "Align by design");
177165
assert(word_size >= min_size, "Requested PLAB is too small");
178166

179167
ShenandoahAllocRequest req = ShenandoahAllocRequest::for_plab(min_size, word_size);
@@ -183,7 +171,6 @@ HeapWord* ShenandoahPLAB::allocate_new_plab(size_t min_size, size_t word_size, s
183171
} else {
184172
*actual_size = 0;
185173
}
186-
assert(is_aligned(res, CardTable::card_size_in_words()), "Align by design");
187174
return res;
188175
}
189176

0 commit comments

Comments
 (0)