Move profile testing to CommonArtTest
Finish the migration of libprofile content by moving test to use
CommonArtTest. This required splitting the libart-related portions into
a separate test that was moved closer to the code it tests.
Bug: 78459333
Test: make -j 40 test-art-host
Change-Id: I134c983b1a5ac81a71ac2b72d8c653eff5df4164
diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc
index ead7cba..42c3320 100644
--- a/libprofile/profile/profile_compilation_info_test.cc
+++ b/libprofile/profile/profile_compilation_info_test.cc
@@ -17,20 +17,14 @@
#include <gtest/gtest.h>
#include <stdio.h>
-#include "art_method-inl.h"
+#include "base/arena_allocator.h"
+#include "base/common_art_test.h"
#include "base/unix_file/fd_file.h"
-#include "class_linker-inl.h"
-#include "common_runtime_test.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "dex/method_reference.h"
#include "dex/type_reference.h"
-#include "handle_scope-inl.h"
-#include "linear_alloc.h"
-#include "mirror/class-inl.h"
-#include "mirror/class_loader.h"
#include "profile/profile_compilation_info.h"
-#include "scoped_thread_state_change-inl.h"
#include "ziparchive/zip_writer.h"
namespace art {
@@ -39,31 +33,14 @@
static constexpr size_t kMaxMethodIds = 65535;
-class ProfileCompilationInfoTest : public CommonRuntimeTest {
+class ProfileCompilationInfoTest : public CommonArtTest {
public:
- void PostRuntimeCreate() OVERRIDE {
- allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
+ void SetUp() OVERRIDE {
+ CommonArtTest::SetUp();
+ allocator_.reset(new ArenaAllocator(&pool_));
}
protected:
- std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader,
- const std::string& clazz) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Thread* self = Thread::Current();
- ScopedObjectAccess soa(self);
- StackHandleScope<1> hs(self);
- Handle<mirror::ClassLoader> h_loader(
- hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader()));
- ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader);
-
- const auto pointer_size = class_linker->GetImagePointerSize();
- std::vector<ArtMethod*> methods;
- for (auto& m : klass->GetVirtualMethods(pointer_size)) {
- methods.push_back(&m);
- }
- return methods;
- }
-
bool AddMethod(const std::string& dex_location,
uint32_t checksum,
uint16_t method_index,
@@ -97,89 +74,6 @@
return static_cast<uint32_t>(file.GetFd());
}
- bool SaveProfilingInfo(
- const std::string& filename,
- const std::vector<ArtMethod*>& methods,
- const std::set<DexCacheResolvedClasses>& resolved_classes,
- Hotness::Flag flags) {
- ProfileCompilationInfo info;
- std::vector<ProfileMethodInfo> profile_methods;
- ScopedObjectAccess soa(Thread::Current());
- for (ArtMethod* method : methods) {
- profile_methods.emplace_back(
- MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
- }
- if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) {
- return false;
- }
- if (info.GetNumberOfMethods() != profile_methods.size()) {
- return false;
- }
- ProfileCompilationInfo file_profile;
- if (!file_profile.Load(filename, false)) {
- return false;
- }
- if (!info.MergeWith(file_profile)) {
- return false;
- }
-
- return info.Save(filename, nullptr);
- }
-
- // Saves the given art methods to a profile backed by 'filename' and adds
- // some fake inline caches to it. The added inline caches are returned in
- // the out map `profile_methods_map`.
- bool SaveProfilingInfoWithFakeInlineCaches(
- const std::string& filename,
- const std::vector<ArtMethod*>& methods,
- Hotness::Flag flags,
- /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) {
- ProfileCompilationInfo info;
- std::vector<ProfileMethodInfo> profile_methods;
- ScopedObjectAccess soa(Thread::Current());
- for (ArtMethod* method : methods) {
- std::vector<ProfileMethodInfo::ProfileInlineCache> caches;
- // Monomorphic
- for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
- std::vector<TypeReference> classes;
- classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0));
- caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
- }
- // Polymorphic
- for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
- std::vector<TypeReference> classes;
- for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) {
- classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
- }
- caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
- }
- // Megamorphic
- for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
- std::vector<TypeReference> classes;
- for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) {
- classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
- }
- caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
- }
- // Missing types
- for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
- std::vector<TypeReference> classes;
- caches.emplace_back(dex_pc, /*is_missing_types*/true, classes);
- }
- ProfileMethodInfo pmi(MethodReference(method->GetDexFile(),
- method->GetDexMethodIndex()),
- caches);
- profile_methods.push_back(pmi);
- profile_methods_map->Put(method, pmi);
- }
-
- if (!info.AddMethods(profile_methods, flags)
- || info.GetNumberOfMethods() != profile_methods.size()) {
- return false;
- }
- return info.Save(filename, nullptr);
- }
-
// Creates an inline cache which will be destructed at the end of the test.
ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
@@ -187,35 +81,6 @@
return used_inline_caches.back().get();
}
- ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo(
- const ProfileMethodInfo& pmi) {
- ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
- ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map);
- SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index
- for (const auto& inline_cache : pmi.inline_caches) {
- ProfileCompilationInfo::DexPcData& dex_pc_data =
- ic_map->FindOrAdd(
- inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second;
- if (inline_cache.is_missing_types) {
- dex_pc_data.SetIsMissingTypes();
- }
- for (const auto& class_ref : inline_cache.classes) {
- uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file),
- static_cast<uint8_t>(dex_map.size()))->second;
- dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex());
- if (dex_profile_index >= offline_pmi.dex_references.size()) {
- // This is a new dex.
- const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey(
- class_ref.dex_file->GetLocation());
- offline_pmi.dex_references.emplace_back(dex_key,
- class_ref.dex_file->GetLocationChecksum(),
- class_ref.dex_file->NumMethodIds());
- }
- }
- }
- return offline_pmi;
- }
-
// Creates an offline profile used for testing inline caches.
ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() {
ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
@@ -261,7 +126,7 @@
ProfileCompilationInfo::InlineCacheMap* ic_map =
const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches);
for (auto it : *ic_map) {
- for (uint16_t k = 0; k <= 2 * InlineCache::kIndividualCacheSize; k++) {
+ for (uint16_t k = 0; k <= 2 * ProfileCompilationInfo::kIndividualInlineCacheSize; k++) {
it.second.AddClass(0, dex::TypeIndex(k));
}
}
@@ -327,6 +192,7 @@
static constexpr int kProfileMagicSize = 4;
static constexpr int kProfileVersionSize = 4;
+ MallocArenaPool pool_;
std::unique_ptr<ArenaAllocator> allocator_;
// Cache of inline caches generated during tests.
@@ -335,61 +201,6 @@
std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
};
-TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
- ScratchFile profile;
-
- Thread* self = Thread::Current();
- jobject class_loader;
- {
- ScopedObjectAccess soa(self);
- class_loader = LoadDex("ProfileTestMultiDex");
- }
- ASSERT_NE(class_loader, nullptr);
-
- // Save virtual methods from Main.
- std::set<DexCacheResolvedClasses> resolved_classes;
- std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
- ASSERT_TRUE(SaveProfilingInfo(
- profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup));
-
- // Check that what we saved is in the profile.
- ProfileCompilationInfo info1;
- ASSERT_TRUE(info1.Load(GetFd(profile)));
- ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size());
- {
- ScopedObjectAccess soa(self);
- for (ArtMethod* m : main_methods) {
- Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
- ASSERT_TRUE(h.IsHot());
- ASSERT_TRUE(h.IsPostStartup());
- }
- }
-
- // Save virtual methods from Second.
- std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;");
- ASSERT_TRUE(SaveProfilingInfo(
- profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup));
-
- // Check that what we saved is in the profile (methods form Main and Second).
- ProfileCompilationInfo info2;
- ASSERT_TRUE(profile.GetFile()->ResetOffset());
- ASSERT_TRUE(info2.Load(GetFd(profile)));
- ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size());
- {
- ScopedObjectAccess soa(self);
- for (ArtMethod* m : main_methods) {
- Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
- ASSERT_TRUE(h.IsHot());
- ASSERT_TRUE(h.IsPostStartup());
- }
- for (ArtMethod* m : second_methods) {
- Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
- ASSERT_TRUE(h.IsHot());
- ASSERT_TRUE(h.IsStartup());
- }
- }
-}
-
TEST_F(ProfileCompilationInfoTest, SaveFd) {
ScratchFile profile;
@@ -722,48 +533,6 @@
ASSERT_TRUE(*loaded_pmi1 == pmi_extra);
}
-TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
- ScratchFile profile;
-
- Thread* self = Thread::Current();
- jobject class_loader;
- {
- ScopedObjectAccess soa(self);
- class_loader = LoadDex("ProfileTestMultiDex");
- }
- ASSERT_NE(class_loader, nullptr);
-
- // Save virtual methods from Main.
- std::set<DexCacheResolvedClasses> resolved_classes;
- std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
-
- SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map;
- ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches(
- profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map));
-
- // Check that what we saved is in the profile.
- ProfileCompilationInfo info;
- ASSERT_TRUE(info.Load(GetFd(profile)));
- ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size());
- {
- ScopedObjectAccess soa(self);
- for (ArtMethod* m : main_methods) {
- Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
- ASSERT_TRUE(h.IsHot());
- ASSERT_TRUE(h.IsStartup());
- const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second;
- std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi =
- info.GetMethod(m->GetDexFile()->GetLocation(),
- m->GetDexFile()->GetLocationChecksum(),
- m->GetDexMethodIndex());
- ASSERT_TRUE(offline_pmi != nullptr);
- ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi =
- ConvertProfileMethodInfo(pmi);
- ASSERT_EQ(converted_pmi, *offline_pmi);
- }
- }
-}
-
TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) {
ScratchFile profile;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index b276c81..777a1fc 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -574,6 +574,7 @@
"interpreter/safe_math_test.cc",
"interpreter/unstarted_runtime_test.cc",
"jdwp/jdwp_options_test.cc",
+ "jit/profiling_info_test.cc",
"jni/java_vm_ext_test.cc",
"method_handles_test.cc",
"mirror/dex_cache_test.cc",
diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc
new file mode 100644
index 0000000..106a80a
--- /dev/null
+++ b/runtime/jit/profiling_info_test.cc
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include "art_method-inl.h"
+#include "base/unix_file/fd_file.h"
+#include "class_linker-inl.h"
+#include "common_runtime_test.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
+#include "dex/method_reference.h"
+#include "dex/type_reference.h"
+#include "handle_scope-inl.h"
+#include "linear_alloc.h"
+#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
+#include "profile/profile_compilation_info.h"
+#include "scoped_thread_state_change-inl.h"
+#include "ziparchive/zip_writer.h"
+
+namespace art {
+
+using Hotness = ProfileCompilationInfo::MethodHotness;
+
+static constexpr size_t kMaxMethodIds = 65535;
+
+class ProfileCompilationInfoTest : public CommonRuntimeTest {
+ public:
+ void PostRuntimeCreate() OVERRIDE {
+ allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
+ }
+
+ protected:
+ std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader,
+ const std::string& clazz) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> h_loader(
+ hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader()));
+ ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader);
+
+ const auto pointer_size = class_linker->GetImagePointerSize();
+ std::vector<ArtMethod*> methods;
+ for (auto& m : klass->GetVirtualMethods(pointer_size)) {
+ methods.push_back(&m);
+ }
+ return methods;
+ }
+
+ bool AddMethod(const std::string& dex_location,
+ uint32_t checksum,
+ uint16_t method_index,
+ ProfileCompilationInfo* info) {
+ return info->AddMethodIndex(Hotness::kFlagHot,
+ dex_location,
+ checksum,
+ method_index,
+ kMaxMethodIds);
+ }
+
+ bool AddMethod(const std::string& dex_location,
+ uint32_t checksum,
+ uint16_t method_index,
+ const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi,
+ ProfileCompilationInfo* info) {
+ return info->AddMethod(
+ dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup);
+ }
+
+ bool AddClass(const std::string& dex_location,
+ uint32_t checksum,
+ dex::TypeIndex type_index,
+ ProfileCompilationInfo* info) {
+ DexCacheResolvedClasses classes(dex_location, dex_location, checksum, kMaxMethodIds);
+ classes.AddClass(type_index);
+ return info->AddClasses({classes});
+ }
+
+ uint32_t GetFd(const ScratchFile& file) {
+ return static_cast<uint32_t>(file.GetFd());
+ }
+
+ bool SaveProfilingInfo(
+ const std::string& filename,
+ const std::vector<ArtMethod*>& methods,
+ const std::set<DexCacheResolvedClasses>& resolved_classes,
+ Hotness::Flag flags) {
+ ProfileCompilationInfo info;
+ std::vector<ProfileMethodInfo> profile_methods;
+ ScopedObjectAccess soa(Thread::Current());
+ for (ArtMethod* method : methods) {
+ profile_methods.emplace_back(
+ MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
+ }
+ if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) {
+ return false;
+ }
+ if (info.GetNumberOfMethods() != profile_methods.size()) {
+ return false;
+ }
+ ProfileCompilationInfo file_profile;
+ if (!file_profile.Load(filename, false)) {
+ return false;
+ }
+ if (!info.MergeWith(file_profile)) {
+ return false;
+ }
+
+ return info.Save(filename, nullptr);
+ }
+
+ // Saves the given art methods to a profile backed by 'filename' and adds
+ // some fake inline caches to it. The added inline caches are returned in
+ // the out map `profile_methods_map`.
+ bool SaveProfilingInfoWithFakeInlineCaches(
+ const std::string& filename,
+ const std::vector<ArtMethod*>& methods,
+ Hotness::Flag flags,
+ /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) {
+ ProfileCompilationInfo info;
+ std::vector<ProfileMethodInfo> profile_methods;
+ ScopedObjectAccess soa(Thread::Current());
+ for (ArtMethod* method : methods) {
+ std::vector<ProfileMethodInfo::ProfileInlineCache> caches;
+ // Monomorphic
+ for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
+ std::vector<TypeReference> classes;
+ classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0));
+ caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
+ }
+ // Polymorphic
+ for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
+ std::vector<TypeReference> classes;
+ for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) {
+ classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
+ }
+ caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
+ }
+ // Megamorphic
+ for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
+ std::vector<TypeReference> classes;
+ for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) {
+ classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
+ }
+ caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
+ }
+ // Missing types
+ for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
+ std::vector<TypeReference> classes;
+ caches.emplace_back(dex_pc, /*is_missing_types*/true, classes);
+ }
+ ProfileMethodInfo pmi(MethodReference(method->GetDexFile(),
+ method->GetDexMethodIndex()),
+ caches);
+ profile_methods.push_back(pmi);
+ profile_methods_map->Put(method, pmi);
+ }
+
+ if (!info.AddMethods(profile_methods, flags)
+ || info.GetNumberOfMethods() != profile_methods.size()) {
+ return false;
+ }
+ return info.Save(filename, nullptr);
+ }
+
+ // Creates an inline cache which will be destructed at the end of the test.
+ ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
+ used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
+ std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
+ return used_inline_caches.back().get();
+ }
+
+ ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo(
+ const ProfileMethodInfo& pmi) {
+ ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
+ ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map);
+ SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index
+ for (const auto& inline_cache : pmi.inline_caches) {
+ ProfileCompilationInfo::DexPcData& dex_pc_data =
+ ic_map->FindOrAdd(
+ inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second;
+ if (inline_cache.is_missing_types) {
+ dex_pc_data.SetIsMissingTypes();
+ }
+ for (const auto& class_ref : inline_cache.classes) {
+ uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file),
+ static_cast<uint8_t>(dex_map.size()))->second;
+ dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex());
+ if (dex_profile_index >= offline_pmi.dex_references.size()) {
+ // This is a new dex.
+ const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey(
+ class_ref.dex_file->GetLocation());
+ offline_pmi.dex_references.emplace_back(dex_key,
+ class_ref.dex_file->GetLocationChecksum(),
+ class_ref.dex_file->NumMethodIds());
+ }
+ }
+ }
+ return offline_pmi;
+ }
+
+ // Cannot sizeof the actual arrays so hard code the values here.
+ // They should not change anyway.
+ static constexpr int kProfileMagicSize = 4;
+ static constexpr int kProfileVersionSize = 4;
+
+ std::unique_ptr<ArenaAllocator> allocator_;
+
+ // 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;
+};
+
+TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
+ ScratchFile profile;
+
+ Thread* self = Thread::Current();
+ jobject class_loader;
+ {
+ ScopedObjectAccess soa(self);
+ class_loader = LoadDex("ProfileTestMultiDex");
+ }
+ ASSERT_NE(class_loader, nullptr);
+
+ // Save virtual methods from Main.
+ std::set<DexCacheResolvedClasses> resolved_classes;
+ std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
+ ASSERT_TRUE(SaveProfilingInfo(
+ profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup));
+
+ // Check that what we saved is in the profile.
+ ProfileCompilationInfo info1;
+ ASSERT_TRUE(info1.Load(GetFd(profile)));
+ ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size());
+ {
+ ScopedObjectAccess soa(self);
+ for (ArtMethod* m : main_methods) {
+ Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
+ ASSERT_TRUE(h.IsHot());
+ ASSERT_TRUE(h.IsPostStartup());
+ }
+ }
+
+ // Save virtual methods from Second.
+ std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;");
+ ASSERT_TRUE(SaveProfilingInfo(
+ profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup));
+
+ // Check that what we saved is in the profile (methods form Main and Second).
+ ProfileCompilationInfo info2;
+ ASSERT_TRUE(profile.GetFile()->ResetOffset());
+ ASSERT_TRUE(info2.Load(GetFd(profile)));
+ ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size());
+ {
+ ScopedObjectAccess soa(self);
+ for (ArtMethod* m : main_methods) {
+ Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
+ ASSERT_TRUE(h.IsHot());
+ ASSERT_TRUE(h.IsPostStartup());
+ }
+ for (ArtMethod* m : second_methods) {
+ Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
+ ASSERT_TRUE(h.IsHot());
+ ASSERT_TRUE(h.IsStartup());
+ }
+ }
+}
+
+TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
+ ScratchFile profile;
+
+ Thread* self = Thread::Current();
+ jobject class_loader;
+ {
+ ScopedObjectAccess soa(self);
+ class_loader = LoadDex("ProfileTestMultiDex");
+ }
+ ASSERT_NE(class_loader, nullptr);
+
+ // Save virtual methods from Main.
+ std::set<DexCacheResolvedClasses> resolved_classes;
+ std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
+
+ SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map;
+ ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches(
+ profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map));
+
+ // Check that what we saved is in the profile.
+ ProfileCompilationInfo info;
+ ASSERT_TRUE(info.Load(GetFd(profile)));
+ ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size());
+ {
+ ScopedObjectAccess soa(self);
+ for (ArtMethod* m : main_methods) {
+ Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
+ ASSERT_TRUE(h.IsHot());
+ ASSERT_TRUE(h.IsStartup());
+ const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second;
+ std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi =
+ info.GetMethod(m->GetDexFile()->GetLocation(),
+ m->GetDexFile()->GetLocationChecksum(),
+ m->GetDexMethodIndex());
+ ASSERT_TRUE(offline_pmi != nullptr);
+ ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi =
+ ConvertProfileMethodInfo(pmi);
+ ASSERT_EQ(converted_pmi, *offline_pmi);
+ }
+ }
+}
+
+} // namespace art