summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCalin Juravle <calin@google.com>2018-02-13 20:32:35 -0800
committerCalin Juravle <calin@google.com>2018-02-15 15:31:19 -0800
commitee9cb41260bc76cdb8572b10e99e6da866d9a8c8 (patch)
treec5192809ccfe6042800b5710fa22ec600060a81d
parentb40fa7c33075292beeb6840ac679ffd08fd1f719 (diff)
downloadandroid_art-ee9cb41260bc76cdb8572b10e99e6da866d9a8c8.tar.gz
android_art-ee9cb41260bc76cdb8572b10e99e6da866d9a8c8.tar.bz2
android_art-ee9cb41260bc76cdb8572b10e99e6da866d9a8c8.zip
Ensure that we always set the method hotness in the profile
The method hotness were not recorded for methods extracted from the JIT code cache. Test: gtest & run-test Bug: 71588770 Change-Id: Ifdf6340caa9faf5adb6f3b3b5b4046f31f34189c
-rw-r--r--profman/profile_assistant_test.cc22
-rw-r--r--profman/profman.cc27
-rw-r--r--runtime/jit/profile_compilation_info.cc55
-rw-r--r--runtime/jit/profile_compilation_info.h8
-rw-r--r--runtime/jit/profile_compilation_info_test.cc40
-rw-r--r--runtime/jit/profile_saver.cc2
6 files changed, 105 insertions, 49 deletions
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index 79310ac166..188d0b0a24 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -31,6 +31,8 @@
namespace art {
+using Hotness = ProfileCompilationInfo::MethodHotness;
+
static constexpr size_t kMaxMethodIds = 65535;
class ProfileAssistantTest : public CommonRuntimeTest {
@@ -80,12 +82,17 @@ class ProfileAssistantTest : public CommonRuntimeTest {
ProfileCompilationInfo::OfflineProfileMethodInfo pmi =
GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
dex_location2, dex_location_checksum2);
+ Hotness::Flag flags = Hotness::kFlagPostStartup;
if (reverse_dex_write_order) {
- ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
- ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
+ ASSERT_TRUE(info->AddMethod(
+ dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi, flags));
+ ASSERT_TRUE(info->AddMethod(
+ dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi, flags));
} else {
- ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
- ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
+ ASSERT_TRUE(info->AddMethod(
+ dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi, flags));
+ ASSERT_TRUE(info->AddMethod(
+ dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi, flags));
}
}
for (uint16_t i = 0; i < number_of_classes; i++) {
@@ -109,7 +116,6 @@ class ProfileAssistantTest : public CommonRuntimeTest {
const ScratchFile& profile,
ProfileCompilationInfo* info) {
std::string dex_location = "location1" + id;
- using Hotness = ProfileCompilationInfo::MethodHotness;
for (uint32_t idx : hot_methods) {
info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods);
}
@@ -1086,10 +1092,10 @@ TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
ASSERT_EQ(1u, classes.size());
ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
- // Verify that the invalid method is in the profile.
- ASSERT_EQ(2u, hot_methods.size());
+ // Verify that the invalid method did not get in the profile.
+ ASSERT_EQ(1u, hot_methods.size());
uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
- ASSERT_TRUE(hot_methods.find(invalid_method_index) != hot_methods.end());
+ ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end());
}
TEST_F(ProfileAssistantTest, DumpOnly) {
diff --git a/profman/profman.cc b/profman/profman.cc
index 387ce8dfae..efb7fcfec6 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -895,6 +895,17 @@ class ProfMan FINAL {
method_str = line.substr(method_sep_index + kMethodSep.size());
}
+ uint32_t flags = 0;
+ if (is_hot) {
+ flags |= ProfileCompilationInfo::MethodHotness::kFlagHot;
+ }
+ if (is_startup) {
+ flags |= ProfileCompilationInfo::MethodHotness::kFlagStartup;
+ }
+ if (is_post_startup) {
+ flags |= ProfileCompilationInfo::MethodHotness::kFlagPostStartup;
+ }
+
TypeReference class_ref(/* dex_file */ nullptr, dex::TypeIndex());
if (!FindClass(dex_files, klass, &class_ref)) {
LOG(WARNING) << "Could not find class: " << klass;
@@ -930,7 +941,7 @@ class ProfMan FINAL {
}
}
// TODO: Check return values?
- profile->AddMethods(methods);
+ profile->AddMethods(methods, static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags));
profile->AddClasses(resolved_class_set);
return true;
}
@@ -982,18 +993,12 @@ class ProfMan FINAL {
}
MethodReference ref(class_ref.dex_file, method_index);
if (is_hot) {
- profile->AddMethod(ProfileMethodInfo(ref, inline_caches));
- }
- uint32_t flags = 0;
- using Hotness = ProfileCompilationInfo::MethodHotness;
- if (is_startup) {
- flags |= Hotness::kFlagStartup;
- }
- if (is_post_startup) {
- flags |= Hotness::kFlagPostStartup;
+ profile->AddMethod(ProfileMethodInfo(ref, inline_caches),
+ static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags));
}
if (flags != 0) {
- if (!profile->AddMethodIndex(static_cast<Hotness::Flag>(flags), ref)) {
+ if (!profile->AddMethodIndex(
+ static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags), ref)) {
return false;
}
DCHECK(profile->GetMethodHotness(ref).IsInProfile());
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index de4d02edaf..dcb4a20b5f 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -168,9 +168,10 @@ bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags,
return data->AddMethod(flags, method_idx);
}
-bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods) {
+bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods,
+ MethodHotness::Flag flags) {
for (const ProfileMethodInfo& method : methods) {
- if (!AddMethod(method)) {
+ if (!AddMethod(method, flags)) {
return false;
}
}
@@ -644,15 +645,26 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
uint32_t dex_checksum,
uint16_t method_index,
uint32_t num_method_ids,
- const OfflineProfileMethodInfo& pmi) {
+ const OfflineProfileMethodInfo& pmi,
+ MethodHotness::Flag flags) {
DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
dex_checksum,
num_method_ids);
- if (data == nullptr) { // checksum mismatch
+ if (data == nullptr) {
+ // The data is null if there is a mismatch in the checksum or number of method ids.
return false;
}
+
// Add the method.
InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
+ if (inline_cache == nullptr) {
+ // Happens if the method index is outside the range (i.e. is greater then the number
+ // of methods in the dex file). This should not happen during normal execution,
+ // But tools (e.g. boot image aggregation tools) and tests stress this behaviour.
+ return false;
+ }
+
+ data->SetMethodHotness(method_index, flags);
if (pmi.inline_caches == nullptr) {
// If we don't have inline caches return success right away.
@@ -691,12 +703,16 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
return true;
}
-bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) {
+bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags) {
DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file);
if (data == nullptr) { // checksum mismatch
return false;
}
InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.ref.index);
+ if (inline_cache == nullptr) {
+ return false;
+ }
+ data->SetMethodHotness(pmi.ref.index, flags);
for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
if (cache.is_missing_types) {
@@ -811,6 +827,9 @@ bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer,
uint16_t method_index = last_method_index + diff_with_last_method_index;
last_method_index = method_index;
InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
+ if (inline_cache == nullptr) {
+ return false;
+ }
if (!ReadInlineCache(buffer,
number_of_dex_files,
dex_profile_index_remap,
@@ -1521,6 +1540,9 @@ bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
for (const auto& other_method_it : other_dex_data->method_map) {
uint16_t other_method_index = other_method_it.first;
InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index);
+ if (inline_cache == nullptr) {
+ return false;
+ }
const auto& other_inline_cache = other_method_it.second;
for (const auto& other_ic_it : other_inline_cache) {
uint16_t other_dex_pc = other_ic_it.first;
@@ -1955,6 +1977,10 @@ bool ProfileCompilationInfo::IsEmpty() const {
ProfileCompilationInfo::InlineCacheMap*
ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) {
+ if (method_index >= num_method_ids) {
+ LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids;
+ return nullptr;
+ }
return &(method_map.FindOrAdd(
method_index,
InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
@@ -1967,12 +1993,8 @@ bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, s
return false;
}
- if ((flags & MethodHotness::kFlagStartup) != 0) {
- method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true);
- }
- if ((flags & MethodHotness::kFlagPostStartup) != 0) {
- method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true);
- }
+ SetMethodHotness(index, flags);
+
if ((flags & MethodHotness::kFlagHot) != 0) {
method_map.FindOrAdd(
index,
@@ -1981,6 +2003,17 @@ bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, s
return true;
}
+void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index,
+ MethodHotness::Flag flags) {
+ DCHECK_LT(index, num_method_ids);
+ if ((flags & MethodHotness::kFlagStartup) != 0) {
+ method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true);
+ }
+ if ((flags & MethodHotness::kFlagPostStartup) != 0) {
+ method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true);
+ }
+}
+
ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
uint32_t dex_method_index) const {
MethodHotness ret;
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index 1973f3f09e..5488a9e81e 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -241,7 +241,7 @@ class ProfileCompilationInfo {
~ProfileCompilationInfo();
// Add the given methods to the current profile object.
- bool AddMethods(const std::vector<ProfileMethodInfo>& methods);
+ bool AddMethods(const std::vector<ProfileMethodInfo>& methods, MethodHotness::Flag flags);
// Add the given classes to the current profile object.
bool AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes);
@@ -278,7 +278,7 @@ class ProfileCompilationInfo {
bool AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref);
// Add a method to the profile using its online representation (containing runtime structures).
- bool AddMethod(const ProfileMethodInfo& pmi);
+ bool AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags);
// Bulk add sampled methods and/or hot methods for a single dex, fast since it only has one
// GetOrAddDexFileData call.
@@ -500,6 +500,7 @@ class ProfileCompilationInfo {
}
}
+ void SetMethodHotness(size_t index, MethodHotness::Flag flags);
MethodHotness GetHotnessInfo(uint32_t dex_method_index) const;
// The allocator used to allocate new inline cache maps.
@@ -559,7 +560,8 @@ class ProfileCompilationInfo {
uint32_t dex_checksum,
uint16_t method_index,
uint32_t num_method_ids,
- const OfflineProfileMethodInfo& pmi);
+ const OfflineProfileMethodInfo& pmi,
+ MethodHotness::Flag flags);
// Add a class index to the profile.
bool AddClassIndex(const std::string& dex_location,
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index 4ac11ee422..e6917956ae 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -80,7 +80,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
uint16_t method_index,
const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi,
ProfileCompilationInfo* info) {
- return info->AddMethod(dex_location, checksum, method_index, kMaxMethodIds, pmi);
+ return info->AddMethod(
+ dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup);
}
bool AddClass(const std::string& dex_location,
@@ -99,7 +100,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
bool SaveProfilingInfo(
const std::string& filename,
const std::vector<ArtMethod*>& methods,
- const std::set<DexCacheResolvedClasses>& resolved_classes) {
+ const std::set<DexCacheResolvedClasses>& resolved_classes,
+ Hotness::Flag flags) {
ProfileCompilationInfo info;
std::vector<ProfileMethodInfo> profile_methods;
ScopedObjectAccess soa(Thread::Current());
@@ -107,7 +109,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
profile_methods.emplace_back(
MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
}
- if (!info.AddMethods(profile_methods) || !info.AddClasses(resolved_classes)) {
+ if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) {
return false;
}
if (info.GetNumberOfMethods() != profile_methods.size()) {
@@ -130,6 +132,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
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;
@@ -170,7 +173,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
profile_methods_map->Put(method, pmi);
}
- if (!info.AddMethods(profile_methods) || info.GetNumberOfMethods() != profile_methods.size()) {
+ if (!info.AddMethods(profile_methods, flags)
+ || info.GetNumberOfMethods() != profile_methods.size()) {
return false;
}
return info.Save(filename, nullptr);
@@ -345,7 +349,8 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
// 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));
+ ASSERT_TRUE(SaveProfilingInfo(
+ profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup));
// Check that what we saved is in the profile.
ProfileCompilationInfo info1;
@@ -354,14 +359,16 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
{
ScopedObjectAccess soa(self);
for (ArtMethod* m : main_methods) {
- ASSERT_TRUE(info1.GetMethodHotness(
- MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot());
+ 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));
+ 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;
@@ -371,12 +378,14 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
{
ScopedObjectAccess soa(self);
for (ArtMethod* m : main_methods) {
- ASSERT_TRUE(
- info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot());
+ Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
+ ASSERT_TRUE(h.IsHot());
+ ASSERT_TRUE(h.IsPostStartup());
}
for (ArtMethod* m : second_methods) {
- ASSERT_TRUE(
- info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot());
+ Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
+ ASSERT_TRUE(h.IsHot());
+ ASSERT_TRUE(h.IsStartup());
}
}
}
@@ -730,7 +739,7 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map;
ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches(
- profile.GetFilename(), main_methods, &profile_methods_map));
+ profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map));
// Check that what we saved is in the profile.
ProfileCompilationInfo info;
@@ -739,8 +748,9 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
{
ScopedObjectAccess soa(self);
for (ArtMethod* m : main_methods) {
- ASSERT_TRUE(
- info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot());
+ 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(),
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 8f0ac33594..53f48644f2 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -511,7 +511,7 @@ bool ProfileSaver::ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number
uint64_t last_save_number_of_methods = info.GetNumberOfMethods();
uint64_t last_save_number_of_classes = info.GetNumberOfResolvedClasses();
- info.AddMethods(profile_methods);
+ info.AddMethods(profile_methods, ProfileCompilationInfo::MethodHotness::kFlagPostStartup);
auto profile_cache_it = profile_cache_.find(filename);
if (profile_cache_it != profile_cache_.end()) {
info.MergeWith(*(profile_cache_it->second));