Preallocate `CodeInfoTableDeduper::dedupe_set_`.
Preallocate large buffer except for multi-image compilation
which requires multiple dedupe sets, so we let them grow as
needed without wasting too much memory. We do not expect to
use multi-image compilation on user devices.
Also remove the hash from the dedupe set entry. With the
large pre-allocated buffer, we have very few hash conflicts
and comparing the hash just slows down finding identical
entries. If we exceed the pre-allocated buffer, this shall
trade some performance for lower memory use.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: Ibbb98b6d3ebbc35ffa75165baad54f4df7c62ad9
diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc
index 03c906b..4857ec0 100644
--- a/compiler/driver/compiled_method_storage.cc
+++ b/compiler/driver/compiled_method_storage.cc
@@ -183,6 +183,11 @@
ReleaseArrayIfNotDeduplicated(code);
}
+size_t CompiledMethodStorage::UniqueCodeEntries() const {
+ DCHECK(DedupeEnabled());
+ return dedupe_code_.Size(Thread::Current());
+}
+
const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateVMapTable(
const ArrayRef<const uint8_t>& table) {
return AllocateOrDeduplicateArray(table, &dedupe_vmap_table_);
@@ -192,6 +197,11 @@
ReleaseArrayIfNotDeduplicated(table);
}
+size_t CompiledMethodStorage::UniqueVMapTableEntries() const {
+ DCHECK(DedupeEnabled());
+ return dedupe_vmap_table_.Size(Thread::Current());
+}
+
const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateCFIInfo(
const ArrayRef<const uint8_t>& cfi_info) {
return AllocateOrDeduplicateArray(cfi_info, &dedupe_cfi_info_);
@@ -201,6 +211,11 @@
ReleaseArrayIfNotDeduplicated(cfi_info);
}
+size_t CompiledMethodStorage::UniqueCFIInfoEntries() const {
+ DCHECK(DedupeEnabled());
+ return dedupe_cfi_info_.Size(Thread::Current());
+}
+
const LengthPrefixedArray<linker::LinkerPatch>* CompiledMethodStorage::DeduplicateLinkerPatches(
const ArrayRef<const linker::LinkerPatch>& linker_patches) {
return AllocateOrDeduplicateArray(linker_patches, &dedupe_linker_patches_);
@@ -211,6 +226,11 @@
ReleaseArrayIfNotDeduplicated(linker_patches);
}
+size_t CompiledMethodStorage::UniqueLinkerPatchesEntries() const {
+ DCHECK(DedupeEnabled());
+ return dedupe_linker_patches_.Size(Thread::Current());
+}
+
CompiledMethodStorage::ThunkMapKey CompiledMethodStorage::GetThunkMapKey(
const linker::LinkerPatch& linker_patch) {
uint32_t custom_value1 = 0u;
diff --git a/compiler/driver/compiled_method_storage.h b/compiler/driver/compiled_method_storage.h
index a5a7691..f9f3401 100644
--- a/compiler/driver/compiled_method_storage.h
+++ b/compiler/driver/compiled_method_storage.h
@@ -53,16 +53,20 @@
const LengthPrefixedArray<uint8_t>* DeduplicateCode(const ArrayRef<const uint8_t>& code);
void ReleaseCode(const LengthPrefixedArray<uint8_t>* code);
+ size_t UniqueCodeEntries() const;
const LengthPrefixedArray<uint8_t>* DeduplicateVMapTable(const ArrayRef<const uint8_t>& table);
void ReleaseVMapTable(const LengthPrefixedArray<uint8_t>* table);
+ size_t UniqueVMapTableEntries() const;
const LengthPrefixedArray<uint8_t>* DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info);
void ReleaseCFIInfo(const LengthPrefixedArray<uint8_t>* cfi_info);
+ size_t UniqueCFIInfoEntries() const;
const LengthPrefixedArray<linker::LinkerPatch>* DeduplicateLinkerPatches(
const ArrayRef<const linker::LinkerPatch>& linker_patches);
void ReleaseLinkerPatches(const LengthPrefixedArray<linker::LinkerPatch>* linker_patches);
+ size_t UniqueLinkerPatchesEntries() const;
// Returns the code associated with the given patch.
// If the code has not been set, returns empty data.
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index ad5a009..51cd999 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -51,6 +51,7 @@
verification_results_(nullptr),
compiler_type_(CompilerType::kAotCompiler),
image_type_(ImageType::kNone),
+ multi_image_(false),
compile_art_test_(false),
baseline_(false),
debuggable_(false),
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 7830924..0034306 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -233,6 +233,10 @@
return image_type_ == ImageType::kAppImage;
}
+ bool IsMultiImage() const {
+ return multi_image_;
+ }
+
// Returns whether we are running ART tests.
// The compiler will use that information for checking invariants.
bool CompileArtTest() const {
@@ -408,6 +412,7 @@
CompilerType compiler_type_;
ImageType image_type_;
+ bool multi_image_;
bool compile_art_test_;
bool baseline_;
bool debuggable_;
diff --git a/compiler/utils/dedupe_set-inl.h b/compiler/utils/dedupe_set-inl.h
index 4e892f2..d4a9cc8 100644
--- a/compiler/utils/dedupe_set-inl.h
+++ b/compiler/utils/dedupe_set-inl.h
@@ -81,6 +81,11 @@
return store_key;
}
+ size_t Size(Thread* self) {
+ MutexLock lock(self, lock_);
+ return keys_.size();
+ }
+
void UpdateStats(Thread* self, Stats* global_stats) REQUIRES(!lock_) {
// HashSet<> doesn't keep entries ordered by hash, so we actually allocate memory
// for bookkeeping while collecting the stats.
@@ -234,6 +239,20 @@
typename HashType,
typename HashFunc,
HashType kShard>
+size_t DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::Size(Thread* self) const {
+ size_t result = 0u;
+ for (const auto& shard : shards_) {
+ result += shard->Size(self);
+ }
+ return result;
+}
+
+template <typename InKey,
+ typename StoreKey,
+ typename Alloc,
+ typename HashType,
+ typename HashFunc,
+ HashType kShard>
std::string DedupeSet<InKey, StoreKey, Alloc, HashType, HashFunc, kShard>::DumpStats(
Thread* self) const {
Stats stats;
diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h
index 3baa061..a1ba208 100644
--- a/compiler/utils/dedupe_set.h
+++ b/compiler/utils/dedupe_set.h
@@ -45,6 +45,8 @@
~DedupeSet();
+ size_t Size(Thread* self) const;
+
std::string DumpStats(Thread* self) const;
private: