Add and use loaded class profiling
Class profiling is a way to keep track of which classes are resolved.
From here the compiler can use this information to generate a smaller
app image.
TODO: Add tests for profile stuff.
Bug: 22858531
(cherry picked from commit 8913fc1a27df8cf3b37fd99e94d87f290591328e)
Change-Id: Ifcd09230cbdc266305bc1247e0d31e7920eb353e
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index 747b112..67c9b5f 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -48,9 +48,11 @@
}
}
-bool ProfileCompilationInfo::SaveProfilingInfo(const std::string& filename,
- const std::vector<ArtMethod*>& methods) {
- if (methods.empty()) {
+bool ProfileCompilationInfo::SaveProfilingInfo(
+ const std::string& filename,
+ const std::vector<ArtMethod*>& methods,
+ const std::set<DexCacheResolvedClasses>& resolved_classes) {
+ if (methods.empty() && resolved_classes.empty()) {
VLOG(profiler) << "No info to save to " << filename;
return true;
}
@@ -71,14 +73,17 @@
}
{
ScopedObjectAccess soa(Thread::Current());
- for (auto it = methods.begin(); it != methods.end(); it++) {
- const DexFile* dex_file = (*it)->GetDexFile();
- if (!info.AddData(GetProfileDexFileKey(dex_file->GetLocation()),
- dex_file->GetLocationChecksum(),
- (*it)->GetDexMethodIndex())) {
+ for (ArtMethod* method : methods) {
+ const DexFile* dex_file = method->GetDexFile();
+ if (!info.AddMethodIndex(GetProfileDexFileKey(dex_file->GetLocation()),
+ dex_file->GetLocationChecksum(),
+ method->GetDexMethodIndex())) {
return false;
}
}
+ for (const DexCacheResolvedClasses& dex_cache : resolved_classes) {
+ info.AddResolvedClasses(dex_cache);
+ }
}
if (!flock.GetFile()->ClearContent()) {
@@ -116,13 +121,14 @@
static constexpr const char kFieldSeparator = ',';
static constexpr const char kLineSeparator = '\n';
+static constexpr const char* kClassesMarker = "classes";
/**
* Serialization format:
- * dex_location1,dex_location_checksum1,method_id11,method_id12...
- * dex_location2,dex_location_checksum2,method_id21,method_id22...
+ * dex_location1,dex_location_checksum1,method_id11,method_id12...,classes,class_id1,class_id2...
+ * dex_location2,dex_location_checksum2,method_id21,method_id22...,classes,class_id1,class_id2...
* e.g.
- * app.apk,131232145,11,23,454,54
+ * app.apk,131232145,11,23,454,54,classes,1,2,4,1234
* app.apk:classes5.dex,218490184,39,13,49,1
**/
bool ProfileCompilationInfo::Save(int fd) {
@@ -133,11 +139,20 @@
for (const auto& it : info_) {
const std::string& dex_location = it.first;
const DexFileData& dex_data = it.second;
+ if (dex_data.method_set.empty() && dex_data.class_set.empty()) {
+ continue;
+ }
os << dex_location << kFieldSeparator << dex_data.checksum;
for (auto method_it : dex_data.method_set) {
os << kFieldSeparator << method_it;
}
+ if (!dex_data.class_set.empty()) {
+ os << kFieldSeparator << kClassesMarker;
+ for (auto class_id : dex_data.class_set) {
+ os << kFieldSeparator << class_id;
+ }
+ }
os << kLineSeparator;
}
@@ -168,18 +183,50 @@
}
}
-bool ProfileCompilationInfo::AddData(const std::string& dex_location,
- uint32_t checksum,
- uint16_t method_idx) {
+ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
+ const std::string& dex_location,
+ uint32_t checksum) {
auto info_it = info_.find(dex_location);
if (info_it == info_.end()) {
info_it = info_.Put(dex_location, DexFileData(checksum));
}
if (info_it->second.checksum != checksum) {
LOG(WARNING) << "Checksum mismatch for dex " << dex_location;
+ return nullptr;
+ }
+ return &info_it->second;
+}
+
+bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
+ const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
+ const uint32_t checksum = classes.GetLocationChecksum();
+ DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
+ if (data == nullptr) {
return false;
}
- info_it->second.method_set.insert(method_idx);
+ data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end());
+ return true;
+}
+
+bool ProfileCompilationInfo::AddMethodIndex(const std::string& dex_location,
+ uint32_t checksum,
+ uint16_t method_idx) {
+ DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
+ if (data == nullptr) {
+ return false;
+ }
+ data->method_set.insert(method_idx);
+ return true;
+}
+
+bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
+ uint32_t checksum,
+ uint16_t class_idx) {
+ DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
+ if (data == nullptr) {
+ return false;
+ }
+ data->class_set.insert(class_idx);
return true;
}
@@ -198,12 +245,30 @@
}
for (size_t i = 2; i < parts.size(); i++) {
+ if (parts[i] == kClassesMarker) {
+ ++i;
+ // All of the remaining idx are class def indexes.
+ for (++i; i < parts.size(); ++i) {
+ uint32_t class_def_idx;
+ if (!ParseInt(parts[i].c_str(), &class_def_idx)) {
+ LOG(WARNING) << "Cannot parse class_def_idx " << parts[i];
+ return false;
+ } else if (class_def_idx >= std::numeric_limits<uint16_t>::max()) {
+ LOG(WARNING) << "Class def idx " << class_def_idx << " is larger than uint16_t max";
+ return false;
+ }
+ if (!AddClassIndex(dex_location, checksum, class_def_idx)) {
+ return false;
+ }
+ }
+ break;
+ }
uint32_t method_idx;
if (!ParseInt(parts[i].c_str(), &method_idx)) {
LOG(WARNING) << "Cannot parse method_idx " << parts[i];
return false;
}
- if (!AddData(dex_location, checksum, method_idx)) {
+ if (!AddMethodIndex(dex_location, checksum, method_idx)) {
return false;
}
}
@@ -280,6 +345,8 @@
}
info_it->second.method_set.insert(other_dex_data.method_set.begin(),
other_dex_data.method_set.end());
+ info_it->second.class_set.insert(other_dex_data.class_set.begin(),
+ other_dex_data.class_set.end());
}
return true;
}
@@ -347,4 +414,16 @@
return info_.Equals(other.info_);
}
+std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses() const {
+ std::set<DexCacheResolvedClasses> ret;
+ for (auto&& pair : info_) {
+ const std::string& profile_key = pair.first;
+ const DexFileData& data = pair.second;
+ DexCacheResolvedClasses classes(profile_key, data.checksum);
+ classes.AddClasses(data.class_set.begin(), data.class_set.end());
+ ret.insert(classes);
+ }
+ return ret;
+}
+
} // namespace art