Skip to content

Commit 3024827

Browse files
committed
Hi all, please review this change to G1 commit/uncommit to merge commit/uncommit calls to the operating system as much as possible. This significantly improves startup performanc Performance results before/after on Zen3 processor for a "HelloWorld" application: ``` $ hyperfine -w 10 -r 10 "baseline/bin/java -XX:+UseG1GC -Xms128m -Xmx128m Hello" Benchmark 1: baseline/bin/java -XX:+UseG1GC -Xms128m -Xmx128m Hello Time (mean ± σ): 16.4 ms ± 0.4 ms [User: 11.0 ms, System: 14.4 ms] Range (min … max): 15.7 ms … 16.8 ms 10 runs $ hyperfine -w 10 -r 10 "baseline/bin/java -XX:+UseG1GC -Xms2g -Xmx2g Hello" Benchmark 1: baseline/bin/java -XX:+UseG1GC -Xms2g -Xmx2g Hello Time (mean ± σ): 24.7 ms ± 0.4 ms [User: 10.7 ms, System: 22.7 ms] Range (min … max): 24.2 ms … 25.4 ms 10 runs My reimplementation of JDK-8071277 does show improvements here: $ hyperfine -w 10 -r 10 "changes/bin/java -XX:+UseG1GC -Xms128m -Xmx128m Hello" Benchmark 1: changes/bin/java -XX:+UseG1GC -Xms128m -Xmx128m Hello Time (mean ± σ): 15.9 ms ± 0.4 ms [User: 11.9 ms, System: 13.1 ms] Range (min … max): 15.4 ms … 16.7 ms 10 runs $ hyperfine -w 10 -r 10 "changes/bin/java -XX:+UseG1GC -Xms2g -Xmx2g Hello" Benchmark 1: changes/bin/java -XX:+UseG1GC -Xms2g -Xmx2g Hello Time (mean ± σ): 19.7 ms ± 0.3 ms [User: 11.3 ms, System: 17.4 ms] Range (min … max): 19.2 ms … 20.1 ms 10 runs ``` I.e., depending on actually committed heap size (`-Xms`), reduction of startup time by 20% or so in above cases. Testing: tier1-5, gha Thanks, Thomas
1 parent 28879d3 commit 3024827

File tree

3 files changed

+79
-18
lines changed

3 files changed

+79
-18
lines changed

