Skip to content

Commit 8ea46a2

Browse files
committed
ZVirtualReservation
1 parent 1fc01a2 commit 8ea46a2

File tree

4 files changed

+118
-54
lines changed

4 files changed

+118
-54
lines changed

src/hotspot/share/gc/z/zMemory.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ ZMemoryManager::ZMemoryManager()
223223
: _freelist(),
224224
_callbacks() {}
225225

226+
bool ZMemoryManager::free_is_contiguous() const {
227+
return _freelist.size() == 1;
228+
}
229+
226230
void ZMemoryManager::register_callbacks(const Callbacks& callbacks) {
227231
_callbacks = callbacks;
228232
}

src/hotspot/share/gc/z/zMemory.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ class ZMemoryManager {
101101
public:
102102
ZMemoryManager();
103103

104+
bool free_is_contiguous() const;
105+
104106
void register_callbacks(const Callbacks& callbacks);
105107

106108
ZMemoryRange total_range() const;

src/hotspot/share/gc/z/zVirtualMemoryManager.cpp

Lines changed: 102 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,64 @@
3434
#include "utilities/align.hpp"
3535
#include "utilities/debug.hpp"
3636

37+
class ZVirtualReservation {
38+
private:
39+
ZMemoryManager _reserved;
40+
size_t _size;
41+
size_t _min_range;
42+
43+
static size_t limit_max_reservation(size_t size) {
44+
const size_t limit = MIN2(ZAddressOffsetMax, ZAddressSpaceLimit::heap());
45+
return MIN2(size * ZVirtualToPhysicalRatio, limit);
46+
}
47+
48+
static size_t calculate_min_range(size_t size) {
49+
// Don't try to reserve address ranges smaller than 1% of the requested size.
50+
// This avoids an explosion of reservation attempts in case large parts of the
51+
// address space is already occupied.
52+
return align_up(size / ZMaxVirtualReservations, ZGranuleSize);
53+
}
54+
55+
public:
56+
ZVirtualReservation(size_t size)
57+
: _reserved(),
58+
_size(limit_max_reservation(size)),
59+
_min_range(calculate_min_range(size)) {
60+
assert(is_aligned(size, ZGranuleSize), "Must be granule aligned 0x%zx", size);
61+
}
62+
63+
void reserve(zoffset start, size_t size) {
64+
_reserved.free(start, size);
65+
}
66+
67+
void transfer(ZMemoryManager& other, size_t size) {
68+
_reserved.transfer_low_address(other, size);
69+
}
70+
71+
size_t size() const {
72+
return _size;
73+
}
74+
75+
bool set_size(size_t size) {
76+
assert(is_aligned(size, ZGranuleSize), "Misaligned");
77+
if (size < _min_range) {
78+
return false;
79+
}
80+
81+
_size = size;
82+
83+
return true;
84+
}
85+
86+
size_t min_range() const {
87+
return _min_range;
88+
}
89+
90+
bool is_contiguous() const {
91+
return _reserved.free_is_contiguous();
92+
}
93+
};
94+
3795
ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity)
3896
: _reserved_memory(),
3997
_managers(),
@@ -46,7 +104,8 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity)
46104
pd_initialize_before_reserve();
47105

48106
// Reserve address space
49-
const size_t reserved_total = reserve(max_capacity);
107+
ZVirtualReservation reservation(max_capacity);
108+
const size_t reserved_total = reserve(&reservation);
50109
if (reserved_total < max_capacity) {
51110
ZInitialize::error_d("Failed to reserve enough address space for Java heap");
52111
return;
@@ -60,7 +119,7 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity)
60119
ZMemoryManager& manager = _managers.get(numa_id);
61120

62121
// Transfer reserved memory
63-
_reserved_memory.transfer_low_address(manager, reserved);
122+
reservation.transfer(manager, reserved);
64123

65124
// Store the range for the manager
66125
_vmem_ranges.set(manager.total_range(), numa_id);
@@ -71,9 +130,9 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity)
71130
}
72131

