Skip to content

Commit 7e05a70

Browse files
author
Matias Saavedra Silva
committed
8251330: Reorder CDS archived heap to speed up relocation
Reviewed-by: iklam, ccheung
1 parent 7d8561d commit 7e05a70

File tree

9 files changed

+204
-34
lines changed

9 files changed

+204
-34
lines changed

src/hotspot/share/cds/archiveHeapLoader.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -164,18 +164,19 @@ void ArchiveHeapLoader::patch_compressed_embedded_pointers(BitMapView bm,
164164

165165
// Optimization: if dumptime shift is the same as runtime shift, we can perform a
166166
// quick conversion from "dumptime narrowOop" -> "runtime narrowOop".
167+
narrowOop* patching_start = (narrowOop*)region.start() + FileMapInfo::current_info()->heap_oopmap_start_pos();
167168
if (_narrow_oop_shift == CompressedOops::shift()) {
168169
uint32_t quick_delta = (uint32_t)rt_encoded_bottom - (uint32_t)dt_encoded_bottom;
169170
log_info(cds)("CDS heap data relocation quick delta = 0x%x", quick_delta);
170171
if (quick_delta == 0) {
171172
log_info(cds)("CDS heap data relocation unnecessary, quick_delta = 0");
172173
} else {
173-
PatchCompressedEmbeddedPointersQuick patcher((narrowOop*)region.start(), quick_delta);
174+
PatchCompressedEmbeddedPointersQuick patcher(patching_start, quick_delta);
174175
bm.iterate(&patcher);
175176
}
176177
} else {
177178
log_info(cds)("CDS heap data quick relocation not possible");
178-
PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
179+
PatchCompressedEmbeddedPointers patcher(patching_start);
179180
bm.iterate(&patcher);
180181
}
181182
}
@@ -186,17 +187,10 @@ void ArchiveHeapLoader::patch_embedded_pointers(FileMapInfo* info,
186187
MemRegion region, address oopmap,
187188
size_t oopmap_size_in_bits) {
188189
BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
189-
190-
#ifndef PRODUCT
191-
ResourceMark rm;
192-
ResourceBitMap checkBm = HeapShared::calculate_oopmap(region);
193-
assert(bm.is_same(checkBm), "sanity");
194-
#endif
195-
196190
if (UseCompressedOops) {
197191
patch_compressed_embedded_pointers(bm, info, region);
198192
} else {
199-
PatchUncompressedEmbeddedPointers patcher((oop*)region.start());
193+
PatchUncompressedEmbeddedPointers patcher((oop*)region.start() + FileMapInfo::current_info()->heap_oopmap_start_pos());
200194
bm.iterate(&patcher);
201195
}
202196
}
@@ -316,7 +310,7 @@ bool ArchiveHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiv
316310
uintptr_t oopmap = bitmap_base + r->oopmap_offset();
317311
BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits());
318312

319-
PatchLoadedRegionPointers patcher((narrowOop*)load_address, loaded_region);
313+
PatchLoadedRegionPointers patcher((narrowOop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region);
320314
bm.iterate(&patcher);
321315
return true;
322316
}
@@ -449,7 +443,7 @@ void ArchiveHeapLoader::patch_native_pointers() {
449443
if (r->mapped_base() != nullptr && r->has_ptrmap()) {
450444
log_info(cds, heap)("Patching native pointers in heap region");
451445
BitMapView bm = r->ptrmap_view();
452-
PatchNativePointers patcher((Metadata**)r->mapped_base());
446+
PatchNativePointers patcher((Metadata**)r->mapped_base() + FileMapInfo::current_info()->heap_ptrmap_start_pos());
453447
bm.iterate(&patcher);
454448
}
455449
}

src/hotspot/share/cds/archiveHeapWriter.cpp

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -62,6 +62,7 @@ address ArchiveHeapWriter::_requested_top;
6262

6363
GrowableArrayCHeap<ArchiveHeapWriter::NativePointerInfo, mtClassShared>* ArchiveHeapWriter::_native_pointers;
6464
GrowableArrayCHeap<oop, mtClassShared>* ArchiveHeapWriter::_source_objs;
65+
GrowableArrayCHeap<int, mtClassShared>* ArchiveHeapWriter::_source_objs_order;
6566

6667
ArchiveHeapWriter::BufferOffsetToSourceObjectTable*
6768
ArchiveHeapWriter::_buffer_offset_to_source_obj_table = nullptr;
@@ -72,6 +73,7 @@ typedef ResourceHashtable<address, size_t,
7273
AnyObj::C_HEAP,
7374
mtClassShared> FillersTable;
7475
static FillersTable* _fillers;
76+
static int _num_native_ptrs = 0;
7577

