summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2021-04-14 09:39:04 +0000
committer Vladimir Marko <vmarko@google.com> 2021-04-16 08:21:03 +0000
commitf4d05ff134347d723e27919ccc89ce9d412b2d58 (patch)
treeaa368066676880ef1f4fbbec722ad8d88cad8771
parentc005ada78df5edebac74739b2c344e1a2a3efcba (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.cc16
-rw-r--r--libartbase/base/common_art_test.cc53
-rw-r--r--libartbase/base/common_art_test.h71
-rw-r--r--libdexfile/dex/dex_file_loader.cc24
-rw-r--r--libdexfile/dex/dex_file_loader.h12
-rw-r--r--libdexfile/dex/test_dex_file_builder.h116
-rw-r--r--libdexfile/dex/test_dex_file_builder_test.cc4
-rw-r--r--libprofile/profile/profile_compilation_info.h7
-rw-r--r--libprofile/profile/profile_compilation_info_test.cc157
-rw-r--r--libprofile/profile/profile_test_helper.h180
-rw-r--r--profman/profile_assistant_test.cc56
-rw-r--r--runtime/jit/profiling_info_test.cc3
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));
}
}
}