diff options
author | 2021-03-08 14:27:05 +0000 | |
---|---|---|
committer | 2021-03-15 11:00:50 +0000 | |
commit | a64c1ad1ad20b99c4bb3a27acdd30dc9b3aa004b (patch) | |
tree | 3872764b79c105075a49d615334bebae34cf6e9d | |
parent | f84ec8662b695f6679023f368bc7203d3804a43e (diff) |
Rewrite hot method info retrieval.
Remove the `ProfileCompilationInfo::GetHotMethodInfo()` API
and provide another API to tie profile indexes to dex files
for inline caches that avoids unnecessary heap allocations.
And look up only dex caches for the referenced dex files
when getting AOT inline caches in HInliner.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimzing
Test: boots.
Bug: 181943478
Change-Id: I124ac4870b0f483c1f0422c841c4ff69fc95b7e0
-rw-r--r-- | compiler/optimizing/inliner.cc | 74 | ||||
-rw-r--r-- | compiler/optimizing/inliner.h | 9 | ||||
-rw-r--r-- | libartbase/base/common_art_test.cc | 53 | ||||
-rw-r--r-- | libartbase/base/common_art_test.h | 5 | ||||
-rw-r--r-- | libprofile/profile/profile_compilation_info.cc | 135 | ||||
-rw-r--r-- | libprofile/profile/profile_compilation_info.h | 149 | ||||
-rw-r--r-- | libprofile/profile/profile_compilation_info_test.cc | 172 | ||||
-rw-r--r-- | oatdump/oatdump_app_test.cc | 20 | ||||
-rw-r--r-- | oatdump/oatdump_image_test.cc | 8 | ||||
-rw-r--r-- | oatdump/oatdump_test.cc | 28 | ||||
-rw-r--r-- | oatdump/oatdump_test.h | 4 | ||||
-rw-r--r-- | profman/profile_assistant_test.cc | 79 | ||||
-rw-r--r-- | profman/profman.cc | 17 | ||||
-rw-r--r-- | runtime/jit/profiling_info_test.cc | 43 |
14 files changed, 327 insertions, 469 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index e3d04814b7..4d457395ef 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -673,63 +673,57 @@ HInliner::InlineCacheType HInliner::GetInlineCacheAOT( return kInlineCacheNoData; } - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_profile = - pci->GetHotMethodInfo(MethodReference( - caller_compilation_unit_.GetDexFile(), caller_compilation_unit_.GetDexMethodIndex())); - if (offline_profile == nullptr) { + ProfileCompilationInfo::MethodHotness hotness = pci->GetMethodHotness(MethodReference( + caller_compilation_unit_.GetDexFile(), caller_compilation_unit_.GetDexMethodIndex())); + if (!hotness.IsHot()) { return kInlineCacheNoData; // no profile information for this invocation. } - *inline_cache = AllocateInlineCacheHolder(caller_compilation_unit_, hs); - if (inline_cache == nullptr) { - // We can't extract any data if we failed to allocate; - return kInlineCacheNoData; - } else { - return ExtractClassesFromOfflineProfile(invoke_instruction, - *(offline_profile.get()), - *inline_cache); - } -} - -HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile( - const HInvoke* invoke_instruction, - const ProfileCompilationInfo::OfflineProfileMethodInfo& offline_profile, - /*out*/Handle<mirror::ObjectArray<mirror::Class>> inline_cache) - REQUIRES_SHARED(Locks::mutator_lock_) { - const auto it = offline_profile.inline_caches->find(invoke_instruction->GetDexPc()); - if (it == offline_profile.inline_caches->end()) { + const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); + DCHECK(inline_caches != nullptr); + const auto it = inline_caches->find(invoke_instruction->GetDexPc()); + if (it == inline_caches->end()) { return kInlineCacheUninitialized; } const ProfileCompilationInfo::DexPcData& dex_pc_data = it->second; - if (dex_pc_data.is_missing_types) { return kInlineCacheMissingTypes; } if (dex_pc_data.is_megamorphic) { return kInlineCacheMegamorphic; } - DCHECK_LE(dex_pc_data.classes.size(), InlineCache::kIndividualCacheSize); + + Handle<mirror::ObjectArray<mirror::Class>> ic = + AllocateInlineCacheHolder(caller_compilation_unit_, hs); + if (ic == nullptr) { + // We can't extract any data if we failed to allocate; + return kInlineCacheNoData; + } + Thread* self = Thread::Current(); // We need to resolve the class relative to the containing dex file. // So first, build a mapping from the index of dex file in the profile to // its dex cache. This will avoid repeating the lookup when walking over // the inline cache types. - std::vector<ObjPtr<mirror::DexCache>> dex_profile_index_to_dex_cache( - offline_profile.dex_references.size()); - for (size_t i = 0; i < offline_profile.dex_references.size(); i++) { - bool found = false; - for (const DexFile* dex_file : codegen_->GetCompilerOptions().GetDexFilesForOatFile()) { - if (offline_profile.dex_references[i].MatchesDex(dex_file)) { - dex_profile_index_to_dex_cache[i] = - caller_compilation_unit_.GetClassLinker()->FindDexCache(self, *dex_file); - found = true; + ScopedArenaAllocator allocator(graph_->GetArenaStack()); + ScopedArenaVector<ObjPtr<mirror::DexCache>> dex_profile_index_to_dex_cache( + pci->GetNumberOfDexFiles(), nullptr, allocator.Adapter(kArenaAllocMisc)); + const std::vector<const DexFile*>& dex_files = + codegen_->GetCompilerOptions().GetDexFilesForOatFile(); + for (const ProfileCompilationInfo::ClassReference& class_ref : dex_pc_data.classes) { + if (dex_profile_index_to_dex_cache[class_ref.dex_profile_index] == nullptr) { + ProfileCompilationInfo::ProfileIndexType profile_index = class_ref.dex_profile_index; + const DexFile* dex_file = pci->FindDexFileForProfileIndex(profile_index, dex_files); + if (dex_file == nullptr) { + VLOG(compiler) << "Could not find profiled dex file: " + << pci->DumpDexReference(profile_index); + return kInlineCacheMissingTypes; } - } - if (!found) { - VLOG(compiler) << "Could not find profiled dex file: " << offline_profile.dex_references[i]; - return kInlineCacheMissingTypes; + dex_profile_index_to_dex_cache[class_ref.dex_profile_index] = + caller_compilation_unit_.GetClassLinker()->FindDexCache(self, *dex_file); + DCHECK(dex_profile_index_to_dex_cache[class_ref.dex_profile_index] != nullptr); } } @@ -751,7 +745,7 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile( dex_cache, caller_compilation_unit_.GetClassLoader().Get()); if (clazz != nullptr) { - inline_cache->Set(ic_index++, clazz); + ic->Set(ic_index++, clazz); } else { VLOG(compiler) << "Could not resolve class from inline cache in AOT mode " << invoke_instruction->GetMethodReference().PrettyMethod() @@ -761,7 +755,9 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile( return kInlineCacheMissingTypes; } } - return GetInlineCacheType(inline_cache); + + *inline_cache = ic; + return GetInlineCacheType(ic); } HInstanceFieldGet* HInliner::BuildGetReceiverClass(ClassLinker* class_linker, diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 9041c7a4d7..9503641bcb 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -187,15 +187,6 @@ class HInliner : public HOptimization { /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache) REQUIRES_SHARED(Locks::mutator_lock_); - // Extract the mirror classes from the offline profile and add them to the `inline_cache`. - // Note that even if we have profile data for the invoke the inline_cache might contain - // only null entries if the types cannot be resolved. - InlineCacheType ExtractClassesFromOfflineProfile( - const HInvoke* invoke_instruction, - const ProfileCompilationInfo::OfflineProfileMethodInfo& offline_profile, - /*out*/Handle<mirror::ObjectArray<mirror::Class>> inline_cache) - REQUIRES_SHARED(Locks::mutator_lock_); - // Compute the inline cache type. InlineCacheType GetInlineCacheType( const Handle<mirror::ObjectArray<mirror::Class>>& classes) diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index 042ce55350..396f7b1961 100644 --- a/libartbase/base/common_art_test.cc +++ b/libartbase/base/common_art_test.cc @@ -669,4 +669,57 @@ CommonArtTestImpl::ForkAndExecResult CommonArtTestImpl::ForkAndExec( return ForkAndExec(argv, post_fork, string_collect_fn); } +bool CommonArtTestImpl::EqualInlineCaches( + const std::vector<ProfileMethodInfo::ProfileInlineCache>& expected, + const ProfileCompilationInfo::MethodHotness& actual_hotness, + const ProfileCompilationInfo& info) { + CHECK(actual_hotness.IsHot()); + CHECK(actual_hotness.GetInlineCacheMap() != nullptr); + const ProfileCompilationInfo::InlineCacheMap& actual = *actual_hotness.GetInlineCacheMap(); + if (expected.size() != actual.size()) { + return false; + } + // The `expected` data should be sorted by dex pc. + CHECK(std::is_sorted(expected.begin(), + expected.end(), + [](auto&& lhs, auto&& rhs) { return lhs.dex_pc < rhs.dex_pc; })); + // The `actual` data is a map sorted by dex pc, so we can just iterate over both. + auto expected_it = expected.begin(); + for (auto it = actual.begin(), end = actual.end(); it != end; ++it, ++expected_it) { + uint32_t dex_pc = it->first; + const ProfileCompilationInfo::DexPcData& dex_pc_data = it->second; + if (dex_pc != expected_it->dex_pc) { + return false; + } + if (dex_pc_data.is_missing_types != expected_it->is_missing_types) { + return false; + } else if (dex_pc_data.is_missing_types) { + continue; // The classes do not matter if we're missing some types. + } + // The `expected_it->is_megamorphic` is not initialized. Check the number of classes. + bool expected_is_megamorphic = + (expected_it->classes.size() >= ProfileCompilationInfo::kIndividualInlineCacheSize); + if (dex_pc_data.is_megamorphic != expected_is_megamorphic) { + return false; + } else if (dex_pc_data.is_megamorphic) { + continue; // The classes do not matter if the inline cache is megamorphic. + } + if (dex_pc_data.classes.size() != expected_it->classes.size()) { + return false; + } + for (const ProfileCompilationInfo::ClassReference& class_ref : dex_pc_data.classes) { + if (std::none_of(expected_it->classes.begin(), + expected_it->classes.end(), + [&](const TypeReference& type_ref) { + return (class_ref.type_index == type_ref.TypeIndex()) && + info.ProfileIndexMatchesDexFile(class_ref.dex_profile_index, + type_ref.dex_file); + })) { + return false; + } + } + } + return true; +} + } // namespace art diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h index 0f5fb0ccab..9835cd7ccb 100644 --- a/libartbase/base/common_art_test.h +++ b/libartbase/base/common_art_test.h @@ -35,6 +35,7 @@ #include "dex/art_dex_file_loader.h" #include "dex/compact_dex_level.h" #include "dex/compact_dex_file.h" +#include "profile/profile_compilation_info.h" namespace art { @@ -309,6 +310,10 @@ class CommonArtTestImpl { std::unique_ptr<const DexFile> OpenTestDexFile(const char* name); + // Compare different representations of inline caches for equality. + static bool EqualInlineCaches(const std::vector<ProfileMethodInfo::ProfileInlineCache>& expected, + const ProfileCompilationInfo::MethodHotness& actual_hotness, + const ProfileCompilationInfo& info); std::string android_data_; std::string android_system_ext_; diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc index 4b8fb9d782..702e0d3bce 100644 --- a/libprofile/profile/profile_compilation_info.cc +++ b/libprofile/profile/profile_compilation_info.cc @@ -1614,28 +1614,6 @@ ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness( : MethodHotness(); } -std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> -ProfileCompilationInfo::GetHotMethodInfo(const MethodReference& method_ref, - const ProfileSampleAnnotation& annotation) const { - MethodHotness hotness(GetMethodHotness(method_ref, annotation)); - if (!hotness.IsHot()) { - return nullptr; - } - const InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); - DCHECK(inline_caches != nullptr); - std::unique_ptr<OfflineProfileMethodInfo> pmi(new OfflineProfileMethodInfo(inline_caches)); - - pmi->dex_references.resize(info_.size()); - for (const DexFileData* dex_data : info_) { - pmi->dex_references[dex_data->profile_index].profile_key = dex_data->profile_key; - pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum; - pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids; - } - - return pmi; -} - - bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx, const ProfileSampleAnnotation& annotation) const { @@ -1906,111 +1884,6 @@ bool ProfileCompilationInfo::GenerateTestProfile( return info.Save(fd); } -bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==( - const OfflineProfileMethodInfo& other) const { - if (inline_caches->size() != other.inline_caches->size()) { - return false; - } - - // We can't use a simple equality test because we need to match the dex files - // of the inline caches which might have different profile indexes. - for (const auto& inline_cache_it : *inline_caches) { - uint16_t dex_pc = inline_cache_it.first; - const DexPcData dex_pc_data = inline_cache_it.second; - const auto& other_it = other.inline_caches->find(dex_pc); - if (other_it == other.inline_caches->end()) { - return false; - } - const DexPcData& other_dex_pc_data = other_it->second; - if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic || - dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) { - return false; - } - for (const ClassReference& class_ref : dex_pc_data.classes) { - bool found = false; - for (const ClassReference& other_class_ref : other_dex_pc_data.classes) { - CHECK_LE(class_ref.dex_profile_index, dex_references.size()); - CHECK_LE(other_class_ref.dex_profile_index, other.dex_references.size()); - const DexReference& dex_ref = dex_references[class_ref.dex_profile_index]; - const DexReference& other_dex_ref = other.dex_references[other_class_ref.dex_profile_index]; - if (class_ref.type_index == other_class_ref.type_index && - dex_ref == other_dex_ref) { - found = true; - break; - } - } - if (!found) { - return false; - } - } - } - return true; -} - -bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==( - const std::vector<ProfileMethodInfo::ProfileInlineCache>& runtime_caches) const { - if (inline_caches->size() != runtime_caches.size()) { - return false; - } - - for (const auto& inline_cache_it : *inline_caches) { - uint16_t dex_pc = inline_cache_it.first; - const DexPcData dex_pc_data = inline_cache_it.second; - - // Find the corresponding inline cahce. - const ProfileMethodInfo::ProfileInlineCache* runtime_cache = nullptr; - for (const ProfileMethodInfo::ProfileInlineCache& pic : runtime_caches) { - if (pic.dex_pc == dex_pc) { - runtime_cache = &pic; - break; - } - } - // If not found, returnb false. - if (runtime_cache == nullptr) { - return false; - } - // Check that the inline cache properties match up. - if (dex_pc_data.is_missing_types) { - if (!runtime_cache->is_missing_types) { - return false; - } else { - // If the inline cache is megamorphic do not check the classes (they don't matter). - continue; - } - } - - if (dex_pc_data.is_megamorphic) { - if (runtime_cache->classes.size() < ProfileCompilationInfo::kIndividualInlineCacheSize) { - return false; - } else { - // If the inline cache is megamorphic do not check the classes (they don't matter). - continue; - } - } - - if (dex_pc_data.classes.size() != runtime_cache->classes.size()) { - return false; - } - // Verify that all classes matches. - for (const ClassReference& class_ref : dex_pc_data.classes) { - bool found = false; - const DexReference& dex_ref = dex_references[class_ref.dex_profile_index]; - for (const TypeReference& type_ref : runtime_cache->classes) { - if (class_ref.type_index == type_ref.TypeIndex() && - dex_ref.MatchesDex(type_ref.dex_file)) { - found = true; - break; - } - } - if (!found) { - return false; - } - } - } - // If we didn't fail until now, then the two inline caches are equal. - return true; -} - bool ProfileCompilationInfo::IsEmpty() const { DCHECK_EQ(info_.empty(), profile_key_map_.empty()); return info_.empty(); @@ -2251,10 +2124,10 @@ size_t ProfileCompilationInfo::GetSizeErrorThresholdBytes() const { } std::ostream& operator<<(std::ostream& stream, - const ProfileCompilationInfo::DexReference& dex_ref) { - stream << "[profile_key=" << dex_ref.profile_key - << ",dex_checksum=" << std::hex << dex_ref.dex_checksum << std::dec - << ",num_method_ids=" << dex_ref.num_method_ids + ProfileCompilationInfo::DexReferenceDumper dumper) { + stream << "[profile_key=" << dumper.GetProfileKey() + << ",dex_checksum=" << std::hex << dumper.GetDexChecksum() << std::dec + << ",num_method_ids=" << dumper.GetNumMethodIds() << "]"; return stream; } diff --git a/libprofile/profile/profile_compilation_info.h b/libprofile/profile/profile_compilation_info.h index 622bec10b3..97660f3290 100644 --- a/libprofile/profile/profile_compilation_info.h +++ b/libprofile/profile/profile_compilation_info.h @@ -17,12 +17,14 @@ #ifndef ART_LIBPROFILE_PROFILE_PROFILE_COMPILATION_INFO_H_ #define ART_LIBPROFILE_PROFILE_PROFILE_COMPILATION_INFO_H_ +#include <array> #include <list> #include <set> #include <vector> #include "base/arena_containers.h" #include "base/arena_object.h" +#include "base/array_ref.h" #include "base/atomic.h" #include "base/bit_memory_region.h" #include "base/hash_set.h" @@ -91,35 +93,8 @@ class ProfileCompilationInfo { // This is exposed as public in order to make it available to dex2oat compilations // (see compiler/optimizing/inliner.cc). - // A profile reference to the dex file (profile key, dex checksum and number of methods). - // - // This contains references to internal std::string data of a profile key. The profile - // key must not be modified or destroyed for the entire lifetime of a `DexReference`. - struct DexReference { - DexReference() : dex_checksum(0), num_method_ids(0) {} - - DexReference(std::string_view key, uint32_t checksum, uint32_t num_methods) - : profile_key(key), dex_checksum(checksum), num_method_ids(num_methods) {} - - bool operator==(const DexReference& other) const { - return dex_checksum == other.dex_checksum && - profile_key == other.profile_key && - num_method_ids == other.num_method_ids; - } - - bool MatchesDex(const DexFile* dex_file) const { - return dex_checksum == dex_file->GetLocationChecksum() && - GetBaseKeyViewFromAugmentedKey(profile_key) == - GetProfileDexFileBaseKeyView(dex_file->GetLocation()); - } - - std::string_view profile_key; - uint32_t dex_checksum; - uint32_t num_method_ids; - }; - // The types used to manipulate the profile index of dex files. - // They set an upper limit to how many dex files a given profile can recored. + // They set an upper limit to how many dex files a given profile can record. // // Boot profiles have more needs than regular profiles as they contain data from // many apps merged together. As such they set the default type for data manipulation. @@ -135,11 +110,10 @@ class ProfileCompilationInfo { // Encodes a class reference in the profile. // The owning dex file is encoded as the index (dex_profile_index) it has in the - // profile rather than as a full DexRefence(location,checksum). + // profile rather than as a full reference (location, checksum). // This avoids excessive string copying when managing the profile data. - // The dex_profile_index is an index in either of: - // - OfflineProfileMethodInfo#dex_references vector (public use) - // - DexFileData#profile_index (internal use). + // The dex_profile_index is an index in the `DexFileData::profile_index` (internal use) + // and a matching dex file can found with `FindDexFileForProfileIndex()`. // Note that the dex_profile_index is not necessary the multidex index. // We cannot rely on the actual multidex index because a single profile may store // data from multiple splits. This means that a profile may contain a classes2.dex from split-A @@ -273,14 +247,14 @@ class ProfileCompilationInfo { return flags_ != 0; } - private: - const InlineCacheMap* inline_cache_map_ = nullptr; - uint32_t flags_ = 0; - const InlineCacheMap* GetInlineCacheMap() const { return inline_cache_map_; } + private: + const InlineCacheMap* inline_cache_map_ = nullptr; + uint32_t flags_ = 0; + void SetInlineCacheMap(const InlineCacheMap* info) { inline_cache_map_ = info; } @@ -288,29 +262,6 @@ class ProfileCompilationInfo { friend class ProfileCompilationInfo; }; - // Encodes the full set of inline caches for a given method. - // - // The `dex_references` vector is indexed according to the ClassReference::dex_profile_index. - // i.e. the dex file of any ClassReference present in the inline caches can be found at - // dex_references[ClassReference::dex_profile_index]. - // - // The `dex_references` contains references to internal std::string data of profile keys. - // Those profile keys must not be modified or destroyed for the entire lifetime of the - // `OfflineProfileMethodInfo`. To ensure that, the `ProfileCompilationInfo` should not - // be modified or destroyed while an `OfflineProfileMethodInfo` is in use. - struct OfflineProfileMethodInfo { - explicit OfflineProfileMethodInfo(const InlineCacheMap* inline_cache_map) - : inline_caches(inline_cache_map) {} - - bool operator==(const OfflineProfileMethodInfo& other) const; - // Checks that this offline representation of inline caches matches the runtime view of the - // data. - bool operator==(const std::vector<ProfileMethodInfo::ProfileInlineCache>& other) const; - - const InlineCacheMap* const inline_caches; - std::vector<DexReference> dex_references; - }; - // Encapsulates metadata that can be associated with the methods and classes added to the profile. // The additional metadata is serialized in the profile and becomes part of the profile key // representation. It can be used to differentiate the samples that are added to the profile @@ -338,6 +289,9 @@ class ProfileCompilationInfo { const std::string origin_package_name_; }; + // Helper class for printing referenced dex file information to a stream. + struct DexReferenceDumper; + // Public methods to create, extend or query the profile. ProfileCompilationInfo(); explicit ProfileCompilationInfo(bool for_boot_image); @@ -427,7 +381,7 @@ class ProfileCompilationInfo { // - No class id exceeds NumTypeIds corresponding to the dex_file. // - For every inline_caches, class_ids does not exceed NumTypeIds corresponding to // the dex_file they are in. - bool VerifyProfileData(const std::vector<const DexFile *> &dex_files); + bool VerifyProfileData(const std::vector<const DexFile*>& dex_files); // Load profile information from the given file // If the current profile is non-empty the load will fail. @@ -449,6 +403,11 @@ class ProfileCompilationInfo { // Save the current profile into the given file. The file will be cleared before saving. bool Save(const std::string& filename, uint64_t* bytes_written); + // Return the number of dex files referenced in the profile. + size_t GetNumberOfDexFiles() const { + return info_.size(); + } + // Return the number of methods that were profiled. uint32_t GetNumberOfMethods() const; @@ -476,15 +435,35 @@ class ProfileCompilationInfo { dex::TypeIndex type_idx, const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) const; - // Return the hot method info for the given location and index from the profiling info. - // If the method index is not found or the checksum doesn't match, null is returned. - // Note: the inline cache map is a pointer to the map stored in the profile and - // its allocation will go away if the profile goes out of scope. - // - // Note: see GetMethodHotness docs for the handling of annotations. - std::unique_ptr<OfflineProfileMethodInfo> GetHotMethodInfo( - const MethodReference& method_ref, - const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) const; + // Return the dex file for the given `profile_index`, or null if none of the provided + // dex files has a matching checksum and a location with the same base key. + template <typename Container> + const DexFile* FindDexFileForProfileIndex(ProfileIndexType profile_index, + const Container& dex_files) const { + static_assert(std::is_same_v<typename Container::value_type, const DexFile*> || + std::is_same_v<typename Container::value_type, std::unique_ptr<const DexFile>>); + DCHECK_LE(profile_index, info_.size()); + const DexFileData* dex_file_data = info_[profile_index]; + DCHECK(dex_file_data != nullptr); + uint32_t dex_checksum = dex_file_data->checksum; + std::string_view base_key = GetBaseKeyViewFromAugmentedKey(dex_file_data->profile_key); + for (const auto& dex_file : dex_files) { + if (dex_checksum == dex_file->GetLocationChecksum() && + base_key == GetProfileDexFileBaseKeyView(dex_file->GetLocation())) { + return std::addressof(*dex_file); + } + } + return nullptr; + } + + // Helper function for tests. + bool ProfileIndexMatchesDexFile(ProfileIndexType profile_index, const DexFile* dex_file) const { + DCHECK(dex_file != nullptr); + std::array<const DexFile*, 1u> dex_files{dex_file}; + return dex_file == FindDexFileForProfileIndex(profile_index, dex_files); + } + + DexReferenceDumper DumpDexReference(ProfileIndexType profile_index) const; // Dump all the loaded profile info into a string and returns it. // If dex_files is not empty then the method indices will be resolved to their @@ -541,10 +520,6 @@ class ProfileCompilationInfo { uint16_t class_percentage, uint32_t random_seed); - // Check that the given profile method info contain the same data. - static bool Equals(const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi1, - const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi2); - ArenaAllocator* GetAllocator() { return &allocator_; } // Return all of the class descriptors in the profile for a set of dex files. @@ -713,10 +688,6 @@ class ProfileCompilationInfo { dex_file->NumMethodIds()); } - // Encode the known dex_files into a vector. The index of a dex_reference will - // be the same as the profile index of the dex file (used to encode the ClassReferences). - void DexFileToProfileIndex(/*out*/std::vector<DexReference>* dex_references) const; - // Return the dex data associated with the given profile key or null if the profile // doesn't contain the key. const DexFileData* FindDexData(const std::string& profile_key, @@ -1071,8 +1042,28 @@ class FlattenProfileData { friend class ProfileCompilationInfo; }; -std::ostream& operator<<(std::ostream& stream, - const ProfileCompilationInfo::DexReference& dex_ref); +struct ProfileCompilationInfo::DexReferenceDumper { + const std::string& GetProfileKey() { + return dex_file_data->profile_key; + } + + uint32_t GetDexChecksum() const { + return dex_file_data->checksum; + } + + uint32_t GetNumMethodIds() const { + return dex_file_data->num_method_ids; + } + + const DexFileData* dex_file_data; +}; + +inline ProfileCompilationInfo::DexReferenceDumper ProfileCompilationInfo::DumpDexReference( + ProfileIndexType profile_index) const { + return DexReferenceDumper{info_[profile_index]}; +} + +std::ostream& operator<<(std::ostream& stream, ProfileCompilationInfo::DexReferenceDumper dumper); } // namespace art diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc index a207125968..1e5cdc5693 100644 --- a/libprofile/profile/profile_compilation_info_test.cc +++ b/libprofile/profile/profile_compilation_info_test.cc @@ -102,19 +102,12 @@ class ProfileCompilationInfoTest : public CommonArtTest { return static_cast<uint32_t>(file.GetFd()); } - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> GetMethod( + ProfileCompilationInfo::MethodHotness GetMethod( const ProfileCompilationInfo& info, const DexFile* dex, uint16_t method_idx, const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { - return info.GetHotMethodInfo(MethodReference(dex, method_idx), annotation); - } - - // Creates an inline cache which will be destructed at the end of the test. - ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { - used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( - std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile))); - return used_inline_caches.back().get(); + return info.GetMethodHotness(MethodReference(dex, method_idx), annotation); } // Creates the default inline caches used in tests. @@ -123,7 +116,7 @@ class ProfileCompilationInfoTest : public CommonArtTest { // Monomorphic for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { std::vector<TypeReference> types = {TypeReference(dex1, dex::TypeIndex(0))}; - inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types)); + inline_caches.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ false, types)); } // Polymorphic for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { @@ -131,23 +124,24 @@ class ProfileCompilationInfoTest : public CommonArtTest { TypeReference(dex1, dex::TypeIndex(0)), TypeReference(dex2, dex::TypeIndex(1)), TypeReference(dex3, dex::TypeIndex(2))}; - inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types)); + inline_caches.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ false, types)); } // Megamorphic for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { - // we need 5 types to make the cache megamorphic + // We need 5 types to make the cache megamorphic. + // The `is_megamorphic` flag shall be `false`; it is not used for testing. std::vector<TypeReference> types = { TypeReference(dex1, dex::TypeIndex(0)), TypeReference(dex1, dex::TypeIndex(1)), TypeReference(dex1, dex::TypeIndex(2)), TypeReference(dex1, dex::TypeIndex(3)), TypeReference(dex1, dex::TypeIndex(4))}; - inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types)); + inline_caches.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ false, types)); } // Missing types for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { std::vector<TypeReference> types; - inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ true, types)); + inline_caches.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ true, types)); } return inline_caches; @@ -524,14 +518,14 @@ TEST_F(ProfileCompilationInfoTest, SaveInlineCaches) { ASSERT_TRUE(loaded_info.Equals(saved_info)); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 = + ProfileCompilationInfo::MethodHotness loaded_hotness1 = GetMethod(loaded_info, dex1, /* method_idx= */ 3); - ASSERT_TRUE(loaded_pmi1 != nullptr); - ASSERT_TRUE(*loaded_pmi1 == inline_caches); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 = + ASSERT_TRUE(loaded_hotness1.IsHot()); + ASSERT_TRUE(EqualInlineCaches(inline_caches, loaded_hotness1, loaded_info)); + ProfileCompilationInfo::MethodHotness loaded_hotness2 = GetMethod(loaded_info, dex4, /* method_idx= */ 3); - ASSERT_TRUE(loaded_pmi2 != nullptr); - ASSERT_TRUE(*loaded_pmi2 == inline_caches); + ASSERT_TRUE(loaded_hotness2.IsHot()); + ASSERT_TRUE(EqualInlineCaches(inline_caches, loaded_hotness2, loaded_info)); } TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCaches) { @@ -569,11 +563,11 @@ TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCaches) { ASSERT_TRUE(loaded_info.Equals(saved_info)); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 = + ProfileCompilationInfo::MethodHotness loaded_hotness1 = GetMethod(loaded_info, dex1, /* method_idx= */ 3); - ASSERT_TRUE(loaded_pmi1 != nullptr); - ASSERT_TRUE(*loaded_pmi1 == inline_caches_extra); + ASSERT_TRUE(loaded_hotness1.IsHot()); + ASSERT_TRUE(EqualInlineCaches(inline_caches_extra, loaded_hotness1, loaded_info)); } TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) { @@ -619,10 +613,10 @@ TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) { ASSERT_TRUE(loaded_info.Equals(saved_info)); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 = + ProfileCompilationInfo::MethodHotness loaded_hotness1 = GetMethod(loaded_info, dex1, /* method_idx= */ 3); - ASSERT_TRUE(loaded_pmi1 != nullptr); - ASSERT_TRUE(*loaded_pmi1 == missing_types); + ASSERT_TRUE(loaded_hotness1.IsHot()); + ASSERT_TRUE(EqualInlineCaches(missing_types, loaded_hotness1, loaded_info)); } TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) { @@ -681,14 +675,12 @@ TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) { // Merging should have no effect as we're adding the exact same stuff. ASSERT_TRUE(info.Equals(info_backup)); for (uint16_t method_idx = 0; method_idx < 10; method_idx++) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 = - GetMethod(info, dex1, method_idx); - ASSERT_TRUE(loaded_pmi1 != nullptr); - ASSERT_TRUE(*loaded_pmi1 == inline_caches); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 = - GetMethod(info, dex2, method_idx); - ASSERT_TRUE(loaded_pmi2 != nullptr); - ASSERT_TRUE(*loaded_pmi2 == inline_caches); + ProfileCompilationInfo::MethodHotness loaded_hotness1 = GetMethod(info, dex1, method_idx); + ASSERT_TRUE(loaded_hotness1.IsHot()); + ASSERT_TRUE(EqualInlineCaches(inline_caches, loaded_hotness1, info)); + ProfileCompilationInfo::MethodHotness loaded_hotness2 = GetMethod(info, dex2, method_idx); + ASSERT_TRUE(loaded_hotness2.IsHot()); + ASSERT_TRUE(EqualInlineCaches(inline_caches, loaded_hotness2, info)); } } @@ -919,9 +911,9 @@ TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOk) { // Verify that we find the methods when searched with the original dex files. for (const std::unique_ptr<const DexFile>& dex : dex_files) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi = + ProfileCompilationInfo::MethodHotness loaded_hotness = GetMethod(info, dex.get(), /* method_idx= */ 0); - ASSERT_TRUE(loaded_pmi != nullptr); + ASSERT_TRUE(loaded_hotness.IsHot()); } // Release the ownership as this is held by the test class; @@ -943,15 +935,15 @@ TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOkButNoUpdate) { // Verify that we did not perform any update and that we cannot find anything with the new // location. for (const std::unique_ptr<const DexFile>& dex : dex_files) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi = + ProfileCompilationInfo::MethodHotness loaded_hotness = GetMethod(info, dex.get(), /* method_idx= */ 0); - ASSERT_TRUE(loaded_pmi == nullptr); + ASSERT_FALSE(loaded_hotness.IsHot()); } // Verify that we can find the original entry. - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi = + ProfileCompilationInfo::MethodHotness loaded_hotness = GetMethod(info, dex2, /* method_idx= */ 0); - ASSERT_TRUE(loaded_pmi != nullptr); + ASSERT_TRUE(loaded_hotness.IsHot()); // Release the ownership as this is held by the test class; for (std::unique_ptr<const DexFile>& dex : dex_files) { @@ -1009,64 +1001,62 @@ TEST_F(ProfileCompilationInfoTest, FilteredLoading) { ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn)); // Verify that we filtered out locations during load. + ASSERT_EQ(2u, loaded_info.GetNumberOfDexFiles()); // Dex location 2 and 4 should have been filtered out for (uint16_t method_idx = 0; method_idx < 10; method_idx++) { - ASSERT_TRUE(nullptr == GetMethod(loaded_info, dex2, method_idx)); - ASSERT_TRUE(nullptr == GetMethod(loaded_info, dex4, method_idx)); + ASSERT_FALSE(GetMethod(loaded_info, dex2, method_idx).IsHot()); + ASSERT_FALSE(GetMethod(loaded_info, dex4, method_idx).IsHot()); } // Dex location 1 should have all all the inline caches referencing dex location 2 set to // missing types. for (uint16_t method_idx = 0; method_idx < 10; method_idx++) { // The methods for dex location 1 should be in the profile data. - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 = + ProfileCompilationInfo::MethodHotness loaded_hotness1 = GetMethod(loaded_info, dex1, method_idx); - ASSERT_TRUE(loaded_pmi1 != nullptr); + ASSERT_TRUE(loaded_hotness1.IsHot()); // Verify the inline cache. // Everything should be as constructed by GetTestInlineCaches with the exception // of the inline caches referring types from dex_location2. // These should be set to IsMissingType. - ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); + std::vector<ProfileInlineCache> expected_ics; // Monomorphic types should remain the same as dex_location1 was kept. for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { - ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); - dex_pc_data.AddClass(0, dex::TypeIndex(0)); - ic_map->Put(dex_pc, dex_pc_data); + std::vector<TypeReference> types = {TypeReference(dex1, dex::TypeIndex(0))}; + expected_ics.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ false, types)); } + // Polymorphic inline cache should have been transformed to IsMissingType due to // the removal of dex_location2. for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { - ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); - dex_pc_data.SetIsMissingTypes(); - ic_map->Put(dex_pc, dex_pc_data); + std::vector<TypeReference> types; + expected_ics.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ true, types)); } // Megamorphic are not affected by removal of dex files. for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { - ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); - dex_pc_data.SetIsMegamorphic(); - ic_map->Put(dex_pc, dex_pc_data); + // We need 5 types to make the cache megamorphic. + // The `is_megamorphic` flag shall be `false`; it is not used for testing. + std::vector<TypeReference> types = { + TypeReference(dex1, dex::TypeIndex(0)), + TypeReference(dex1, dex::TypeIndex(1)), + TypeReference(dex1, dex::TypeIndex(2)), + TypeReference(dex1, dex::TypeIndex(3)), + TypeReference(dex1, dex::TypeIndex(4))}; + expected_ics.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ false, types)); } + // Missing types are not affected be removal of dex files. for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { - ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); - dex_pc_data.SetIsMissingTypes(); - ic_map->Put(dex_pc, dex_pc_data); + std::vector<TypeReference> types; + expected_ics.push_back(ProfileInlineCache(dex_pc, /*missing_types=*/ true, types)); } - ProfileCompilationInfo::OfflineProfileMethodInfo expected_pmi(ic_map); - - // The dex references should not have dex_location2 in the list. - expected_pmi.dex_references.emplace_back( - dex1->GetLocation(), dex1->GetLocationChecksum(), dex1->NumMethodIds()); - expected_pmi.dex_references.emplace_back( - dex3->GetLocation(), dex3->GetLocationChecksum(), dex3->NumMethodIds()); - // Now check that we get back what we expect. - ASSERT_TRUE(*loaded_pmi1 == expected_pmi); + ASSERT_TRUE(EqualInlineCaches(expected_ics, loaded_hotness1, loaded_info)); } } @@ -1132,16 +1122,16 @@ TEST_F(ProfileCompilationInfoTest, FilteredLoadingKeepAll) { ASSERT_TRUE(loaded_info.Equals(saved_info)); for (uint16_t method_idx = 0; method_idx < 10; method_idx++) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 = + ProfileCompilationInfo::MethodHotness loaded_hotness1 = GetMethod(loaded_info, dex1, method_idx); - ASSERT_TRUE(loaded_pmi1 != nullptr); - ASSERT_TRUE(*loaded_pmi1 == inline_caches); + ASSERT_TRUE(loaded_hotness1.IsHot()); + ASSERT_TRUE(EqualInlineCaches(inline_caches, loaded_hotness1, loaded_info)); } for (uint16_t method_idx = 0; method_idx < 10; method_idx++) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 = + ProfileCompilationInfo::MethodHotness loaded_hotness2 = GetMethod(loaded_info, dex4, method_idx); - ASSERT_TRUE(loaded_pmi2 != nullptr); - ASSERT_TRUE(*loaded_pmi2 == inline_caches); + ASSERT_TRUE(loaded_hotness2.IsHot()); + ASSERT_TRUE(EqualInlineCaches(inline_caches, loaded_hotness2, loaded_info)); } } @@ -1414,14 +1404,13 @@ TEST_F(ProfileCompilationInfoTest, AddMethodsProfileMethodInfoInlineCaches) { info.AddMethod(ProfileMethodInfo(startup, inline_caches), Hotness::kFlagStartup); // Check the hot method's inline cache. - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> hot_pmi = - GetMethod(info, dex1, hot.index); - ASSERT_TRUE(hot_pmi != nullptr); - ASSERT_EQ(hot_pmi->inline_caches->size(), 1u); - ASSERT_TRUE(hot_pmi->inline_caches->Get(0).is_missing_types); + ProfileCompilationInfo::MethodHotness hot_hotness = GetMethod(info, dex1, hot.index); + ASSERT_TRUE(hot_hotness.IsHot()); + ASSERT_EQ(hot_hotness.GetInlineCacheMap()->size(), 1u); + ASSERT_TRUE(hot_hotness.GetInlineCacheMap()->Get(0).is_missing_types); // Check there's no inline caches for the startup method. - ASSERT_TRUE(GetMethod(info, dex1, startup.index) == nullptr); + ASSERT_FALSE(GetMethod(info, dex1, startup.index).IsHot()); } // Verifies that we correctly add methods to the profile according to their flags. @@ -1453,37 +1442,37 @@ TEST_F(ProfileCompilationInfoTest, AddAnnotationsToMethods) { // Check that all methods are in. for (uint16_t i = 0; i < 10; i++) { EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsInProfile()); - EXPECT_TRUE(info.GetHotMethodInfo(MethodReference(dex1, i), psa1) != nullptr); + EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsHot()); } for (uint16_t i = 5; i < 15; i++) { EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile()); - EXPECT_TRUE(info.GetHotMethodInfo(MethodReference(dex1, i), psa2) != nullptr); + EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsHot()); } // Check that the non-overlapping methods are not added with a wrong annotation. for (uint16_t i = 10; i < 15; i++) { EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsInProfile()); - EXPECT_FALSE(info.GetHotMethodInfo(MethodReference(dex1, i), psa1) != nullptr); + EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsHot()); } for (uint16_t i = 0; i < 5; i++) { EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile()); - EXPECT_FALSE(info.GetHotMethodInfo(MethodReference(dex1, i), psa2) != nullptr); + EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsHot()); } // Check that when querying without an annotation only the first one is searched. for (uint16_t i = 0; i < 10; i++) { EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i)).IsInProfile()); - EXPECT_TRUE(info.GetHotMethodInfo(MethodReference(dex1, i)) != nullptr); + EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i)).IsHot()); } // ... this should be false because they belong the second appearance of dex1. for (uint16_t i = 10; i < 15; i++) { EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i)).IsInProfile()); - EXPECT_FALSE(info.GetHotMethodInfo(MethodReference(dex1, i)) != nullptr); + EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i)).IsHot()); } // Check that the methods cannot be found with a non existing annotation. MethodReference ref(dex1, 0); - ProfileSampleAnnotation not_exisiting("A"); - EXPECT_FALSE(info.GetMethodHotness(ref, not_exisiting).IsInProfile()); - EXPECT_FALSE(info.GetHotMethodInfo(ref, not_exisiting) != nullptr); + ProfileSampleAnnotation not_existing("A"); + EXPECT_FALSE(info.GetMethodHotness(ref, not_existing).IsInProfile()); + EXPECT_FALSE(info.GetMethodHotness(ref, not_existing).IsHot()); }; // Run the test before save. @@ -1653,9 +1642,9 @@ TEST_F(ProfileCompilationInfoTest, MergeWithInlineCaches) { for (uint16_t i = 0; i < 10; i++) { EXPECT_TRUE(info_12.GetMethodHotness(MethodReference(dex1, i), psa1).IsInProfile()); EXPECT_TRUE(info_12.ContainsClass(*dex1, dex::TypeIndex(i), psa1)); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_ic_12 = + ProfileCompilationInfo::MethodHotness loaded_ic_12 = GetMethod(info_12, dex1, /* method_idx= */ i); - ASSERT_TRUE(loaded_ic_12 != nullptr); + ASSERT_TRUE(loaded_ic_12.IsHot()); std::vector<TypeReference> cls_pc12; cls_pc12.resize(dex1_type_12.size() + dex2_type_48.size(), TypeReference(nullptr, dex::TypeIndex(-1))); @@ -1674,9 +1663,8 @@ TEST_F(ProfileCompilationInfoTest, MergeWithInlineCaches) { /* pc= */ 15, /* missing_types= */ false, /* profile_classes= */ cls_pc15) }; - EXPECT_EQ(loaded_ic_12->dex_references.size(), 2u); - EXPECT_EQ(loaded_ic_12->inline_caches->size(), expected.size()); - EXPECT_TRUE(*loaded_ic_12 == expected) << i; + EXPECT_EQ(loaded_ic_12.GetInlineCacheMap()->size(), expected.size()); + EXPECT_TRUE(EqualInlineCaches(expected, loaded_ic_12, info_12)) << i; } } diff --git a/oatdump/oatdump_app_test.cc b/oatdump/oatdump_app_test.cc index b4997ba8db..9c37707b4e 100644 --- a/oatdump/oatdump_app_test.cc +++ b/oatdump/oatdump_app_test.cc @@ -19,36 +19,36 @@ namespace art { TEST_F(OatDumpTest, TestAppWithBootImage) { - ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"})); - ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode)); + ASSERT_TRUE(GenerateAppOdexFile(Flavor::kDynamic, {"--runtime-arg", "-Xmx64M"})); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeOatWithBootImage, {}, kListAndCode)); } TEST_F(OatDumpTest, TestAppWithBootImageStatic) { TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); - ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"})); - ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode)); + ASSERT_TRUE(GenerateAppOdexFile(Flavor::kStatic, {"--runtime-arg", "-Xmx64M"})); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeOatWithBootImage, {}, kListAndCode)); } TEST_F(OatDumpTest, TestAppImageWithBootImage) { TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS(); // GC bug, b/126305867 const std::string app_image_arg = "--app-image-file=" + GetAppImageName(); - ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M", app_image_arg})); - ASSERT_TRUE(Exec(kDynamic, kModeAppImage, {}, kListAndCode)); + ASSERT_TRUE(GenerateAppOdexFile(Flavor::kDynamic, {"--runtime-arg", "-Xmx64M", app_image_arg})); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeAppImage, {}, kListAndCode)); } TEST_F(OatDumpTest, TestAppImageWithBootImageStatic) { TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS(); // GC bug, b/126305867 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); const std::string app_image_arg = "--app-image-file=" + GetAppImageName(); - ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M", app_image_arg})); - ASSERT_TRUE(Exec(kStatic, kModeAppImage, {}, kListAndCode)); + ASSERT_TRUE(GenerateAppOdexFile(Flavor::kStatic, {"--runtime-arg", "-Xmx64M", app_image_arg})); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeAppImage, {}, kListAndCode)); } TEST_F(OatDumpTest, TestAppImageInvalidPath) { TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS(); // GC bug, b/126305867 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); const std::string app_image_arg = "--app-image-file=" + GetAppImageName(); - ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M", app_image_arg})); + ASSERT_TRUE(GenerateAppOdexFile(Flavor::kStatic, {"--runtime-arg", "-Xmx64M", app_image_arg})); SetAppImageName("missing_app_image.art"); - ASSERT_TRUE(Exec(kStatic, kModeAppImage, {}, kListAndCode, /*expect_failure=*/true)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeAppImage, {}, kListAndCode, /*expect_failure=*/true)); } } // namespace art diff --git a/oatdump/oatdump_image_test.cc b/oatdump/oatdump_image_test.cc index 627010522f..7308f828b1 100644 --- a/oatdump/oatdump_image_test.cc +++ b/oatdump/oatdump_image_test.cc @@ -26,25 +26,25 @@ namespace art { TEST_F(OatDumpTest, TestImage) { TEST_DISABLED_FOR_ARM_AND_ARM64(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeArt, {}, kListAndCode)); } TEST_F(OatDumpTest, TestImageStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeArt, {}, kListAndCode)); } TEST_F(OatDumpTest, TestOatImage) { TEST_DISABLED_FOR_ARM_AND_ARM64(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeCoreOat, {}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeCoreOat, {}, kListAndCode)); } TEST_F(OatDumpTest, TestOatImageStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeCoreOat, {}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeCoreOat, {}, kListAndCode)); } } // namespace art diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc index 0c98cc1c7f..7615260299 100644 --- a/oatdump/oatdump_test.cc +++ b/oatdump/oatdump_test.cc @@ -28,61 +28,61 @@ namespace art { TEST_F(OatDumpTest, TestNoDumpVmap) { TEST_DISABLED_FOR_ARM_AND_ARM64(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode)); } TEST_F(OatDumpTest, TestNoDumpVmapStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode)); } TEST_F(OatDumpTest, TestNoDisassemble) { TEST_DISABLED_FOR_ARM_AND_ARM64(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode)); } TEST_F(OatDumpTest, TestNoDisassembleStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeArt, {"--no-disassemble"}, kListAndCode)); } TEST_F(OatDumpTest, TestListClasses) { TEST_DISABLED_FOR_ARM_AND_ARM64(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly)); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeArt, {"--list-classes"}, kListOnly)); } TEST_F(OatDumpTest, TestListClassesStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeArt, {"--list-classes"}, kListOnly)); } TEST_F(OatDumpTest, TestListMethods) { TEST_DISABLED_FOR_ARM_AND_ARM64(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly)); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeArt, {"--list-methods"}, kListOnly)); } TEST_F(OatDumpTest, TestListMethodsStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeArt, {"--list-methods"}, kListOnly)); } TEST_F(OatDumpTest, TestSymbolize) { TEST_DISABLED_FOR_TARGET(); // Can not write files inside the apex directory. std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly)); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeSymbolize, {}, kListOnly)); } TEST_F(OatDumpTest, TestSymbolizeStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly)); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeSymbolize, {}, kListOnly)); } TEST_F(OatDumpTest, TestExportDex) { @@ -90,8 +90,8 @@ TEST_F(OatDumpTest, TestExportDex) { // Test is failing on target, b/77469384. TEST_DISABLED_FOR_TARGET(); std::string error_msg; - ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"})); - ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly)); + ASSERT_TRUE(GenerateAppOdexFile(Flavor::kDynamic, {"--runtime-arg", "-Xmx64M"})); + ASSERT_TRUE(Exec(Flavor::kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly)); const std::string dex_location = tmp_dir_+ "/" + android::base::Basename(GetTestDexFileName(GetAppBaseName().c_str())) + "_export.dex"; @@ -108,8 +108,8 @@ TEST_F(OatDumpTest, TestExportDexStatic) { TEST_DISABLED_FOR_ARM_AND_ARM64(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"})); - ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly)); + ASSERT_TRUE(GenerateAppOdexFile(Flavor::kStatic, {"--runtime-arg", "-Xmx64M"})); + ASSERT_TRUE(Exec(Flavor::kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly)); } } // namespace art diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index ece7128240..3ec5b94afa 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -65,7 +65,7 @@ class OatDumpTest : public CommonRuntimeTest { } // Linking flavor. - enum Flavor { + enum class Flavor { kDynamic, // oatdump(d), dex2oat(d) kStatic, // oatdump(d)s, dex2oat(d)s }; @@ -86,7 +86,7 @@ class OatDumpTest : public CommonRuntimeTest { } std::string GetExecutableFilePath(Flavor flavor, const char* name, bool bitness) { - return GetExecutableFilePath(name, kIsDebugBuild, flavor == kStatic, bitness); + return GetExecutableFilePath(name, kIsDebugBuild, flavor == Flavor::kStatic, bitness); } enum Mode { diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index 90786fa00e..0f85e10e1f 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -372,14 +372,14 @@ class ProfileAssistantTest : public CommonRuntimeTest { bool is_megamorphic, bool is_missing_types) REQUIRES_SHARED(Locks::mutator_lock_) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi = - info.GetHotMethodInfo(MethodReference( - method->GetDexFile(), method->GetDexMethodIndex())); - ASSERT_TRUE(pmi != nullptr); - ASSERT_TRUE(pmi->inline_caches->find(dex_pc) != pmi->inline_caches->end()); + ProfileCompilationInfo::MethodHotness hotness = + info.GetMethodHotness(MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); + ASSERT_TRUE(hotness.IsHot()); + const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); + ASSERT_TRUE(inline_caches->find(dex_pc) != inline_caches->end()); AssertInlineCaches(expected_clases, - pmi.get(), - pmi->inline_caches->find(dex_pc)->second, + info, + inline_caches->find(dex_pc)->second, is_megamorphic, is_missing_types); } @@ -389,20 +389,20 @@ class ProfileAssistantTest : public CommonRuntimeTest { bool is_megamorphic, bool is_missing_types) REQUIRES_SHARED(Locks::mutator_lock_) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi = - info.GetHotMethodInfo(MethodReference( - method->GetDexFile(), method->GetDexMethodIndex())); - ASSERT_TRUE(pmi != nullptr); - ASSERT_EQ(pmi->inline_caches->size(), 1u); + ProfileCompilationInfo::MethodHotness hotness = + info.GetMethodHotness(MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); + ASSERT_TRUE(hotness.IsHot()); + const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); + ASSERT_EQ(inline_caches->size(), 1u); AssertInlineCaches(expected_clases, - pmi.get(), - pmi->inline_caches->begin()->second, + info, + inline_caches->begin()->second, is_megamorphic, is_missing_types); } void AssertInlineCaches(const TypeReferenceSet& expected_clases, - ProfileCompilationInfo::OfflineProfileMethodInfo* pmi, + const ProfileCompilationInfo& info, const ProfileCompilationInfo::DexPcData& dex_pc_data, bool is_megamorphic, bool is_missing_types) @@ -413,9 +413,8 @@ class ProfileAssistantTest : public CommonRuntimeTest { size_t found = 0; for (const TypeReference& type_ref : expected_clases) { for (const auto& class_ref : dex_pc_data.classes) { - ProfileCompilationInfo::DexReference dex_ref = - pmi->dex_references[class_ref.dex_profile_index]; - if (dex_ref.MatchesDex(type_ref.dex_file) && class_ref.type_index == type_ref.TypeIndex()) { + if (class_ref.type_index == type_ref.TypeIndex() && + info.ProfileIndexMatchesDexFile(class_ref.dex_profile_index, type_ref.dex_file)) { found++; } } @@ -832,9 +831,9 @@ TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) { for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) { if (!method.IsCopied() && method.GetCodeItem() != nullptr) { ++method_count; - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi = - info.GetHotMethodInfo(MethodReference(method.GetDexFile(), method.GetDexMethodIndex())); - ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod(); + ProfileCompilationInfo::MethodHotness hotness = + info.GetMethodHotness(MethodReference(method.GetDexFile(), method.GetDexMethodIndex())); + ASSERT_TRUE(hotness.IsHot()) << method.PrettyMethod(); } } EXPECT_GT(method_count, 0u); @@ -1328,11 +1327,10 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { // Verify that method noInlineCache has no inline caches in the profile. ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache"); ASSERT_TRUE(no_inline_cache != nullptr); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache = - info.GetHotMethodInfo(MethodReference( - no_inline_cache->GetDexFile(), no_inline_cache->GetDexMethodIndex())); - ASSERT_TRUE(pmi_no_inline_cache != nullptr); - ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty()); + ProfileCompilationInfo::MethodHotness hotness_no_inline_cache = info.GetMethodHotness( + MethodReference(no_inline_cache->GetDexFile(), no_inline_cache->GetDexMethodIndex())); + ASSERT_TRUE(hotness_no_inline_cache.IsHot()); + ASSERT_TRUE(hotness_no_inline_cache.GetInlineCacheMap()->empty()); } { @@ -1469,11 +1467,10 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCacheMulti"); ASSERT_TRUE(no_inline_cache != nullptr); - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache = - info.GetHotMethodInfo( - MethodReference(no_inline_cache->GetDexFile(), no_inline_cache->GetDexMethodIndex())); - ASSERT_TRUE(pmi_no_inline_cache != nullptr); - ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty()); + ProfileCompilationInfo::MethodHotness hotness_no_inline_cache = info.GetMethodHotness( + MethodReference(no_inline_cache->GetDexFile(), no_inline_cache->GetDexMethodIndex())); + ASSERT_TRUE(hotness_no_inline_cache.IsHot()); + ASSERT_TRUE(hotness_no_inline_cache.GetInlineCacheMap()->empty()); } } @@ -1552,11 +1549,12 @@ TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) { const DexFile* dex_file = inline_monomorphic->GetDexFile(); // Verify that the inline cache contains the invalid type. - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi = - info.GetHotMethodInfo(MethodReference(dex_file, inline_monomorphic->GetDexMethodIndex())); - ASSERT_TRUE(pmi != nullptr); - ASSERT_EQ(pmi->inline_caches->size(), 1u); - const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second; + ProfileCompilationInfo::MethodHotness hotness = + info.GetMethodHotness(MethodReference(dex_file, inline_monomorphic->GetDexMethodIndex())); + ASSERT_TRUE(hotness.IsHot()); + const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); + ASSERT_EQ(inline_caches->size(), 1u); + const ProfileCompilationInfo::DexPcData& dex_pc_data = inline_caches->begin()->second; dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1); ASSERT_EQ(1u, dex_pc_data.classes.size()); ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index); @@ -1768,12 +1766,11 @@ TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) { // Verify that the renaming was done. for (uint16_t i = 0; i < num_methods_to_add; i ++) { - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi; - ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(&d1, i)) != nullptr) << i; - ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(&d2, i)) != nullptr) << i; + ASSERT_TRUE(result.GetMethodHotness(MethodReference(&d1, i)).IsHot()) << i; + ASSERT_TRUE(result.GetMethodHotness(MethodReference(&d2, i)).IsHot()) << i; - ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(dex_to_be_updated1, i)) == nullptr); - ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(dex_to_be_updated2, i)) == nullptr); + ASSERT_FALSE(result.GetMethodHotness(MethodReference(dex_to_be_updated1, i)).IsHot()) << i; + ASSERT_FALSE(result.GetMethodHotness(MethodReference(dex_to_be_updated2, i)).IsHot()) << i; } } diff --git a/profman/profman.cc b/profman/profman.cc index 3e7e0281aa..9672f2b109 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -767,11 +767,13 @@ class ProfMan final { const dex::MethodId& id, const DexFile* dex_file, uint16_t dex_method_idx) { - auto method_info = profile_info.GetHotMethodInfo(MethodReference(dex_file, dex_method_idx)); - if (method_info == nullptr || method_info->inline_caches->empty()) { + ProfileCompilationInfo::MethodHotness hotness = + profile_info.GetMethodHotness(MethodReference(dex_file, dex_method_idx)); + DCHECK(!hotness.IsHot() || hotness.GetInlineCacheMap() != nullptr); + if (!hotness.IsHot() || hotness.GetInlineCacheMap()->empty()) { return ""; } - const ProfileCompilationInfo::InlineCacheMap* inline_caches = method_info->inline_caches; + const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); struct IcLineInfo { bool is_megamorphic_ = false; bool is_missing_types_ = false; @@ -799,14 +801,13 @@ class ProfMan final { val->second.is_missing_types_ = true; } for (auto cls : ic_data.classes) { - auto it = std::find_if(dex_files->begin(), dex_files->end(), [&](const auto& d) { - return method_info->dex_references[cls.dex_profile_index].MatchesDex(&*d); - }); - if (it == dex_files->end()) { + const DexFile* class_dex_file = + profile_info.FindDexFileForProfileIndex(cls.dex_profile_index, *dex_files); + if (class_dex_file == nullptr) { val->second.is_missing_types_ = true; continue; } - val->second.classes_.insert({ it->get(), cls.type_index }); + val->second.classes_.insert({ class_dex_file, cls.type_index }); } } if (ics.empty()) { diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc index efaea84160..870ec11b5e 100644 --- a/runtime/jit/profiling_info_test.cc +++ b/runtime/jit/profiling_info_test.cc @@ -154,40 +154,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { return used_inline_caches.back().get(); } - ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo( - const ProfileMethodInfo& pmi) { - ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); - ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map); - SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index - for (const auto& inline_cache : pmi.inline_caches) { - ProfileCompilationInfo::DexPcData& dex_pc_data = - ic_map->FindOrAdd( - inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second; - if (inline_cache.is_missing_types) { - dex_pc_data.SetIsMissingTypes(); - } - for (const auto& class_ref : inline_cache.classes) { - uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), - static_cast<uint8_t>(dex_map.size()))->second; - dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex()); - if (dex_profile_index >= offline_pmi.dex_references.size()) { - // This is a new dex. - const std::string& location = class_ref.dex_file->GetLocation(); - std::string dex_key = ProfileCompilationInfo::GetProfileDexFileBaseKey(location); - // The `dex_key` is a temporary that shall cease to exist soon. Create a view - // using the dex file's location as the backing data. - CHECK(EndsWith(location, dex_key)); - size_t dex_key_start = location.size() - dex_key.size(); - std::string_view dex_key_view(location.data() + dex_key_start, dex_key.size()); - offline_pmi.dex_references.emplace_back(dex_key_view, - class_ref.dex_file->GetLocationChecksum(), - class_ref.dex_file->NumMethodIds()); - } - } - } - return offline_pmi; - } - // Cannot sizeof the actual arrays so hard code the values here. // They should not change anyway. static constexpr int kProfileMagicSize = 4; @@ -292,12 +258,9 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { ASSERT_TRUE(h.IsHot()); ASSERT_TRUE(h.IsStartup()); const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = - info.GetHotMethodInfo(method_ref); - ASSERT_TRUE(offline_pmi != nullptr); - ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi = - ConvertProfileMethodInfo(pmi); - ASSERT_EQ(converted_pmi, *offline_pmi); + ProfileCompilationInfo::MethodHotness offline_hotness = info.GetMethodHotness(method_ref); + ASSERT_TRUE(offline_hotness.IsHot()); + ASSERT_TRUE(EqualInlineCaches(pmi.inline_caches, offline_hotness, info)); } } } |