7678
void ArchiveHeapWriter::init() {
7779
if (HeapShared::can_write()) {
@@ -84,13 +86,15 @@ void ArchiveHeapWriter::init() {
8486

8587
_native_pointers = new GrowableArrayCHeap<NativePointerInfo, mtClassShared>(2048);
8688
_source_objs = new GrowableArrayCHeap<oop, mtClassShared>(10000);
89+
_source_objs_order = new GrowableArrayCHeap<int, mtClassShared>(10000);
8790

8891
guarantee(UseG1GC, "implementation limitation");
8992
guarantee(MIN_GC_REGION_ALIGNMENT <= /*G1*/HeapRegion::min_region_size_in_words() * HeapWordSize, "must be");
9093
}
9194
}
9295

9396
void ArchiveHeapWriter::add_source_obj(oop src_obj) {
97+
_source_objs_order->append(_source_objs->length());
9498
_source_objs->append(src_obj);
9599
}
96100

@@ -226,9 +230,54 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap<oop, mtClassShar
226230
_buffer_used = new_used;
227231
}
228232

233+
static int oop_sorting_rank(oop o) {
234+
bool has_o_ptr = HeapShared::has_oop_pointers(o);
235+
bool has_n_ptr = HeapShared::has_native_pointers(o);
236+
237+
if (!has_o_ptr) {
238+
if (!has_n_ptr) {
239+
return 0;
240+
} else {
241+
return 1;
242+
}
243+
} else {
244+
if (has_n_ptr) {
245+
return 2;
246+
} else {
247+
return 3;
248+
}
249+
}
250+
}
251+
252+
// The goal is to sort the objects in increasing order of:
253+
// - objects that have no pointers
254+
// - objects that have only native pointers
255+
// - objects that have both native and oop pointers
256+
// - objects that have only oop pointers
257+
int ArchiveHeapWriter::compare_objs_by_oop_fields(int* a, int* b) {
258+
oop oa = _source_objs->at(*a);
259+
oop ob = _source_objs->at(*b);
260+
261+
int rank_a = oop_sorting_rank(oa);
262+
int rank_b = oop_sorting_rank(ob);
263+
264+
if (rank_a != rank_b) {
265+
return rank_a - rank_b;
266+
} else {
267+
// If they are the same rank, sort them by their position in the _source_objs array
268+
return *a - *b;
269+
}
270+
}
271+
272+
void ArchiveHeapWriter::sort_source_objs() {
273+
_source_objs_order->sort(compare_objs_by_oop_fields);
274+
}
275+
229276
void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots) {
230-
for (int i = 0; i < _source_objs->length(); i++) {
231-
oop src_obj = _source_objs->at(i);
277+
sort_source_objs();
278+
for (int i = 0; i < _source_objs_order->length(); i++) {
279+
int src_obj_index = _source_objs_order->at(i);
280+
oop src_obj = _source_objs->at(src_obj_index);
232281
HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
233282
assert(info != nullptr, "must be");
234283
size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
@@ -239,8 +288,8 @@ void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtCla
239288

240289
copy_roots_to_buffer(roots);
241290

242-
log_info(cds)("Size of heap region = " SIZE_FORMAT " bytes, %d objects, %d roots",
243-
_buffer_used, _source_objs->length() + 1, roots->length());
291+
log_info(cds)("Size of heap region = " SIZE_FORMAT " bytes, %d objects, %d roots, %d native ptrs",
292+
_buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
244293
}
245294

246295
size_t ArchiveHeapWriter::filler_array_byte_size(int length) {
@@ -512,21 +561,35 @@ class ArchiveHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure {
512561
}
513562
};
514563

564+
static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bits) {
565+
// The whole heap is covered by total_bits, but there are only non-zero bits within [start ... end).
566+
size_t start = bitmap->find_first_set_bit(0);
567+
size_t end = bitmap->size();
568+
log_info(cds)("%s = " SIZE_FORMAT_W(7) " ... " SIZE_FORMAT_W(7) " (%3zu%% ... %3zu%% = %3zu%%)", which,
569+
start, end,
570+
start * 100 / total_bits,
571+
end * 100 / total_bits,
572+
(end - start) * 100 / total_bits);
573+
}
574+
515575
// Update all oop fields embedded in the buffered objects
516576
void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassShared>* roots,
517577
ArchiveHeapInfo* heap_info) {
518578
size_t oopmap_unit = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
519579
size_t heap_region_byte_size = _buffer_used;
520580
heap_info->oopmap()->resize(heap_region_byte_size / oopmap_unit);
521581

522-
auto iterator = [&] (oop src_obj, HeapShared::CachedOopInfo& info) {
523-
oop requested_obj = requested_obj_from_buffer_offset(info.buffer_offset());
582+
for (int i = 0; i < _source_objs_order->length(); i++) {
583+
int src_obj_index = _source_objs_order->at(i);
584+
oop src_obj = _source_objs->at(src_obj_index);
585+
HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
586+
assert(info != nullptr, "must be");
587+
oop requested_obj = requested_obj_from_buffer_offset(info->buffer_offset());
524588
update_header_for_requested_obj(requested_obj, src_obj, src_obj->klass());
525-
address buffered_obj = offset_to_buffered_address<address>(info.buffer_offset());
589+
address buffered_obj = offset_to_buffered_address<address>(info->buffer_offset());
526590
EmbeddedOopRelocator relocator(src_obj, buffered_obj, heap_info->oopmap());
527591
src_obj->oop_iterate(&relocator);
528592
};
529-
HeapShared::archived_object_cache()->iterate_all(iterator);
530593

531594
// Relocate HeapShared::roots(), which is created in copy_roots_to_buffer() and
532595
// doesn't have a corresponding src_obj, so we can't use EmbeddedOopRelocator on it.
@@ -542,6 +605,10 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassSh
542605
}
543606

544607
compute_ptrmap(heap_info);
608+
609+
size_t total_bytes = (size_t)_buffer->length();
610+
log_bitmap_usage("oopmap", heap_info->oopmap(), total_bytes / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)));
611+
log_bitmap_usage("ptrmap", heap_info->ptrmap(), total_bytes / sizeof(address));
545612
}
546613

547614
void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) {
@@ -551,6 +618,8 @@ void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) {
551618
info._src_obj = src_obj;
552619
info._field_offset = field_offset;
553620
_native_pointers->append(info);
621+
HeapShared::set_has_native_pointers(src_obj);
622+
_num_native_ptrs ++;
554623
}
555624
}
556625

@@ -565,6 +634,13 @@ bool ArchiveHeapWriter::is_marked_as_native_pointer(ArchiveHeapInfo* heap_info,
565634
assert((Metadata**)_requested_bottom <= requested_field_addr && requested_field_addr < (Metadata**) _requested_top, "range check");
566635

567636
BitMap::idx_t idx = requested_field_addr - (Metadata**) _requested_bottom;
637+
// Leading zeros have been removed so some addresses may not be in the ptrmap
638+
size_t start_pos = FileMapInfo::current_info()->heap_ptrmap_start_pos();
639+
if (idx < start_pos) {
640+
return false;
641+
} else {
642+
idx -= start_pos;
643+
}
568644
return (idx < heap_info->ptrmap()->size()) && (heap_info->ptrmap()->at(idx) == true);
569645
}
570646

src/hotspot/share/cds/archiveHeapWriter.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -140,6 +140,7 @@ class ArchiveHeapWriter : AllStatic {
140140

141141
static GrowableArrayCHeap<NativePointerInfo, mtClassShared>* _native_pointers;
142142
static GrowableArrayCHeap<oop, mtClassShared>* _source_objs;
143+
static GrowableArrayCHeap<int, mtClassShared>* _source_objs_order;
143144

144145
typedef ResourceHashtable<size_t, oop,
145146
36137, // prime number
@@ -210,6 +211,10 @@ class ArchiveHeapWriter : AllStatic {
210211
template <typename T> static void relocate_root_at(oop requested_roots, int index, CHeapBitMap* oopmap);
211212

212213
static void update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass);
214+
215+
static int compare_objs_by_oop_fields(int* a, int* b);
216+
static void sort_source_objs();
217+
213218
public:
214219
static void init() NOT_CDS_JAVA_HEAP_RETURN;
215220
static void add_source_obj(oop src_obj);

src/hotspot/share/cds/filemap.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ void FileMapHeader::print(outputStream* st) {
289289
st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
290290
st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
291291
st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
292+
st->print_cr("- _heap_oopmap_start_pos: " SIZE_FORMAT, _heap_oopmap_start_pos);
293+
st->print_cr("- _heap_ptrmap_start_pos: " SIZE_FORMAT, _heap_ptrmap_start_pos);
292294
st->print_cr("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
293295
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
294296
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
@@ -1565,11 +1567,37 @@ static size_t write_bitmap(const CHeapBitMap* map, char* output, size_t offset)
15651567
return offset + size_in_bytes;
15661568
}
15671569

1570+
// The start of the archived heap has many primitive arrays (String
1571+
// bodies) that are not marked by the oop/ptr maps. So we must have
1572+
// lots of leading zeros.
1573+
size_t FileMapInfo::remove_bitmap_leading_zeros(CHeapBitMap* map) {
1574+
size_t old_zeros = map->find_first_set_bit(0);
1575+
size_t old_size = map->size_in_bytes();
1576+
1577+
// Slice and resize bitmap
1578+
map->truncate(old_zeros, map->size());
1579+
1580+
DEBUG_ONLY(
1581+
size_t new_zeros = map->find_first_set_bit(0);
1582+
assert(new_zeros == 0, "Should have removed leading zeros");
1583+
)
1584+
1585+
assert(map->size_in_bytes() < old_size, "Map size should have decreased");
1586+
return old_zeros;
1587+
}
1588+
15681589
char* FileMapInfo::write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
15691590
size_t &size_in_bytes) {
15701591
size_in_bytes = ptrmap->size_in_bytes();
15711592

15721593
if (heap_info->is_used()) {
1594+
// Remove leading zeros
1595+
size_t removed_oop_zeros = remove_bitmap_leading_zeros(heap_info->oopmap());
1596+
size_t removed_ptr_zeros = remove_bitmap_leading_zeros(heap_info->ptrmap());
1597+
1598+
header()->set_heap_oopmap_start_pos(removed_oop_zeros);
1599+
header()->set_heap_ptrmap_start_pos(removed_ptr_zeros);
1600+
15731601
size_in_bytes += heap_info->oopmap()->size_in_bytes();
15741602
size_in_bytes += heap_info->ptrmap()->size_in_bytes();
15751603
}

src/hotspot/share/cds/filemap.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ class FileMapHeader: private CDSFileMapHeaderBase {
228228
size_t _ptrmap_size_in_bits; // Size of pointer relocation bitmap
229229
size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
230230
// of the archived heap objects, in bytes.
231+
size_t _heap_oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
232+
size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.
231233
char* from_mapped_offset(size_t offset) const {
232234
return mapped_base_address() + offset;
233235
}
@@ -269,6 +271,8 @@ class FileMapHeader: private CDSFileMapHeaderBase {
269271
bool compressed_oops() const { return _compressed_oops; }
270272
bool compressed_class_pointers() const { return _compressed_class_ptrs; }
271273
size_t heap_roots_offset() const { return _heap_roots_offset; }
274+
size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos;}
275+
size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos;}
272276
// FIXME: These should really return int
273277
jshort max_used_path_index() const { return _max_used_path_index; }
274278
jshort app_module_paths_start_index() const { return _app_module_paths_start_index; }
@@ -281,6 +285,8 @@ class FileMapHeader: private CDSFileMapHeaderBase {
281285
void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; }
282286
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
283287
void set_heap_roots_offset(size_t n) { _heap_roots_offset = n; }
288+
void set_heap_oopmap_start_pos(size_t n) { _heap_oopmap_start_pos = n; }
289+
void set_heap_ptrmap_start_pos(size_t n) { _heap_ptrmap_start_pos = n; }
284290
void copy_base_archive_name(const char* name);
285291

286292
void set_shared_path_table(SharedPathTable table) {
@@ -378,6 +384,8 @@ class FileMapInfo : public CHeapObj<mtInternal> {
378384
uintx max_heap_size() const { return header()->max_heap_size(); }
379385
size_t heap_roots_offset() const { return header()->heap_roots_offset(); }
380386
size_t core_region_alignment() const { return header()->core_region_alignment(); }
387+
size_t heap_oopmap_start_pos() const { return header()->heap_oopmap_start_pos(); }
388+
size_t heap_ptrmap_start_pos() const { return header()->heap_ptrmap_start_pos(); }
381389

382390
CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); }
383391
jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); }
@@ -434,6 +442,7 @@ class FileMapInfo : public CHeapObj<mtInternal> {
434442
void write_header();
435443
void write_region(int region, char* base, size_t size,
436444
bool read_only, bool allow_exec);
445+
size_t remove_bitmap_leading_zeros(CHeapBitMap* map);
437446
char* write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
438447
size_t &size_in_bytes);
439448
size_t write_heap_region(ArchiveHeapInfo* heap_info);

0 commit comments

Comments
 (0)