diff options
author | 2021-04-14 09:39:04 +0000 | |
---|---|---|
committer | 2021-04-16 08:21:03 +0000 | |
commit | f4d05ff134347d723e27919ccc89ce9d412b2d58 (patch) | |
tree | aa368066676880ef1f4fbbec722ad8d88cad8771 | |
parent | c005ada78df5edebac74739b2c344e1a2a3efcba (diff) |
Clean up profile tests.
Use TestDexFileBuilder and remove FakeDex. Add a helper
class for shared code between ProfileCompilationInfoTest
and ProfileAssistantTest.
Test: m test-art-host-gtest
Test: run-gtests.sh
Bug: 148067697
Change-Id: I0bf5d3fb7a456dcd717bce694d7f832a654fcccb
-rw-r--r-- | dex2oat/linker/oat_writer_test.cc | 16 | ||||
-rw-r--r-- | libartbase/base/common_art_test.cc | 53 | ||||
-rw-r--r-- | libartbase/base/common_art_test.h | 71 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_loader.cc | 24 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_loader.h | 12 | ||||
-rw-r--r-- | libdexfile/dex/test_dex_file_builder.h | 116 | ||||
-rw-r--r-- | libdexfile/dex/test_dex_file_builder_test.cc | 4 | ||||
-rw-r--r-- | libprofile/profile/profile_compilation_info.h | 7 | ||||
-rw-r--r-- | libprofile/profile/profile_compilation_info_test.cc | 157 | ||||
-rw-r--r-- | libprofile/profile/profile_test_helper.h | 180 | ||||
-rw-r--r-- | profman/profile_assistant_test.cc | 56 | ||||
-rw-r--r-- | runtime/jit/profiling_info_test.cc | 3 |
12 files changed, 364 insertions, 335 deletions
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 6cb3ac8dd9..d765d21b3f 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -590,8 +590,8 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) { ScratchFile dex_file1; TestDexFileBuilder builder1; - builder1.AddField("Lsome.TestClass;", "int", "someField"); - builder1.AddMethod("Lsome.TestClass;", "()I", "foo"); + builder1.AddField("Lsome/TestClass;", "int", "someField"); + builder1.AddMethod("Lsome/TestClass;", "()I", "foo"); std::unique_ptr<const DexFile> dex_file1_data = builder1.Build(dex_file1.GetFilename()); MaybeModifyDexFileToFail(verify, dex_file1_data); @@ -607,8 +607,8 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) { ScratchFile dex_file2; TestDexFileBuilder builder2; - builder2.AddField("Land.AnotherTestClass;", "boolean", "someOtherField"); - builder2.AddMethod("Land.AnotherTestClass;", "()J", "bar"); + builder2.AddField("Land/AnotherTestClass;", "boolean", "someOtherField"); + builder2.AddMethod("Land/AnotherTestClass;", "()J", "bar"); std::unique_ptr<const DexFile> dex_file2_data = builder2.Build(dex_file2.GetFilename()); MaybeModifyDexFileToFail(verify, dex_file2_data); @@ -714,8 +714,8 @@ void OatTest::TestZipFileInput(bool verify, CopyOption copy) { ScratchFile dex_file1; TestDexFileBuilder builder1; - builder1.AddField("Lsome.TestClass;", "long", "someField"); - builder1.AddMethod("Lsome.TestClass;", "()D", "foo"); + builder1.AddField("Lsome/TestClass;", "long", "someField"); + builder1.AddMethod("Lsome/TestClass;", "()D", "foo"); std::unique_ptr<const DexFile> dex_file1_data = builder1.Build(dex_file1.GetFilename()); MaybeModifyDexFileToFail(verify, dex_file1_data); @@ -732,8 +732,8 @@ void OatTest::TestZipFileInput(bool verify, CopyOption copy) { ScratchFile dex_file2; TestDexFileBuilder builder2; - builder2.AddField("Land.AnotherTestClass;", "boolean", "someOtherField"); - builder2.AddMethod("Land.AnotherTestClass;", "()J", "bar"); + builder2.AddField("Land/AnotherTestClass;", "boolean", "someOtherField"); + builder2.AddMethod("Land/AnotherTestClass;", "()J", "bar"); std::unique_ptr<const DexFile> dex_file2_data = builder2.Build(dex_file2.GetFilename()); MaybeModifyDexFileToFail(verify, dex_file2_data); diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index 396f7b1961..042ce55350 100644 --- a/libartbase/base/common_art_test.cc +++ b/libartbase/base/common_art_test.cc @@ -669,57 +669,4 @@ 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 9835cd7ccb..8dd1f8868f 100644 --- a/libartbase/base/common_art_test.h +++ b/libartbase/base/common_art_test.h @@ -35,7 +35,6 @@ #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 { @@ -95,71 +94,6 @@ class ScratchFile { std::unique_ptr<File> file_; }; -// Close to store a fake dex file and its underlying data. -class FakeDex { - public: - static std::unique_ptr<FakeDex> Create( - const std::string& location, - uint32_t checksum, - uint32_t num_method_ids) { - FakeDex* fake_dex = new FakeDex(); - fake_dex->dex = CreateFakeDex(location, checksum, num_method_ids, &fake_dex->storage); - return std::unique_ptr<FakeDex>(fake_dex); - } - - static std::unique_ptr<const DexFile> CreateFakeDex( - const std::string& location, - uint32_t checksum, - uint32_t num_method_ids, - std::vector<uint8_t>* storage) { - storage->resize(kPageSize); - CompactDexFile::Header* header = - const_cast<CompactDexFile::Header*>(CompactDexFile::Header::At(storage->data())); - CompactDexFile::WriteMagic(header->magic_); - CompactDexFile::WriteCurrentVersion(header->magic_); - header->data_off_ = 0; - header->data_size_ = storage->size(); - header->method_ids_size_ = num_method_ids; - - const DexFileLoader dex_file_loader; - std::string error_msg; - std::unique_ptr<const DexFile> dex(dex_file_loader.Open(storage->data(), - storage->size(), - location, - checksum, - /*oat_dex_file=*/nullptr, - /*verify=*/false, - /*verify_checksum=*/false, - &error_msg)); - CHECK(dex != nullptr) << error_msg; - return dex; - } - - std::unique_ptr<const DexFile>& Dex() { - return dex; - } - - private: - std::vector<uint8_t> storage; - std::unique_ptr<const DexFile> dex; -}; - -// Convenience class to store multiple fake dex files in order to make -// allocation/de-allocation easier in tests. -class FakeDexStorage { - public: - const DexFile* AddFakeDex( - const std::string& location, - uint32_t checksum, - uint32_t num_method_ids) { - fake_dex_files.push_back(FakeDex::Create(location, checksum, num_method_ids)); - return fake_dex_files.back()->Dex().get(); - } - - private: - std::vector<std::unique_ptr<FakeDex>> fake_dex_files; -}; - // Helper class that removes an environment variable whilst in scope. class ScopedUnsetEnvironmentVariable { public: @@ -310,11 +244,6 @@ 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_; std::string dalvik_cache_; diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc index d3fac97296..861f911b67 100644 --- a/libdexfile/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc @@ -220,6 +220,30 @@ bool DexFileLoader::GetMultiDexChecksums( } std::unique_ptr<const DexFile> DexFileLoader::Open( + const std::string& location, + uint32_t location_checksum, + std::vector<uint8_t>&& memory, + const OatDexFile* oat_dex_file, + bool verify, + bool verify_checksum, + std::string* error_msg) { + auto memory_data = memory.data(); + auto memory_size = memory.size(); + return OpenCommon(memory_data, + memory_size, + /*data_base=*/ nullptr, + /*data_size=*/ 0, + location, + location_checksum, + oat_dex_file, + verify, + verify_checksum, + error_msg, + std::make_unique<VectorContainer>(std::move(memory)), + /*verify_result=*/ nullptr); +} + +std::unique_ptr<const DexFile> DexFileLoader::Open( const uint8_t* base, size_t size, const std::string& location, diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h index 923fb1f32f..d6268bc23e 100644 --- a/libdexfile/dex/dex_file_loader.h +++ b/libdexfile/dex/dex_file_loader.h @@ -125,7 +125,17 @@ class DexFileLoader { int zip_fd = -1, bool* zip_file_only_contains_uncompress_dex = nullptr) const; - // Opens .dex file, backed by existing memory + // Opens .dex file, backed by existing vector memory. + static std::unique_ptr<const DexFile> Open( + const std::string& location, + uint32_t location_checksum, + std::vector<uint8_t>&& memory, + const OatDexFile* oat_dex_file, + bool verify, + bool verify_checksum, + std::string* error_msg); + + // Opens .dex file, backed by existing memory. virtual std::unique_ptr<const DexFile> Open( const uint8_t* base, size_t size, diff --git a/libdexfile/dex/test_dex_file_builder.h b/libdexfile/dex/test_dex_file_builder.h index 2b0bad0854..283dd48401 100644 --- a/libdexfile/dex/test_dex_file_builder.h +++ b/libdexfile/dex/test_dex_file_builder.h @@ -26,6 +26,7 @@ #include <android-base/logging.h> +#include "base/array_ref.h" #include "base/bit_utils.h" #include "dex/dex_file_loader.h" #include "dex/standard_dex_file.h" @@ -35,24 +36,22 @@ namespace art { class TestDexFileBuilder { public: TestDexFileBuilder() - : strings_(), types_(), fields_(), protos_(), dex_file_data_() { + : strings_(), types_(), fields_(), protos_() { } void AddString(const std::string& str) { - CHECK(dex_file_data_.empty()); - auto it = strings_.emplace(str, IdxAndDataOffset()).first; - CHECK_LT(it->first.length(), 128u); // Don't allow multi-byte length in uleb128. + CHECK_LT(str.length(), 128u); // Don't allow multi-byte length in uleb128. + strings_.emplace(str, IdxAndDataOffset()); } void AddType(const std::string& descriptor) { - CHECK(dex_file_data_.empty()); AddString(descriptor); types_.emplace(descriptor, 0u); } - void AddField(const std::string& class_descriptor, const std::string& type, + void AddField(const std::string& class_descriptor, + const std::string& type, const std::string& name) { - CHECK(dex_file_data_.empty()); AddType(class_descriptor); AddType(type); AddString(name); @@ -60,9 +59,9 @@ class TestDexFileBuilder { fields_.emplace(key, 0u); } - void AddMethod(const std::string& class_descriptor, const std::string& signature, + void AddMethod(const std::string& class_descriptor, + const std::string& signature, const std::string& name) { - CHECK(dex_file_data_.empty()); AddType(class_descriptor); AddString(name); @@ -81,9 +80,8 @@ class TestDexFileBuilder { methods_.emplace(method_key, 0u); } - // NOTE: The builder holds the actual data, so it must live as long as the dex file. - std::unique_ptr<const DexFile> Build(const std::string& dex_location) { - CHECK(dex_file_data_.empty()); + std::unique_ptr<const DexFile> Build(const std::string& dex_location, + uint32_t location_checksum = 0u) { union { uint8_t data[sizeof(DexFile::Header)]; uint64_t force_alignment; @@ -164,19 +162,22 @@ class TestDexFileBuilder { header->data_off_ = (data_section_size != 0u) ? data_section_offset : 0u; uint32_t total_size = data_section_offset + data_section_size; - - dex_file_data_.resize(total_size); + std::vector<uint8_t> dex_file_data(total_size, 0u); for (const auto& entry : strings_) { CHECK_LT(entry.first.size(), 128u); uint32_t raw_offset = data_section_offset + entry.second.data_offset; - dex_file_data_[raw_offset] = static_cast<uint8_t>(entry.first.size()); - std::memcpy(&dex_file_data_[raw_offset + 1], entry.first.c_str(), entry.first.size() + 1); - Write32(string_ids_offset + entry.second.idx * sizeof(dex::StringId), raw_offset); + dex_file_data[raw_offset] = static_cast<uint8_t>(entry.first.size()); + std::memcpy(&dex_file_data[raw_offset + 1], entry.first.c_str(), entry.first.size() + 1); + Write32(dex_file_data, + string_ids_offset + entry.second.idx * sizeof(dex::StringId), + raw_offset); } for (const auto& entry : types_) { - Write32(type_ids_offset + entry.second * sizeof(dex::TypeId), GetStringIdx(entry.first)); + Write32(dex_file_data, + type_ids_offset + entry.second * sizeof(dex::TypeId), + GetStringIdx(entry.first)); ++type_idx; } @@ -185,14 +186,15 @@ class TestDexFileBuilder { uint32_t type_list_offset = (num_args != 0u) ? data_section_offset + entry.second.data_offset : 0u; uint32_t raw_offset = proto_ids_offset + entry.second.idx * sizeof(dex::ProtoId); - Write32(raw_offset + 0u, GetStringIdx(entry.first.shorty)); - Write16(raw_offset + 4u, GetTypeIdx(entry.first.return_type)); - Write32(raw_offset + 8u, type_list_offset); + Write32(dex_file_data, raw_offset + 0u, GetStringIdx(entry.first.shorty)); + Write16(dex_file_data, raw_offset + 4u, GetTypeIdx(entry.first.return_type)); + Write32(dex_file_data, raw_offset + 8u, type_list_offset); if (num_args != 0u) { CHECK_NE(entry.second.data_offset, 0u); - Write32(type_list_offset, num_args); + Write32(dex_file_data, type_list_offset, num_args); for (size_t i = 0; i != num_args; ++i) { - Write16(type_list_offset + 4u + i * sizeof(dex::TypeItem), + Write16(dex_file_data, + type_list_offset + 4u + i * sizeof(dex::TypeItem), GetTypeIdx(entry.first.args[i])); } } @@ -200,46 +202,46 @@ class TestDexFileBuilder { for (const auto& entry : fields_) { uint32_t raw_offset = field_ids_offset + entry.second * sizeof(dex::FieldId); - Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor)); - Write16(raw_offset + 2u, GetTypeIdx(entry.first.type)); - Write32(raw_offset + 4u, GetStringIdx(entry.first.name)); + Write16(dex_file_data, raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor)); + Write16(dex_file_data, raw_offset + 2u, GetTypeIdx(entry.first.type)); + Write32(dex_file_data, raw_offset + 4u, GetStringIdx(entry.first.name)); } for (const auto& entry : methods_) { uint32_t raw_offset = method_ids_offset + entry.second * sizeof(dex::MethodId); - Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor)); + Write16(dex_file_data, raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor)); auto it = protos_.find(*entry.first.proto); CHECK(it != protos_.end()); - Write16(raw_offset + 2u, it->second.idx); - Write32(raw_offset + 4u, GetStringIdx(entry.first.name)); + Write16(dex_file_data, raw_offset + 2u, it->second.idx); + Write32(dex_file_data, raw_offset + 4u, GetStringIdx(entry.first.name)); } // Leave signature as zeros. - header->file_size_ = dex_file_data_.size(); + header->file_size_ = dex_file_data.size(); // Write the complete header early, as part of it needs to be checksummed. - std::memcpy(&dex_file_data_[0], header_data.data, sizeof(DexFile::Header)); + std::memcpy(&dex_file_data[0], header_data.data, sizeof(DexFile::Header)); // Checksum starts after the checksum field. size_t skip = sizeof(header->magic_) + sizeof(header->checksum_); header->checksum_ = adler32(adler32(0L, Z_NULL, 0), - dex_file_data_.data() + skip, - dex_file_data_.size() - skip); + dex_file_data.data() + skip, + dex_file_data.size() - skip); // Write the complete header again, just simpler that way. - std::memcpy(&dex_file_data_[0], header_data.data, sizeof(DexFile::Header)); + std::memcpy(&dex_file_data[0], header_data.data, sizeof(DexFile::Header)); + + // Do not protect the final data from writing. Some tests need to modify it. static constexpr bool kVerify = false; static constexpr bool kVerifyChecksum = false; std::string error_msg; - const DexFileLoader dex_file_loader; - std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open( - &dex_file_data_[0], - dex_file_data_.size(), + std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open( dex_location, - 0u, - nullptr, + location_checksum, + std::move(dex_file_data), + /*oat_dex_file=*/ nullptr, kVerify, kVerifyChecksum, &error_msg)); @@ -366,25 +368,25 @@ class TestDexFileBuilder { return key; } - void Write32(size_t offset, uint32_t value) { - CHECK_LE(offset + 4u, dex_file_data_.size()); - CHECK_EQ(dex_file_data_[offset + 0], 0u); - CHECK_EQ(dex_file_data_[offset + 1], 0u); - CHECK_EQ(dex_file_data_[offset + 2], 0u); - CHECK_EQ(dex_file_data_[offset + 3], 0u); - dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0); - dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8); - dex_file_data_[offset + 2] = static_cast<uint8_t>(value >> 16); - dex_file_data_[offset + 3] = static_cast<uint8_t>(value >> 24); + static void Write32(std::vector<uint8_t>& dex_file_data, size_t offset, uint32_t value) { + CHECK_LE(offset + 4u, dex_file_data.size()); + CHECK_EQ(dex_file_data[offset + 0], 0u); + CHECK_EQ(dex_file_data[offset + 1], 0u); + CHECK_EQ(dex_file_data[offset + 2], 0u); + CHECK_EQ(dex_file_data[offset + 3], 0u); + dex_file_data[offset + 0] = static_cast<uint8_t>(value >> 0); + dex_file_data[offset + 1] = static_cast<uint8_t>(value >> 8); + dex_file_data[offset + 2] = static_cast<uint8_t>(value >> 16); + dex_file_data[offset + 3] = static_cast<uint8_t>(value >> 24); } - void Write16(size_t offset, uint32_t value) { + static void Write16(std::vector<uint8_t>& dex_file_data, size_t offset, uint32_t value) { CHECK_LE(value, 0xffffu); - CHECK_LE(offset + 2u, dex_file_data_.size()); - CHECK_EQ(dex_file_data_[offset + 0], 0u); - CHECK_EQ(dex_file_data_[offset + 1], 0u); - dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0); - dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8); + CHECK_LE(offset + 2u, dex_file_data.size()); + CHECK_EQ(dex_file_data[offset + 0], 0u); + CHECK_EQ(dex_file_data[offset + 1], 0u); + dex_file_data[offset + 0] = static_cast<uint8_t>(value >> 0); + dex_file_data[offset + 1] = static_cast<uint8_t>(value >> 8); } std::map<std::string, IdxAndDataOffset> strings_; @@ -392,8 +394,6 @@ class TestDexFileBuilder { std::map<FieldKey, uint32_t, FieldKeyComparator> fields_; std::map<ProtoKey, IdxAndDataOffset, ProtoKeyComparator> protos_; std::map<MethodKey, uint32_t, MethodKeyComparator> methods_; - - std::vector<uint8_t> dex_file_data_; }; } // namespace art diff --git a/libdexfile/dex/test_dex_file_builder_test.cc b/libdexfile/dex/test_dex_file_builder_test.cc index 11e073a8a1..9aeaded1ab 100644 --- a/libdexfile/dex/test_dex_file_builder_test.cc +++ b/libdexfile/dex/test_dex_file_builder_test.cc @@ -80,7 +80,9 @@ TEST(TestDexFileBuilderTest, SimpleTest) { EXPECT_EQ(2u, builder.GetTypeIdx("Ljava/lang/Class;")); EXPECT_EQ(0u, builder.GetFieldIdx("LTestClass;", "[I", "intField")); EXPECT_EQ(1u, builder.GetMethodIdx("LTestClass;", "()I", "foo")); - EXPECT_EQ(0u, builder.GetMethodIdx("LTestClass;", "(Ljava/lang/Object;[Ljava/lang/Object;)LTestClass;", "bar")); + EXPECT_EQ(0u, builder.GetMethodIdx("LTestClass;", + "(Ljava/lang/Object;[Ljava/lang/Object;)LTestClass;", + "bar")); } } // namespace art diff --git a/libprofile/profile/profile_compilation_info.h b/libprofile/profile/profile_compilation_info.h index 99794d139c..1cf8da588e 100644 --- a/libprofile/profile/profile_compilation_info.h +++ b/libprofile/profile/profile_compilation_info.h @@ -459,13 +459,6 @@ class ProfileCompilationInfo { 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. diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc index a279717f6b..1e3c3b9610 100644 --- a/libprofile/profile/profile_compilation_info_test.cc +++ b/libprofile/profile/profile_compilation_info_test.cc @@ -27,77 +27,34 @@ #include "dex/method_reference.h" #include "dex/type_reference.h" #include "profile/profile_compilation_info.h" +#include "profile/profile_test_helper.h" #include "ziparchive/zip_writer.h" namespace art { -using Hotness = ProfileCompilationInfo::MethodHotness; -using ProfileInlineCache = ProfileMethodInfo::ProfileInlineCache; -using ProfileSampleAnnotation = ProfileCompilationInfo::ProfileSampleAnnotation; -using ProfileIndexType = ProfileCompilationInfo::ProfileIndexType; using ProfileIndexTypeRegular = ProfileCompilationInfo::ProfileIndexTypeRegular; using ItemMetadata = FlattenProfileData::ItemMetadata; -static constexpr size_t kMaxMethodIds = 65535; -static uint32_t kMaxHotnessFlagBootIndex = - WhichPowerOf2(static_cast<uint32_t>(Hotness::kFlagLastBoot)); -static uint32_t kMaxHotnessFlagRegularIndex = - WhichPowerOf2(static_cast<uint32_t>(Hotness::kFlagLastRegular)); - -class ProfileCompilationInfoTest : public CommonArtTest { +class ProfileCompilationInfoTest : public CommonArtTest, public ProfileTestHelper { public: void SetUp() override { CommonArtTest::SetUp(); allocator_.reset(new ArenaAllocator(&pool_)); - dex1 = fake_dex_storage.AddFakeDex("location1", /* checksum= */ 1, /* num_method_ids= */ 10001); - dex2 = fake_dex_storage.AddFakeDex("location2", /* checksum= */ 2, /* num_method_ids= */ 10002); - dex3 = fake_dex_storage.AddFakeDex("location3", /* checksum= */ 3, /* num_method_ids= */ 10003); - dex4 = fake_dex_storage.AddFakeDex("location4", /* checksum= */ 4, /* num_method_ids= */ 10004); - - dex1_checksum_missmatch = fake_dex_storage.AddFakeDex( - "location1", /* checksum= */ 12, /* num_method_ids= */ 10001); - dex1_renamed = fake_dex_storage.AddFakeDex( - "location1-renamed", /* checksum= */ 1, /* num_method_ids= */ 10001); - dex2_renamed = fake_dex_storage.AddFakeDex( - "location2-renamed", /* checksum= */ 2, /* num_method_ids= */ 10002); + dex1 = BuildDex("location1", /* checksum= */ 1, "LUnique1;", /* num_method_ids= */ 101); + dex2 = BuildDex("location2", /* checksum= */ 2, "LUnique2;", /* num_method_ids= */ 102); + dex3 = BuildDex("location3", /* checksum= */ 3, "LUnique3;", /* num_method_ids= */ 103); + dex4 = BuildDex("location4", /* checksum= */ 4, "LUnique4;", /* num_method_ids= */ 104); - dex_max_methods1 = fake_dex_storage.AddFakeDex( - "location-max1", /* checksum= */ 5, /* num_method_ids= */ kMaxMethodIds); - dex_max_methods2 = fake_dex_storage.AddFakeDex( - "location-max2", /* checksum= */ 6, /* num_method_ids= */ kMaxMethodIds); + dex1_checksum_missmatch = + BuildDex("location1", /* checksum= */ 12, "LUnique1;", /* num_method_ids= */ 101); + dex1_renamed = + BuildDex("location1-renamed", /* checksum= */ 1, "LUnique1;", /* num_method_ids= */ 101); + dex2_renamed = + BuildDex("location2-renamed", /* checksum= */ 2, "LUnique2;", /* num_method_ids= */ 102); } protected: - bool AddMethod(ProfileCompilationInfo* info, - const DexFile* dex, - uint16_t method_idx, - Hotness::Flag flags = Hotness::kFlagHot, - const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { - return info->AddMethod(ProfileMethodInfo(MethodReference(dex, method_idx)), - flags, - annotation); - } - - bool AddMethod(ProfileCompilationInfo* info, - const DexFile* dex, - uint16_t method_idx, - const std::vector<ProfileInlineCache>& inline_caches, - const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { - return info->AddMethod( - ProfileMethodInfo(MethodReference(dex, method_idx), inline_caches), - Hotness::kFlagHot, - annotation); - } - - bool AddClass(ProfileCompilationInfo* info, - const DexFile* dex, - dex::TypeIndex type_index, - const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { - std::vector<dex::TypeIndex> classes = {type_index}; - return info->AddClassesForDex(dex, classes.begin(), classes.end(), annotation); - } - uint32_t GetFd(const ScratchFile& file) { return static_cast<uint32_t>(file.GetFd()); } @@ -219,10 +176,9 @@ class ProfileCompilationInfoTest : public CommonArtTest { static constexpr size_t kNumDexFiles = 5; - FakeDexStorage local_storage; std::vector<const DexFile*> dex_files; for (uint32_t i = 0; i < kNumDexFiles; i++) { - dex_files.push_back(local_storage.AddFakeDex(std::to_string(i), i, kMaxMethodIds)); + dex_files.push_back(BuildDex(std::to_string(i), i, "LC;", kMaxMethodIds)); } std::srand(0); @@ -264,6 +220,13 @@ class ProfileCompilationInfoTest : public CommonArtTest { ASSERT_TRUE(loaded_reg.Load(GetFd(reg_file))); } + static constexpr size_t kMaxMethodIds = 65535; + static constexpr size_t kMaxClassIds = 65535; + static constexpr uint32_t kMaxHotnessFlagBootIndex = + WhichPowerOf2(static_cast<uint32_t>(Hotness::kFlagLastBoot)); + static constexpr uint32_t kMaxHotnessFlagRegularIndex = + WhichPowerOf2(static_cast<uint32_t>(Hotness::kFlagLastRegular)); + // Cannot sizeof the actual arrays so hard code the values here. // They should not change anyway. static constexpr int kProfileMagicSize = 4; @@ -279,15 +242,11 @@ class ProfileCompilationInfoTest : public CommonArtTest { const DexFile* dex1_checksum_missmatch; const DexFile* dex1_renamed; const DexFile* dex2_renamed; - const DexFile* dex_max_methods1; - const DexFile* dex_max_methods2; // Cache of inline caches generated during tests. // This makes it easier to pass data between different utilities and ensure that // caches are destructed at the end of the test. std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; - - FakeDexStorage fake_dex_storage; }; TEST_F(ProfileCompilationInfoTest, SaveFd) { @@ -366,16 +325,22 @@ TEST_F(ProfileCompilationInfoTest, MergeFdFail) { TEST_F(ProfileCompilationInfoTest, SaveMaxMethods) { ScratchFile profile; + const DexFile* dex_max1 = BuildDex( + "location-max1", /* checksum= */ 5, "LUniqueMax1;", kMaxMethodIds, kMaxClassIds); + const DexFile* dex_max2 = BuildDex( + "location-max2", /* checksum= */ 6, "LUniqueMax2;", kMaxMethodIds, kMaxClassIds); + + ProfileCompilationInfo saved_info; // Save the maximum number of methods for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) { - ASSERT_TRUE(AddMethod(&saved_info, dex_max_methods1, /* method_idx= */ i)); - ASSERT_TRUE(AddMethod(&saved_info, dex_max_methods2, /* method_idx= */ i)); + ASSERT_TRUE(AddMethod(&saved_info, dex_max1, /* method_idx= */ i)); + ASSERT_TRUE(AddMethod(&saved_info, dex_max2, /* method_idx= */ i)); } // Save the maximum number of classes for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) { - ASSERT_TRUE(AddClass(&saved_info, dex1, dex::TypeIndex(i))); - ASSERT_TRUE(AddClass(&saved_info, dex2, dex::TypeIndex(i))); + ASSERT_TRUE(AddClass(&saved_info, dex_max1, dex::TypeIndex(i))); + ASSERT_TRUE(AddClass(&saved_info, dex_max2, dex::TypeIndex(i))); } ASSERT_TRUE(saved_info.Save(GetFd(profile))); @@ -685,32 +650,28 @@ TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) { } TEST_F(ProfileCompilationInfoTest, AddMoreDexFileThanLimitRegular) { - FakeDexStorage local_storage; ProfileCompilationInfo info; // Save a few methods. for (uint16_t i = 0; i < std::numeric_limits<ProfileIndexTypeRegular>::max(); i++) { std::string location = std::to_string(i); - const DexFile* dex = local_storage.AddFakeDex( - location, /* checksum= */ 1, /* num_method_ids= */ 1); + const DexFile* dex = BuildDex(location, /* checksum= */ 1, "LC;", /* num_method_ids= */ 1); ASSERT_TRUE(AddMethod(&info, dex, /* method_idx= */ 0)); } // Add an extra dex file. - const DexFile* dex = local_storage.AddFakeDex("-1", /* checksum= */ 1, /* num_method_ids= */ 1); + const DexFile* dex = BuildDex("-1", /* checksum= */ 1, "LC;", /* num_method_ids= */ 1); ASSERT_FALSE(AddMethod(&info, dex, /* method_idx= */ 0)); } TEST_F(ProfileCompilationInfoTest, AddMoreDexFileThanLimitBoot) { - FakeDexStorage local_storage; ProfileCompilationInfo info(/*for_boot_image=*/true); // Save a few methods. for (uint16_t i = 0; i < std::numeric_limits<ProfileIndexType>::max(); i++) { std::string location = std::to_string(i); - const DexFile* dex = local_storage.AddFakeDex( - location, /* checksum= */ 1, /* num_method_ids= */ 1); + const DexFile* dex = BuildDex(location, /* checksum= */ 1, "LC;", /* num_method_ids= */ 1); ASSERT_TRUE(AddMethod(&info, dex, /* method_idx= */ 0)); } // Add an extra dex file. - const DexFile* dex = local_storage.AddFakeDex("-1", /* checksum= */ 1, /* num_method_ids= */ 1); + const DexFile* dex = BuildDex("-1", /* checksum= */ 1, "LC;", /* num_method_ids= */ 1); ASSERT_FALSE(AddMethod(&info, dex, /* method_idx= */ 0)); } @@ -1166,31 +1127,43 @@ TEST_F(ProfileCompilationInfoTest, FilteredLoadingKeepAll) { TEST_F(ProfileCompilationInfoTest, FilteredLoadingWithClasses) { ScratchFile profile; + const DexFile* dex1_1000 = BuildDex("location1_1000", + /* checksum= */ 7, + "LC1_1000;", + /* num_method_ids = */ 1u, + /* num_class_ids = */ 1000u); + const DexFile* dex2_1000 = BuildDex("location2_1000", + /* checksum= */ 8, + "LC2_1000;", + /* num_method_ids = */ 1u, + /* num_class_ids = */ 1000u); + // Save a profile with 2 dex files containing just classes. ProfileCompilationInfo saved_info; uint16_t item_count = 1000; for (uint16_t i = 0; i < item_count; i++) { - ASSERT_TRUE(AddClass(&saved_info, dex1, dex::TypeIndex(i))); - ASSERT_TRUE(AddClass(&saved_info, dex2, dex::TypeIndex(i))); + ASSERT_TRUE(AddClass(&saved_info, dex1_1000, dex::TypeIndex(i))); + ASSERT_TRUE(AddClass(&saved_info, dex2_1000, dex::TypeIndex(i))); } ASSERT_TRUE(saved_info.Save(GetFd(profile))); ASSERT_EQ(0, profile.GetFile()->Flush()); - // Filter out dex locations: kepp only dex_location2. + // Filter out dex locations: keep only `dex2_1000->GetLocation()`. ProfileCompilationInfo loaded_info; ASSERT_TRUE(profile.GetFile()->ResetOffset()); ProfileCompilationInfo::ProfileLoadFilterFn filter_fn = - [&dex2 = dex2](const std::string& dex_location, uint32_t checksum) -> bool { - return (dex_location == dex2->GetLocation() && checksum == dex2->GetLocationChecksum()); + [dex2_1000](const std::string& dex_location, uint32_t checksum) -> bool { + return dex_location == dex2_1000->GetLocation() && + checksum == dex2_1000->GetLocationChecksum(); }; ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn)); // Compute the expectation. ProfileCompilationInfo expected_info; for (uint16_t i = 0; i < item_count; i++) { - ASSERT_TRUE(AddClass(&expected_info, dex2, dex::TypeIndex(i))); + ASSERT_TRUE(AddClass(&expected_info, dex2_1000, dex::TypeIndex(i))); } // Validate the expectation. @@ -1525,34 +1498,34 @@ TEST_F(ProfileCompilationInfoTest, AddAnnotationsToClasses) { ProfileSampleAnnotation psa1("test1"); ProfileSampleAnnotation psa2("test2"); // Save a few classes using different annotations, some overlapping, some not. - for (uint16_t i = 0; i < 10; i++) { + for (uint16_t i = 0; i < 7; i++) { ASSERT_TRUE(AddClass(&info, dex1, dex::TypeIndex(i), psa1)); } - for (uint16_t i = 5; i < 15; i++) { + for (uint16_t i = 3; i < 10; i++) { ASSERT_TRUE(AddClass(&info, dex1, dex::TypeIndex(i), psa2)); } auto run_test = [&dex1 = dex1, &psa1 = psa1, &psa2 = psa2](const ProfileCompilationInfo& info) { // Check that all classes are in. - for (uint16_t i = 0; i < 10; i++) { + for (uint16_t i = 0; i < 7; i++) { EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa1)); } - for (uint16_t i = 5; i < 15; i++) { + for (uint16_t i = 3; i < 10; i++) { EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2)); } // Check that the non-overlapping classes are not added with a wrong annotation. - for (uint16_t i = 10; i < 15; i++) { + for (uint16_t i = 7; i < 10; i++) { EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa1)); } - for (uint16_t i = 0; i < 5; i++) { + for (uint16_t i = 0; i < 3; i++) { EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2)); } // Check that when querying without an annotation only the first one is searched. - for (uint16_t i = 0; i < 10; i++) { + for (uint16_t i = 0; i < 7; i++) { EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i))); } // ... this should be false because they belong the second appearance of dex1. - for (uint16_t i = 10; i < 15; i++) { + for (uint16_t i = 7; i < 10; i++) { EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i))); } @@ -1585,11 +1558,11 @@ TEST_F(ProfileCompilationInfoTest, MergeWithAnnotations) { ProfileSampleAnnotation psa1("test1"); ProfileSampleAnnotation psa2("test2"); - for (uint16_t i = 0; i < 10; i++) { + for (uint16_t i = 0; i < 7; i++) { ASSERT_TRUE(AddMethod(&info1, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1)); ASSERT_TRUE(AddClass(&info1, dex1, dex::TypeIndex(i), psa1)); } - for (uint16_t i = 5; i < 15; i++) { + for (uint16_t i = 3; i < 10; i++) { ASSERT_TRUE(AddMethod(&info2, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1)); ASSERT_TRUE(AddMethod(&info2, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa2)); ASSERT_TRUE(AddMethod(&info2, dex2, /* method_idx= */ i, Hotness::kFlagHot, psa2)); @@ -1602,18 +1575,18 @@ TEST_F(ProfileCompilationInfoTest, MergeWithAnnotations) { ASSERT_TRUE(info.MergeWith(info2)); // Check that all items are in. - for (uint16_t i = 0; i < 15; i++) { + for (uint16_t i = 0; i < 10; i++) { EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsInProfile()); EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa1)); } - for (uint16_t i = 5; i < 15; i++) { + for (uint16_t i = 3; i < 10; i++) { EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile()); EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex2, i), psa2).IsInProfile()); EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2)); } // Check that the non-overlapping items are not added with a wrong annotation. - for (uint16_t i = 0; i < 5; i++) { + for (uint16_t i = 0; i < 3; i++) { EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile()); EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex2, i), psa2).IsInProfile()); EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2)); diff --git a/libprofile/profile/profile_test_helper.h b/libprofile/profile/profile_test_helper.h new file mode 100644 index 0000000000..859c8fb195 --- /dev/null +++ b/libprofile/profile/profile_test_helper.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_LIBPROFILE_PROFILE_PROFILE_TEST_HELPER_H_ +#define ART_LIBPROFILE_PROFILE_PROFILE_TEST_HELPER_H_ + +#include <memory> +#include <vector> + +#include "dex/test_dex_file_builder.h" +#include "profile/profile_compilation_info.h" + +namespace art { + +class ProfileTestHelper { + public: + ProfileTestHelper() = default; + + using Hotness = ProfileCompilationInfo::MethodHotness; + using ProfileInlineCache = ProfileMethodInfo::ProfileInlineCache; + using ProfileSampleAnnotation = ProfileCompilationInfo::ProfileSampleAnnotation; + using ProfileIndexType = ProfileCompilationInfo::ProfileIndexType; + + static bool AddMethod( + ProfileCompilationInfo* info, + const DexFile* dex, + uint16_t method_idx, + const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { + return AddMethod(info, dex, method_idx, Hotness::kFlagHot, annotation); + } + + static bool AddMethod( + ProfileCompilationInfo* info, + const DexFile* dex, + uint16_t method_idx, + Hotness::Flag flags, + const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { + return info->AddMethod( + ProfileMethodInfo(MethodReference(dex, method_idx)), flags, annotation); + } + + static bool AddMethod( + ProfileCompilationInfo* info, + const DexFile* dex, + uint16_t method_idx, + const std::vector<ProfileInlineCache>& inline_caches, + const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { + return AddMethod(info, dex, method_idx, inline_caches, Hotness::kFlagHot, annotation); + } + + static bool AddMethod( + ProfileCompilationInfo* info, + const DexFile* dex, + uint16_t method_idx, + const std::vector<ProfileInlineCache>& inline_caches, + Hotness::Flag flags, + const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { + return info->AddMethod( + ProfileMethodInfo(MethodReference(dex, method_idx), inline_caches), flags, annotation); + } + + static bool AddClass(ProfileCompilationInfo* info, + const DexFile* dex, + dex::TypeIndex type_index, + const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) { + std::vector<dex::TypeIndex> classes = {type_index}; + return info->AddClassesForDex(dex, classes.begin(), classes.end(), annotation); + } + + static bool ProfileIndexMatchesDexFile(const ProfileCompilationInfo& info, + ProfileIndexType profile_index, + const DexFile* dex_file) { + DCHECK(dex_file != nullptr); + std::array<const DexFile*, 1u> dex_files{dex_file}; + return dex_file == info.FindDexFileForProfileIndex(profile_index, dex_files); + } + + // 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) { + 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()) && + ProfileIndexMatchesDexFile(info, + class_ref.dex_profile_index, + type_ref.dex_file); + })) { + return false; + } + } + } + return true; + } + + protected: + static constexpr size_t kNumSharedTypes = 10u; + + const DexFile* BuildDex(const std::string& location, + uint32_t location_checksum, + const std::string& class_descriptor, + size_t num_method_ids, + size_t num_class_ids = kNumSharedTypes + 1u) { + TestDexFileBuilder builder; + for (size_t shared_type_index = 0; shared_type_index != kNumSharedTypes; ++shared_type_index) { + builder.AddType("LSharedType" + std::to_string(shared_type_index) + ";"); + } + builder.AddType(class_descriptor); + for (size_t i = kNumSharedTypes + 1u; i < num_class_ids; ++i) { + builder.AddType("LFiller" + std::to_string(i) + ";"); + } + for (size_t method_index = 0; method_index != num_method_ids; ++method_index) { + // Keep the number of protos and names low even for the maximum number of methods. + size_t return_type_index = method_index % kNumSharedTypes; + size_t arg_type_index = (method_index / kNumSharedTypes) % kNumSharedTypes; + size_t method_name_index = (method_index / kNumSharedTypes) / kNumSharedTypes; + std::string return_type = "LSharedType" + std::to_string(return_type_index) + ";"; + std::string arg_type = "LSharedType" + std::to_string(arg_type_index) + ";"; + std::string signature = "(" + arg_type + ")" + return_type; + builder.AddMethod(class_descriptor, signature, "m" + std::to_string(method_name_index)); + } + storage.push_back(builder.Build(location, location_checksum)); + return storage.back().get(); + } + + std::vector<std::unique_ptr<const DexFile>> storage; +}; + +} // namespace art + +#endif // ART_LIBPROFILE_PROFILE_PROFILE_TEST_HELPER_H_ diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index d01d4fbedf..e1e220ee84 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -35,59 +35,31 @@ #include "mirror/class-inl.h" #include "obj_ptr-inl.h" #include "profile/profile_compilation_info.h" +#include "profile/profile_test_helper.h" #include "profile_assistant.h" #include "scoped_thread_state_change-inl.h" namespace art { -using Hotness = ProfileCompilationInfo::MethodHotness; using TypeReferenceSet = std::set<TypeReference, TypeReferenceValueComparator>; -using ProfileInlineCache = ProfileMethodInfo::ProfileInlineCache; // TODO(calin): These tests share a lot with the ProfileCompilationInfo tests. // we should introduce a better abstraction to extract the common parts. -class ProfileAssistantTest : public CommonRuntimeTest { +class ProfileAssistantTest : public CommonRuntimeTest, public ProfileTestHelper { public: void PostRuntimeCreate() override { allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); - dex1 = fake_dex_storage.AddFakeDex("location1", /* checksum= */ 1, /* num_method_ids= */ 10001); - dex2 = fake_dex_storage.AddFakeDex("location2", /* checksum= */ 2, /* num_method_ids= */ 10002); - dex3 = fake_dex_storage.AddFakeDex("location3", /* checksum= */ 3, /* num_method_ids= */ 10003); - dex4 = fake_dex_storage.AddFakeDex("location4", /* checksum= */ 4, /* num_method_ids= */ 10004); + dex1 = BuildDex("location1", /* checksum= */ 1, "LUnique1;", /* num_method_ids= */ 10001); + dex2 = BuildDex("location2", /* checksum= */ 2, "LUnique2;", /* num_method_ids= */ 10002); + dex3 = BuildDex("location3", /* checksum= */ 3, "LUnique3;", /* num_method_ids= */ 10003); + dex4 = BuildDex("location4", /* checksum= */ 4, "LUnique4;", /* num_method_ids= */ 10004); - dex1_checksum_missmatch = fake_dex_storage.AddFakeDex( - "location1", /* checksum= */ 12, /* num_method_ids= */ 10001); + dex1_checksum_missmatch = + BuildDex("location1", /* checksum= */ 12, "LUnique1;", /* num_method_ids= */ 10001); } protected: - bool AddMethod(ProfileCompilationInfo* info, - const DexFile* dex, - uint16_t method_idx, - const std::vector<ProfileInlineCache>& inline_caches, - Hotness::Flag flags) { - return info->AddMethod( - ProfileMethodInfo(MethodReference(dex, method_idx), inline_caches), flags); - } - - bool AddMethod(ProfileCompilationInfo* info, - const DexFile* dex, - uint16_t method_idx, - Hotness::Flag flags, - const ProfileCompilationInfo::ProfileSampleAnnotation& annotation - = ProfileCompilationInfo::ProfileSampleAnnotation::kNone) { - return info->AddMethod(ProfileMethodInfo(MethodReference(dex, method_idx)), - flags, - annotation); - } - - bool AddClass(ProfileCompilationInfo* info, - const DexFile* dex, - dex::TypeIndex type_index) { - std::vector<dex::TypeIndex> classes = {type_index}; - return info->AddClassesForDex(dex, classes.begin(), classes.end()); - } - void SetupProfile(const DexFile* dex_file1, const DexFile* dex_file2, uint16_t number_of_methods, @@ -417,7 +389,7 @@ class ProfileAssistantTest : public CommonRuntimeTest { for (const TypeReference& type_ref : expected_clases) { for (const auto& class_ref : dex_pc_data.classes) { if (class_ref.type_index == type_ref.TypeIndex() && - info.ProfileIndexMatchesDexFile(class_ref.dex_profile_index, type_ref.dex_file)) { + ProfileIndexMatchesDexFile(info, class_ref.dex_profile_index, type_ref.dex_file)) { found++; } } @@ -476,7 +448,6 @@ class ProfileAssistantTest : public CommonRuntimeTest { const DexFile* dex3; const DexFile* dex4; const DexFile* dex1_checksum_missmatch; - FakeDexStorage fake_dex_storage; }; TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) { @@ -1827,11 +1798,10 @@ TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) { ProfileCompilationInfo info1; uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds()); - FakeDexStorage local_storage; - const DexFile* dex_to_be_updated1 = local_storage.AddFakeDex( - "fake-location1", d1.GetLocationChecksum(), d1.NumMethodIds()); - const DexFile* dex_to_be_updated2 = local_storage.AddFakeDex( - "fake-location2", d2.GetLocationChecksum(), d2.NumMethodIds()); + const DexFile* dex_to_be_updated1 = + BuildDex("fake-location1", d1.GetLocationChecksum(), "LC;", d1.NumMethodIds()); + const DexFile* dex_to_be_updated2 = + BuildDex("fake-location2", d2.GetLocationChecksum(), "LC;", d2.NumMethodIds()); SetupProfile(dex_to_be_updated1, dex_to_be_updated2, num_methods_to_add, diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc index 870ec11b5e..e502adc269 100644 --- a/runtime/jit/profiling_info_test.cc +++ b/runtime/jit/profiling_info_test.cc @@ -30,6 +30,7 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "profile/profile_compilation_info.h" +#include "profile/profile_test_helper.h" #include "scoped_thread_state_change-inl.h" namespace art { @@ -260,7 +261,7 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; ProfileCompilationInfo::MethodHotness offline_hotness = info.GetMethodHotness(method_ref); ASSERT_TRUE(offline_hotness.IsHot()); - ASSERT_TRUE(EqualInlineCaches(pmi.inline_caches, offline_hotness, info)); + ASSERT_TRUE(ProfileTestHelper::EqualInlineCaches(pmi.inline_caches, offline_hotness, info)); } } } |