73132
#ifdef ASSERT
74-
size_t ZVirtualMemoryManager::force_reserve_discontiguous(size_t size) {
75-
const size_t min_range = calculate_min_range(size);
76-
const size_t max_range = MAX2(align_down(size / ZForceDiscontiguousHeapReservations, ZGranuleSize), min_range);
133+
size_t ZVirtualMemoryManager::force_reserve_discontiguous(ZVirtualReservation* reservation) {
134+
const size_t size = reservation->size();
135+
const size_t max_range = MAX2(align_down(size / ZForceDiscontiguousHeapReservations, ZGranuleSize), reservation->min_range());
77136
size_t reserved = 0;
78137

79138
// Try to reserve ZForceDiscontiguousHeapReservations number of virtual memory
@@ -84,7 +143,8 @@ size_t ZVirtualMemoryManager::force_reserve_discontiguous(size_t size) {
84143
const size_t reserve_size = MIN2(max_range, remaining);
85144
const uintptr_t reserve_start = end - reserve_size;
86145

87-
if (reserve_contiguous(to_zoffset(reserve_start), reserve_size)) {
146+
reservation->set_size(reserve_size);
147+
if (reserve_contiguous(reservation, to_zoffset(reserve_start))) {
88148
reserved += reserve_size;
89149
}
90150

@@ -95,64 +155,59 @@ size_t ZVirtualMemoryManager::force_reserve_discontiguous(size_t size) {
95155
uintptr_t start = 0;
96156
while (reserved < size && start < ZAddressOffsetMax) {
97157
const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start);
98-
reserved += reserve_discontiguous(to_zoffset(start), remaining, min_range);
158+
if (reservation->set_size(remaining)) {
159+
reserved += reserve_discontiguous(reservation, to_zoffset(start));
160+
}
99161
start += remaining;
100162
}
101163

102164
return reserved;
103165
}
104166
#endif
105167

106-
size_t ZVirtualMemoryManager::reserve_discontiguous(zoffset start, size_t size, size_t min_range) {
107-
if (size < min_range) {
108-
// Too small
109-
return 0;
110-
}
111-
112-
assert(is_aligned(size, ZGranuleSize), "Misaligned");
113-
114-
if (reserve_contiguous(start, size)) {
115-
return size;
168+
size_t ZVirtualMemoryManager::reserve_discontiguous(ZVirtualReservation* reservation, zoffset start) {
169+
if (reserve_contiguous(reservation, start)) {
170+
return reservation->size();
116171
}
117172

173+
const size_t size = reservation->size();
118174
const size_t half = size / 2;
119-
if (half < min_range) {
175+
if (half < reservation->min_range()) {
120176
// Too small
121177
return 0;
122178
}
123179

124180
// Divide and conquer
125181
const size_t first_part = align_down(half, ZGranuleSize);
182+
reservation->set_size(first_part);
183+
const size_t first_size = reserve_discontiguous(reservation, start);
184+
126185
const size_t second_part = size - first_part;
127-
const size_t first_size = reserve_discontiguous(start, first_part, min_range);
128-
const size_t second_size = reserve_discontiguous(start + first_part, second_part, min_range);
129-
return first_size + second_size;
130-
}
186+
reservation->set_size(second_part);
187+
const size_t second_size = reserve_discontiguous(reservation, start + first_part);
131188

132-
size_t ZVirtualMemoryManager::calculate_min_range(size_t size) {
133-
// Don't try to reserve address ranges smaller than 1% of the requested size.
134-
// This avoids an explosion of reservation attempts in case large parts of the
135-
// address space is already occupied.
136-
return align_up(size / ZMaxVirtualReservations, ZGranuleSize);
189+
return first_size + second_size;
137190
}
138191

139-
size_t ZVirtualMemoryManager::reserve_discontiguous(size_t size) {
140-
const size_t min_range = calculate_min_range(size);
192+
size_t ZVirtualMemoryManager::reserve_discontiguous(ZVirtualReservation* reservation) {
193+
const size_t size = reservation->size();
141194
uintptr_t start = 0;
142195
size_t reserved = 0;
143196

144197
// Reserve size somewhere between [0, ZAddressOffsetMax)
145198
while (reserved < size && start < ZAddressOffsetMax) {
146199
const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start);
147-
reserved += reserve_discontiguous(to_zoffset(start), remaining, min_range);
200+
if (reservation->set_size(remaining)) {
201+
reserved += reserve_discontiguous(reservation, to_zoffset(start));
202+
}
148203
start += remaining;
149204
}
150205

151206
return reserved;
152207
}
153208

154-
bool ZVirtualMemoryManager::reserve_contiguous(zoffset start, size_t size) {
155-
assert(is_aligned(size, ZGranuleSize), "Must be granule aligned 0x%zx", size);
209+
bool ZVirtualMemoryManager::reserve_contiguous(ZVirtualReservation* reservation, zoffset start) {
210+
const size_t size = reservation->size();
156211

157212
// Reserve address views
158213
const zaddress_unsafe addr = ZOffset::address_unsafe(start);
@@ -165,18 +220,19 @@ bool ZVirtualMemoryManager::reserve_contiguous(zoffset start, size_t size) {
165220
// Register address views with native memory tracker
166221
ZNMT::reserve(addr, size);
167222

168-
_reserved_memory.free(start, size);
223+
reservation->reserve(start, size);
169224

170225
return true;
171226
}
172227

173-
bool ZVirtualMemoryManager::reserve_contiguous(size_t size) {
228+
bool ZVirtualMemoryManager::reserve_contiguous(ZVirtualReservation* reservation) {
174229
// Allow at most 8192 attempts spread evenly across [0, ZAddressOffsetMax)
230+
const size_t size = reservation->size();
175231
const size_t unused = ZAddressOffsetMax - size;
176232
const size_t increment = MAX2(align_up(unused / 8192, ZGranuleSize), ZGranuleSize);
177233

178234
for (uintptr_t start = 0; start + size <= ZAddressOffsetMax; start += increment) {
179-
if (reserve_contiguous(to_zoffset(start), size)) {
235+
if (reserve_contiguous(reservation, to_zoffset(start))) {
180236
// Success
181237
return true;
182238
}
@@ -186,33 +242,33 @@ bool ZVirtualMemoryManager::reserve_contiguous(size_t size) {
186242
return false;
187243
}
188244

189-
size_t ZVirtualMemoryManager::reserve(size_t max_capacity) {
190-
const size_t limit = MIN2(ZAddressOffsetMax, ZAddressSpaceLimit::heap());
191-
const size_t size = MIN2(max_capacity * ZVirtualToPhysicalRatio, limit);
192-
bool contiguous_reservation = false;
245+
size_t ZVirtualMemoryManager::reserve(ZVirtualReservation* reservation) {
246+
const size_t size = reservation->size();
193247

194248
auto do_reserve = [&]() {
195249
#ifdef ASSERT
196250
if (ZForceDiscontiguousHeapReservations > 0) {
197-
return force_reserve_discontiguous(size);
251+
return force_reserve_discontiguous(reservation);
198252
}
199253
#endif
200254

201255
// Prefer a contiguous address space
202-
if (reserve_contiguous(size)) {
203-
contiguous_reservation = true;
204-
return size;
256+
if (reserve_contiguous(reservation)) {
257+
return reservation->size();
205258
}
206259

207260
// Fall back to a discontiguous address space
208-
return reserve_discontiguous(size);
261+
return reserve_discontiguous(reservation);
209262
};
210263

211264
const size_t reserved = do_reserve();
212265

266+
const bool contiguous = reservation->is_contiguous();
267+
const bool limited = ZAddressSpaceLimit::heap() == ZAddressOffsetMax;
268+
213269
log_info_p(gc, init)("Address Space Type: %s/%s/%s",
214-
(contiguous_reservation ? "Contiguous" : "Discontiguous"),
215-
(limit == ZAddressOffsetMax ? "Unrestricted" : "Restricted"),
270+
(contiguous ? "Contiguous" : "Discontiguous"),
271+
(limited ? "Unrestricted" : "Restricted"),
216272
(reserved == size ? "Complete" : "Degraded"));
217273
log_info_p(gc, init)("Address Space Size: %zuM", reserved / M);
218274

src/hotspot/share/gc/z/zVirtualMemoryManager.hpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@
2929
#include "gc/z/zMemory.hpp"
3030
#include "gc/z/zValue.hpp"
3131

32+
class ZVirtualReservation;
33+
3234
class ZVirtualMemoryManager {
3335
friend class ZMapperTest;
3436

3537
private:
36-
static size_t calculate_min_range(size_t size);
37-
3838
ZMemoryManager _reserved_memory;
3939
ZPerNUMA<ZMemoryManager> _managers;
4040
ZPerNUMA<ZMemoryRange> _vmem_ranges;
@@ -46,15 +46,17 @@ class ZVirtualMemoryManager {
4646
bool pd_reserve(zaddress_unsafe addr, size_t size);
4747
void pd_unreserve(zaddress_unsafe addr, size_t size);
4848

49-
bool reserve_contiguous(zoffset start, size_t size);
50-
bool reserve_contiguous(size_t size);
51-
size_t reserve_discontiguous(zoffset start, size_t size, size_t min_range);
52-
size_t reserve_discontiguous(size_t size);
53-
size_t reserve(size_t max_capacity);
49+
bool reserve_contiguous(ZVirtualReservation* reservation, zoffset start);
50+
bool reserve_contiguous(ZVirtualReservation* reservation);
51+
52+
size_t reserve_discontiguous(ZVirtualReservation* reservation, zoffset start);
53+
size_t reserve_discontiguous(ZVirtualReservation* reservation);
54+
55+
size_t reserve(ZVirtualReservation* reservation);
5456

5557
void set_vmem_range_for_manager(int numa_id);
5658

57-
DEBUG_ONLY(size_t force_reserve_discontiguous(size_t size);)
59+
DEBUG_ONLY(size_t force_reserve_discontiguous(ZVirtualReservation* reservation);)
5860

5961
public:
6062
ZVirtualMemoryManager(size_t max_capacity);

0 commit comments

Comments
 (0)