src/hotspot/share/gc/g1/g1NUMA.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,7 @@ uint G1NUMA::index_for_region(G1HeapRegion* hr) const {
203203
// * G1HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-|
204204
// * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----|
205205
void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index) {
206-
if (!is_enabled()) {
207-
return;
208-
}
206+
assert(is_enabled(), "must be, check before");
209207

210208
if (size_in_bytes == 0) {
211209
return;

src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,15 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper {
9696
const size_t start_page = (size_t)start_idx * _pages_per_region;
9797
const size_t size_in_pages = num_regions * _pages_per_region;
9898
bool zero_filled = _storage.commit(start_page, size_in_pages);
99-
if (_memory_tag == mtJavaHeap) {
99+
100+
if (should_distribute_across_numa_nodes()) {
100101
for (uint region_index = start_idx; region_index < start_idx + num_regions; region_index++ ) {
101102
void* address = _storage.page_start(region_index * _pages_per_region);
102103
size_t size_in_bytes = _storage.page_size() * _pages_per_region;
103104
G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region_index);
104105
}
105106
}
107+
106108
if (AlwaysPreTouch) {
107109
_storage.pretouch(start_page, size_in_pages, pretouch_workers);
108110
}
@@ -148,15 +150,62 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
148150
return _region_commit_map.find_first_set_bit(region, region_limit) != region_limit;
149151
}
150152

151-
void numa_request_on_node(size_t page_idx) {
152-
if (_memory_tag == mtJavaHeap) {
153-
uint region = (uint)(page_idx * _regions_per_page);
154-
void* address = _storage.page_start(page_idx);
155-
size_t size_in_bytes = _storage.page_size();
156-
G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region);
153+
bool commit_pages(size_t start_page, size_t size_in_pages) {
154+
bool result = _storage.commit(start_page, size_in_pages);
155+
156+
if (should_distribute_across_numa_nodes()) {
157+
for (size_t page = start_page; page < start_page + size_in_pages; page++) {
158+
uint region = checked_cast<uint>(page * _regions_per_page);
159+
void* address = _storage.page_start(page);
160+
size_t size_in_bytes = _storage.page_size();
161+
G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region);
162+
}
157163
}
164+
return result;
158165
}
159166

167+
// Given increasing integers, applies the method OnNewRange(size_t range_start, size_t range_size)
168+
// in the constructor all ranges of consecutive indexes. Consecutive means that
169+
// the difference between integers is 1.
170+
// Call apply_last() to cover the last range.
171+
template <typename OnNewRange>
172+
class RangeApplicator {
173+
size_t const NoIndex = SIZE_MAX;
174+
175+
size_t _cur_start;
176+
size_t _cur_end;
177+
178+
OnNewRange _on_new_range;
179+
180+
public:
181+
RangeApplicator(OnNewRange on_new_range) : _cur_start(NoIndex), _cur_end(NoIndex), _on_new_range(on_new_range) { }
182+
~RangeApplicator() {
183+
assert(_cur_start == NoIndex, "must be, missing application of lambda");
184+
assert(_cur_end == NoIndex, "must be, missing application of lambda");
185+
}
186+
187+
void next_value(size_t index) {
188+
assert(_cur_end == NoIndex || _cur_end < index, "Given indexes must be ascending");
189+
190+
if (_cur_start == NoIndex) {
191+
_cur_start = _cur_end = index;
192+
} else if (_cur_end + 1 != index) {
193+
_on_new_range(_cur_start, _cur_end - _cur_start + 1);
194+
_cur_start = _cur_end = index;
195+
} else {
196+
_cur_end = index;
197+
}
198+
}
199+
200+
void apply_last() {
201+
if (_cur_start != NoIndex) {
202+
assert(_cur_end != NoIndex, "must be");
203+
_on_new_range(_cur_start, _cur_end - _cur_start + 1);
204+
_cur_start = _cur_end = NoIndex;
205+
}
206+
}
207+
};
208+
160209
public:
161210
G1RegionsSmallerThanCommitSizeMapper(ReservedSpace rs,
162211
size_t actual_size,
@@ -190,6 +239,13 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
190239
// Concurrent operations might operate on regions sharing the same
191240
// underlying OS page. See lock declaration for more details.
192241
{
242+
auto commit_range = [&](size_t page_start, size_t size_in_pages) {
243+
if (!commit_pages(page_start, size_in_pages)) {
244+
all_zero_filled = false;
245+
}
246+
};
247+
RangeApplicator range(commit_range);
248+
193249
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
194250
for (size_t page = start_page; page <= end_page; page++) {
195251
if (!is_page_committed(page)) {
@@ -199,18 +255,13 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
199255
}
200256
num_committed++;
201257

202-
if (!_storage.commit(page, 1)) {
203-
// Found dirty region during commit.
204-
all_zero_filled = false;
205-
}
206-
207-
// Move memory to correct NUMA node for the heap.
208-
numa_request_on_node(page);
258+
range.next_value(page);
209259
} else {
210260
// Page already committed.
211261
all_zero_filled = false;
212262
}
213263
}
264+
range.apply_last();
214265

215266
// Update the commit map for the given range. Not using the par_set_range
216267
// since updates to _region_commit_map for this mapper is protected by _lock.
@@ -233,6 +284,11 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
233284
size_t start_page = region_idx_to_page_idx(start_idx);
234285
size_t end_page = region_idx_to_page_idx(region_limit - 1);
235286

287+
auto uncommit_range = [&](size_t page_start, size_t size_in_pages) {
288+
_storage.uncommit(page_start, size_in_pages);
289+
};
290+
RangeApplicator r(uncommit_range);
291+
236292
// Concurrent operations might operate on regions sharing the same
237293
// underlying OS page. See lock declaration for more details.
238294
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
@@ -245,9 +301,10 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
245301
// the page is still marked as committed after the clear we should
246302
// not uncommit it.
247303
if (!is_page_committed(page)) {
248-
_storage.uncommit(page, 1);
304+
r.next_value(page);
249305
}
250306
}
307+
r.apply_last();
251308
}
252309
};
253310

@@ -257,6 +314,10 @@ void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions, b
257314
}
258315
}
259316

317+
bool G1RegionToSpaceMapper::should_distribute_across_numa_nodes() const {
318+
return _memory_tag == mtJavaHeap && G1NUMA::numa()->is_enabled();
319+
}
320+
260321
G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs,
261322
size_t actual_size,
262323
size_t page_size,

src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class G1RegionToSpaceMapper : public CHeapObj<mtGC> {
5858
G1RegionToSpaceMapper(ReservedSpace rs, size_t used_size, size_t page_size, size_t region_granularity, size_t commit_factor, MemTag mem_tag);
5959

6060
void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled);
61+
62+
bool should_distribute_across_numa_nodes() const;
6163
public:
6264
MemRegion reserved() { return _storage.reserved(); }
6365

0 commit comments

Comments
 (0)