summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Islam Elbanna <islamelbanna@google.com> 2024-08-09 15:47:02 +0000
committer Islam Elbanna <islamelbanna@google.com> 2024-08-10 03:17:31 +0000
commit2e2c1ac96d9ea3fc04a4758912774180ee6bfac7 (patch)
treef319f6dbd5a4647d02a35cc59546dc39a58a0723
parenta77898ceddae1a61f169c11747eda08bfeb5d6e3 (diff)
Support inline cache for boot image profile HRF in Profman.
Refactor `GetInlineCacheLine` at `profman.cc` to be used for normal profiles as well as boot image profiles (using `--generate-boot-image-profile` flag). With this change, the dumped boot-image profile HRF will contain inline cache for hot methods in the profile. Bug: 348109271 Change-Id: Ie3645b2f3004c01f15298a524f74f14576b5a255 Test: Locally run `./art/tools/boot-image-profile-generate.sh /usr/local/google/home/islamelbanna/Documents /usr/local/google/home/islamelbanna/Downloads/boot.zip frameworks/base/config/preloaded-classes-denylist /usr/local/google/home/islamelbanna/Downloads/android.prof --profman-arg --upgrade-startup-to-hot=false --profman-arg --generate-boot-image-profile` Partial result(since file is too big): gpaste/4527986827329536
-rw-r--r--libprofile/profile/profile_compilation_info.cc70
-rw-r--r--libprofile/profile/profile_compilation_info.h25
-rw-r--r--profman/Android.bp1
-rw-r--r--profman/boot_image_profile.cc5
-rw-r--r--profman/inline_cache_format_util.cc53
-rw-r--r--profman/inline_cache_format_util.h40
-rw-r--r--profman/profman.cc91
7 files changed, 192 insertions, 93 deletions
diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc
index 631bf1148b..9bc43f69b7 100644
--- a/libprofile/profile/profile_compilation_info.cc
+++ b/libprofile/profile/profile_compilation_info.cc
@@ -60,6 +60,7 @@
#include "dex/code_item_accessors-inl.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file_loader.h"
+#include "dex/dex_instruction-inl.h"
#ifdef ART_TARGET_ANDROID
#include "android-modules-utils/sdk_level.h"
@@ -3030,9 +3031,49 @@ FlattenProfileData::ItemMetadata::ItemMetadata() :
flags_(0) {
}
-FlattenProfileData::ItemMetadata::ItemMetadata(const ItemMetadata& other) :
- flags_(other.flags_),
- annotations_(other.annotations_) {
+void FlattenProfileData::ItemMetadata::ExtractInlineCacheInfo(
+ const ProfileCompilationInfo& profile_info,
+ const DexFile* dex_file,
+ uint16_t dex_method_idx) {
+ ProfileCompilationInfo::MethodHotness hotness =
+ profile_info.GetMethodHotness(MethodReference(dex_file, dex_method_idx));
+ DCHECK(!hotness.IsHot() || hotness.GetInlineCacheMap() != nullptr);
+ if (!hotness.IsHot() || hotness.GetInlineCacheMap()->empty()) {
+ return;
+ }
+ const dex::MethodId& id = dex_file->GetMethodId(dex_method_idx);
+ const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
+ const dex::ClassDef* class_def = dex_file->FindClassDef(id.class_idx_);
+ if (class_def == nullptr) {
+ // No class def found.
+ return;
+ }
+
+ CodeItemInstructionAccessor accessor(
+ *dex_file, dex_file->GetCodeItem(dex_file->FindCodeItemOffset(*class_def, dex_method_idx)));
+ for (const auto& [pc, ic_data] : *inline_caches) {
+ if (pc >= accessor.InsnsSizeInCodeUnits()) {
+ // Inlined inline caches are not supported in AOT, so discard any pc beyond the
+ // code item size. See also `HInliner::GetInlineCacheAOT`.
+ continue;
+ }
+ const Instruction& inst = accessor.InstructionAt(pc);
+ const dex::MethodId& target = dex_file->GetMethodId(inst.VRegB());
+ if (ic_data.classes.empty() && !ic_data.is_megamorphic && !ic_data.is_missing_types) {
+ continue;
+ }
+ InlineCacheInfo& val =
+ inline_cache_.FindOrAdd(TypeReference(dex_file, target.class_idx_))->second;
+ if (ic_data.is_megamorphic) {
+ val.is_megamorphic_ = true;
+ }
+ if (ic_data.is_missing_types) {
+ val.is_missing_types_ = true;
+ }
+ for (dex::TypeIndex type_index : ic_data.classes) {
+ val.classes_.insert(profile_info.GetTypeDescriptor(dex_file, type_index));
+ }
+ }
}
std::unique_ptr<FlattenProfileData> ProfileCompilationInfo::ExtractProfileData(
@@ -3067,6 +3108,8 @@ std::unique_ptr<FlattenProfileData> ProfileCompilationInfo::ExtractProfileData(
result->method_metadata_.GetOrCreate(ref, create_metadata_fn);
metadata.flags_ |= hotness.flags_;
metadata.annotations_.push_back(annotation);
+ metadata.ExtractInlineCacheInfo(*this, dex_file.get(), method_idx);
+
// Update the max aggregation counter for methods.
// This is essentially a cache, to avoid traversing all the methods just to find out
// this value.
@@ -3098,6 +3141,26 @@ std::unique_ptr<FlattenProfileData> ProfileCompilationInfo::ExtractProfileData(
return result;
}
+void FlattenProfileData::ItemMetadata::MergeInlineCacheInfo(
+ const SafeMap<TypeReference, InlineCacheInfo, TypeReferenceValueComparator>& other) {
+ for (const auto& [target, inline_cache_data] : other) {
+ if (!inline_cache_data.is_megamorphic_ && !inline_cache_data.is_missing_types_ &&
+ inline_cache_data.classes_.empty()) {
+ continue;
+ }
+ InlineCacheInfo& val = inline_cache_.FindOrAdd(target)->second;
+ if (inline_cache_data.is_megamorphic_) {
+ val.is_megamorphic_ = true;
+ }
+ if (inline_cache_data.is_missing_types_) {
+ val.is_missing_types_ = true;
+ }
+ for (const std::string& cls : inline_cache_data.classes_) {
+ val.classes_.insert(cls);
+ }
+ }
+}
+
void FlattenProfileData::MergeData(const FlattenProfileData& other) {
auto create_metadata_fn = []() { return FlattenProfileData::ItemMetadata(); };
for (const auto& it : other.method_metadata_) {
@@ -3111,6 +3174,7 @@ void FlattenProfileData::MergeData(const FlattenProfileData& other) {
metadata.flags_ |= otherData.GetFlags();
metadata.annotations_.insert(
metadata.annotations_.end(), other_annotations.begin(), other_annotations.end());
+ metadata.MergeInlineCacheInfo(otherData.GetInlineCache());
max_aggregation_for_methods_ = std::max(
max_aggregation_for_methods_,
diff --git a/libprofile/profile/profile_compilation_info.h b/libprofile/profile/profile_compilation_info.h
index 104198f1fa..f6b0105ff6 100644
--- a/libprofile/profile/profile_compilation_info.h
+++ b/libprofile/profile/profile_compilation_info.h
@@ -1092,8 +1092,14 @@ class FlattenProfileData {
public:
class ItemMetadata {
public:
+ struct InlineCacheInfo {
+ bool is_megamorphic_ = false;
+ bool is_missing_types_ = false;
+ std::set<std::string> classes_;
+ };
+
ItemMetadata();
- ItemMetadata(const ItemMetadata& other);
+ ItemMetadata(const ItemMetadata& other) = default;
uint16_t GetFlags() const {
return flags_;
@@ -1111,12 +1117,29 @@ class FlattenProfileData {
return (flags_ & flag) != 0;
}
+ // Extracts inline cache info for the given method into this instance.
+ // Note that this will collapse all ICs with the same receiver type.
+ void ExtractInlineCacheInfo(const ProfileCompilationInfo& profile_info,
+ const DexFile* dex_file,
+ uint16_t dex_method_idx);
+
+ // Merges the inline cache info from the other metadata into this instance.
+ void MergeInlineCacheInfo(
+ const SafeMap<TypeReference, InlineCacheInfo, TypeReferenceValueComparator>& other);
+
+ const SafeMap<TypeReference, InlineCacheInfo, TypeReferenceValueComparator>& GetInlineCache()
+ const {
+ return inline_cache_;
+ }
+
private:
// will be 0 for classes and MethodHotness::Flags for methods.
uint16_t flags_;
// This is a list that may contain duplicates after a merge operation.
// It represents that a method was used multiple times across different devices.
std::list<ProfileCompilationInfo::ProfileSampleAnnotation> annotations_;
+ // Inline cache map for methods.
+ SafeMap<TypeReference, InlineCacheInfo, TypeReferenceValueComparator> inline_cache_;
friend class ProfileCompilationInfo;
friend class FlattenProfileData;
diff --git a/profman/Android.bp b/profman/Android.bp
index df8c55fd18..948b6fd23d 100644
--- a/profman/Android.bp
+++ b/profman/Android.bp
@@ -32,6 +32,7 @@ cc_defaults {
"boot_image_profile.cc",
"profman.cc",
"profile_assistant.cc",
+ "inline_cache_format_util.cc",
],
header_libs: ["profman_headers"],
diff --git a/profman/boot_image_profile.cc b/profman/boot_image_profile.cc
index fc20f20a65..9c46786df2 100644
--- a/profman/boot_image_profile.cc
+++ b/profman/boot_image_profile.cc
@@ -20,13 +20,13 @@
#include <set>
#include "android-base/file.h"
-#include "base/unix_file/fd_file.h"
#include "dex/class_accessor-inl.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
#include "dex/method_reference.h"
#include "dex/type_reference.h"
#include "profile/profile_compilation_info.h"
+#include "inline_cache_format_util.h"
namespace art {
@@ -100,7 +100,8 @@ static std::string MethodToProfileFormat(
extra = kPackageUseDelim + GetPackageUseString(metadata);
}
- return flags_string + method + extra;
+ std::string inline_cache_string = GetInlineCacheLine(metadata.GetInlineCache());
+ return flags_string + method + extra + inline_cache_string;
}
// Converts a class representation to its final profile or preloaded classes format.
diff --git a/profman/inline_cache_format_util.cc b/profman/inline_cache_format_util.cc
new file mode 100644
index 0000000000..24ed8a09cd
--- /dev/null
+++ b/profman/inline_cache_format_util.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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 "inline_cache_format_util.h"
+
+#include "profile/profile_compilation_info.h"
+
+namespace art {
+
+std::string GetInlineCacheLine(const SafeMap<TypeReference,
+ FlattenProfileData::ItemMetadata::InlineCacheInfo,
+ TypeReferenceValueComparator>& inline_cache) {
+ if (inline_cache.empty()) {
+ return "";
+ }
+ std::ostringstream dump_ic;
+ dump_ic << kProfileParsingInlineChacheSep;
+ for (const auto& [target_ref, inline_cache_data] : inline_cache) {
+ dump_ic << kProfileParsingInlineChacheTargetSep;
+ dump_ic << target_ref.dex_file->GetTypeDescriptor(
+ target_ref.dex_file->GetTypeId(target_ref.TypeIndex()));
+ if (inline_cache_data.is_missing_types_) {
+ dump_ic << kMissingTypesMarker;
+ } else if (inline_cache_data.is_megamorphic_) {
+ dump_ic << kMegamorphicTypesMarker;
+ } else {
+ bool first = true;
+ for (const std::string& cls : inline_cache_data.classes_) {
+ if (!first) {
+ dump_ic << kProfileParsingTypeSep;
+ }
+ first = false;
+ dump_ic << cls;
+ }
+ }
+ }
+ return dump_ic.str();
+}
+
+} // namespace art
diff --git a/profman/inline_cache_format_util.h b/profman/inline_cache_format_util.h
new file mode 100644
index 0000000000..ef3d4742f6
--- /dev/null
+++ b/profman/inline_cache_format_util.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 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_PROFMAN_INLINE_CACHE_FORMAT_UTIL_H_
+#define ART_PROFMAN_INLINE_CACHE_FORMAT_UTIL_H_
+
+#include "profile/profile_compilation_info.h"
+
+namespace art {
+
+constexpr char kProfileParsingInlineChacheSep = '+';
+constexpr char kProfileParsingInlineChacheTargetSep = ']';
+constexpr char kMissingTypesMarker[] = "missing_types";
+constexpr char kMegamorphicTypesMarker[] = "megamorphic_types";
+constexpr char kProfileParsingTypeSep = ',';
+
+// Creates the inline-cache portion of a text-profile line. If there is no
+// inline-caches this will be an empty string. Otherwise it will be '@'
+// followed by an IC description matching the format described by
+// Profman::ProcessLine.
+std::string GetInlineCacheLine(const SafeMap<TypeReference,
+ FlattenProfileData::ItemMetadata::InlineCacheInfo,
+ TypeReferenceValueComparator>& inline_cache);
+
+} // namespace art
+
+#endif // ART_PROFMAN_INLINE_CACHE_FORMAT_UTIL_H_
diff --git a/profman/profman.cc b/profman/profman.cc
index 1525b476cd..2fcb2ef72b 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -63,6 +63,7 @@
#include "profile/profile_compilation_info.h"
#include "profile_assistant.h"
#include "profman/profman_result.h"
+#include "inline_cache_format_util.h"
namespace art {
@@ -209,14 +210,9 @@ static constexpr uint16_t kDefaultTestProfileClassPercentage = 5;
// Separators used when parsing human friendly representation of profiles.
static const std::string kMethodSep = "->"; // NOLINT [runtime/string] [4]
-static const std::string kMissingTypesMarker = "missing_types"; // NOLINT [runtime/string] [4]
-static const std::string kMegamorphicTypesMarker = "megamorphic_types"; // NOLINT [runtime/string] [4]
static const std::string kClassAllMethods = "*"; // NOLINT [runtime/string] [4]
static constexpr char kAnnotationStart = '{';
static constexpr char kAnnotationEnd = '}';
-static constexpr char kProfileParsingInlineChacheSep = '+';
-static constexpr char kProfileParsingInlineChacheTargetSep = ']';
-static constexpr char kProfileParsingTypeSep = ',';
static constexpr char kProfileParsingFirstCharInSignature = '(';
static constexpr char kMethodFlagStringHot = 'H';
static constexpr char kMethodFlagStringStartup = 'S';
@@ -801,86 +797,6 @@ class ProfMan final {
return dump_only_;
}
- // Creates the inline-cache portion of a text-profile line. If the class def can't be found, or if
- // there is no inline-caches this will be and empty string. Otherwise it will be '@' followed by
- // an IC description matching the format described by ProcessLine below. Note that this will
- // collapse all ICs with the same receiver type.
- std::string GetInlineCacheLine(const ProfileCompilationInfo& profile_info,
- const dex::MethodId& id,
- const DexFile* dex_file,
- uint16_t dex_method_idx) {
- ProfileCompilationInfo::MethodHotness hotness =
- profile_info.GetMethodHotness(MethodReference(dex_file, dex_method_idx));
- DCHECK(!hotness.IsHot() || hotness.GetInlineCacheMap() != nullptr);
- if (!hotness.IsHot() || hotness.GetInlineCacheMap()->empty()) {
- return "";
- }
- const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
- struct IcLineInfo {
- bool is_megamorphic_ = false;
- bool is_missing_types_ = false;
- std::set<dex::TypeIndex> classes_;
- };
- std::unordered_map<dex::TypeIndex, IcLineInfo> ics;
- const dex::ClassDef* class_def = dex_file->FindClassDef(id.class_idx_);
- if (class_def == nullptr) {
- // No class def found.
- return "";
- }
-
- CodeItemInstructionAccessor accessor(
- *dex_file, dex_file->GetCodeItem(dex_file->FindCodeItemOffset(*class_def, dex_method_idx)));
- for (const auto& [pc, ic_data] : *inline_caches) {
- if (pc >= accessor.InsnsSizeInCodeUnits()) {
- // Inlined inline caches are not supported in AOT, so discard any pc beyond the
- // code item size. See also `HInliner::GetInlineCacheAOT`.
- continue;
- }
- const Instruction& inst = accessor.InstructionAt(pc);
- const dex::MethodId& target = dex_file->GetMethodId(inst.VRegB());
- if (ic_data.classes.empty() && !ic_data.is_megamorphic && !ic_data.is_missing_types) {
- continue;
- }
- auto val = ics.find(target.class_idx_);
- if (val == ics.end()) {
- val = ics.insert({ target.class_idx_, {} }).first;
- }
- if (ic_data.is_megamorphic) {
- val->second.is_megamorphic_ = true;
- }
- if (ic_data.is_missing_types) {
- val->second.is_missing_types_ = true;
- }
- for (dex::TypeIndex type_index : ic_data.classes) {
- val->second.classes_.insert(type_index);
- }
- }
- if (ics.empty()) {
- return "";
- }
- std::ostringstream dump_ic;
- dump_ic << kProfileParsingInlineChacheSep;
- for (const auto& [target, dex_data] : ics) {
- dump_ic << kProfileParsingInlineChacheTargetSep;
- dump_ic << dex_file->GetTypeDescriptor(dex_file->GetTypeId(target));
- if (dex_data.is_missing_types_) {
- dump_ic << kMissingTypesMarker;
- } else if (dex_data.is_megamorphic_) {
- dump_ic << kMegamorphicTypesMarker;
- } else {
- bool first = true;
- for (dex::TypeIndex type_index : dex_data.classes_) {
- if (!first) {
- dump_ic << kProfileParsingTypeSep;
- }
- first = false;
- dump_ic << profile_info.GetTypeDescriptor(dex_file, type_index);
- }
- }
- }
- return dump_ic.str();
- }
-
bool GetClassNamesAndMethods(const ProfileCompilationInfo& profile_info,
std::vector<std::unique_ptr<const DexFile>>* dex_files,
std::set<std::string>* out_lines) {
@@ -916,8 +832,9 @@ class ProfMan final {
if (post_startup_methods.find(dex_method_idx) != post_startup_methods.end()) {
flags_string += kMethodFlagStringPostStartup;
}
- std::string inline_cache_string =
- GetInlineCacheLine(profile_info, id, dex_file.get(), dex_method_idx);
+ FlattenProfileData::ItemMetadata metadata;
+ metadata.ExtractInlineCacheInfo(profile_info, dex_file.get(), dex_method_idx);
+ std::string inline_cache_string = GetInlineCacheLine(metadata.GetInlineCache());
out_lines->insert(ART_FORMAT("{}{}{}{}{}{}",
flags_string,
type_string,