summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dex2oat/dex2oat.cc16
-rw-r--r--dex2oat/dex2oat_test.cc97
-rw-r--r--runtime/class_linker.cc11
-rw-r--r--runtime/class_linker.h3
-rw-r--r--runtime/jit/profile_compilation_info.cc19
-rw-r--r--runtime/jit/profile_compilation_info.h5
6 files changed, 113 insertions, 38 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index dbae70ec14..f535557e8c 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1426,25 +1426,15 @@ class Dex2Oat FINAL {
if (profile_compilation_info_ != nullptr && IsAppImage()) {
Runtime* runtime = Runtime::Current();
CHECK(runtime != nullptr);
- std::set<DexCacheResolvedClasses> resolved_classes(
- profile_compilation_info_->GetResolvedClasses());
-
// Filter out class path classes since we don't want to include these in the image.
std::unordered_set<std::string> dex_files_locations;
for (const DexFile* dex_file : dex_files_) {
dex_files_locations.insert(dex_file->GetLocation());
}
- for (auto it = resolved_classes.begin(); it != resolved_classes.end(); ) {
- if (dex_files_locations.find(it->GetDexLocation()) == dex_files_locations.end()) {
- VLOG(compiler) << "Removed profile samples for non-app dex file " << it->GetDexLocation();
- it = resolved_classes.erase(it);
- } else {
- ++it;
- }
- }
-
+ std::set<DexCacheResolvedClasses> resolved_classes(
+ profile_compilation_info_->GetResolvedClasses(dex_files_locations));
image_classes_.reset(new std::unordered_set<std::string>(
- runtime->GetClassLinker()->GetClassDescriptorsForProfileKeys(resolved_classes)));
+ runtime->GetClassLinker()->GetClassDescriptorsForResolvedClasses(resolved_classes)));
VLOG(compiler) << "Loaded " << image_classes_->size()
<< " image class descriptors from profile";
if (VLOG_IS_ON(compiler)) {
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index b79050e9d0..e7277bceae 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -63,6 +63,7 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
CHECK(oat_file != nullptr) << odex_location;
args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
+ args.push_back("--oat-location=" + odex_location);
} else {
args.push_back("--oat-file=" + odex_location);
}
@@ -583,13 +584,16 @@ class Dex2oatLayoutTest : public Dex2oatTest {
// Emits a profile with a single dex file with the given location and a single class index of 1.
void GenerateProfile(const std::string& test_profile,
const std::string& dex_location,
+ size_t num_classes,
uint32_t checksum) {
int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
CHECK_GE(profile_test_fd, 0);
ProfileCompilationInfo info;
std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location);
- info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1));
+ for (size_t i = 0; i < num_classes; ++i) {
+ info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i));
+ }
bool result = info.Save(profile_test_fd);
close(profile_test_fd);
ASSERT_TRUE(result);
@@ -597,7 +601,9 @@ class Dex2oatLayoutTest : public Dex2oatTest {
void CompileProfileOdex(const std::string& dex_location,
const std::string& odex_location,
+ const std::string& app_image_file_name,
bool use_fd,
+ size_t num_profile_classes,
const std::vector<std::string>& extra_args = {}) {
const std::string profile_location = GetScratchDir() + "/primary.prof";
const char* location = dex_location.c_str();
@@ -606,33 +612,86 @@ class Dex2oatLayoutTest : public Dex2oatTest {
ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
EXPECT_EQ(dex_files.size(), 1U);
std::unique_ptr<const DexFile>& dex_file = dex_files[0];
- GenerateProfile(profile_location, dex_location, dex_file->GetLocationChecksum());
+ GenerateProfile(profile_location,
+ dex_location,
+ num_profile_classes,
+ dex_file->GetLocationChecksum());
std::vector<std::string> copy(extra_args);
copy.push_back("--profile-file=" + profile_location);
+ std::unique_ptr<File> app_image_file;
+ if (!app_image_file_name.empty()) {
+ if (use_fd) {
+ app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str()));
+ copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd()));
+ } else {
+ copy.push_back("--app-image-file=" + app_image_file_name);
+ }
+ }
GenerateOdexForTest(dex_location,
odex_location,
CompilerFilter::kSpeedProfile,
copy,
/* expect_success */ true,
use_fd);
+ if (app_image_file != nullptr) {
+ ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
+ }
}
- void RunTest() {
+ uint64_t GetImageSize(const std::string& image_file_name) {
+ EXPECT_FALSE(image_file_name.empty());
+ std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
+ CHECK(file != nullptr);
+ ImageHeader image_header;
+ const bool success = file->ReadFully(&image_header, sizeof(image_header));
+ CHECK(success);
+ CHECK(image_header.IsValid());
+ ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
+ return image_header.GetImageSize();
+ }
+
+ void RunTest(bool app_image) {
std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
+ std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): "";
Copy(GetDexSrc2(), dex_location);
- CompileProfileOdex(dex_location, odex_location, /* use_fd */ false);
-
+ uint64_t image_file_empty_profile = 0;
+ if (app_image) {
+ CompileProfileOdex(dex_location,
+ odex_location,
+ app_image_file,
+ /* use_fd */ false,
+ /* num_profile_classes */ 0);
+ CheckValidity();
+ ASSERT_TRUE(success_);
+ // Don't check the result since CheckResult relies on the class being in the profile.
+ image_file_empty_profile = GetImageSize(app_image_file);
+ EXPECT_GT(image_file_empty_profile, 0u);
+ }
+
+ // Small profile.
+ CompileProfileOdex(dex_location,
+ odex_location,
+ app_image_file,
+ /* use_fd */ false,
+ /* num_profile_classes */ 1);
CheckValidity();
ASSERT_TRUE(success_);
- CheckResult(dex_location, odex_location);
+ CheckResult(dex_location, odex_location, app_image_file);
+
+ if (app_image) {
+ // Test that the profile made a difference by adding more classes.
+ const uint64_t image_file_small_profile = GetImageSize(app_image_file);
+ CHECK_LT(image_file_empty_profile, image_file_small_profile);
+ }
}
void RunTestVDex() {
std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
+ std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art";
Copy(GetDexSrc2(), dex_location);
std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
@@ -643,7 +702,9 @@ class Dex2oatLayoutTest : public Dex2oatTest {
std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
CompileProfileOdex(dex_location,
odex_location,
+ app_image_file_name,
/* use_fd */ true,
+ /* num_profile_classes */ 1,
{ input_vdex, output_vdex });
EXPECT_GT(vdex_file1->GetLength(), 0u);
}
@@ -652,17 +713,21 @@ class Dex2oatLayoutTest : public Dex2oatTest {
std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
CompileProfileOdex(dex_location,
odex_location,
+ app_image_file_name,
/* use_fd */ true,
+ /* num_profile_classes */ 1,
{ input_vdex, output_vdex });
EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
}
ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
CheckValidity();
ASSERT_TRUE(success_);
- CheckResult(dex_location, odex_location);
+ CheckResult(dex_location, odex_location, app_image_file_name);
}
- void CheckResult(const std::string& dex_location, const std::string& odex_location) {
+ void CheckResult(const std::string& dex_location,
+ const std::string& odex_location,
+ const std::string& app_image_file_name) {
// Host/target independent checks.
std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
@@ -698,6 +763,16 @@ class Dex2oatLayoutTest : public Dex2oatTest {
}
EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
+
+ if (!app_image_file_name.empty()) {
+ // Go peek at the image header to make sure it was large enough to contain the class.
+ std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str()));
+ ImageHeader image_header;
+ bool success = file->ReadFully(&image_header, sizeof(image_header));
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(image_header.IsValid());
+ EXPECT_GT(image_header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u);
+ }
}
// Check whether the dex2oat run was really successful.
@@ -720,7 +795,11 @@ class Dex2oatLayoutTest : public Dex2oatTest {
};
TEST_F(Dex2oatLayoutTest, TestLayout) {
- RunTest();
+ RunTest(/* app-image */ false);
+}
+
+TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) {
+ RunTest(/* app-image */ true);
}
TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cac5449c4c..d232714338 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8933,7 +8933,7 @@ std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_bo
return ret;
}
-std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForProfileKeys(
+std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForResolvedClasses(
const std::set<DexCacheResolvedClasses>& classes) {
ScopedTrace trace(__PRETTY_FUNCTION__);
std::unordered_set<std::string> ret;
@@ -8948,14 +8948,13 @@ std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForProfileKeys(
if (dex_cache != nullptr) {
const DexFile* dex_file = dex_cache->GetDexFile();
// There could be duplicates if two dex files with the same location are mapped.
- location_to_dex_file.emplace(
- ProfileCompilationInfo::GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
+ location_to_dex_file.emplace(dex_file->GetLocation(), dex_file);
}
}
}
for (const DexCacheResolvedClasses& info : classes) {
- const std::string& profile_key = info.GetDexLocation();
- auto found = location_to_dex_file.find(profile_key);
+ const std::string& location = info.GetDexLocation();
+ auto found = location_to_dex_file.find(location);
if (found != location_to_dex_file.end()) {
const DexFile* dex_file = found->second;
VLOG(profiler) << "Found opened dex file for " << dex_file->GetLocation() << " with "
@@ -8967,7 +8966,7 @@ std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForProfileKeys(
ret.insert(descriptor);
}
} else {
- VLOG(class_linker) << "Failed to find opened dex file for profile key " << profile_key;
+ VLOG(class_linker) << "Failed to find opened dex file for location " << location;
}
}
return ret;
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 33eed3c8e3..a5d26c7a88 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -617,7 +617,8 @@ class ClassLinker {
std::set<DexCacheResolvedClasses> GetResolvedClasses(bool ignore_boot_classes)
REQUIRES(!Locks::dex_lock_);
- std::unordered_set<std::string> GetClassDescriptorsForProfileKeys(
+ // Returns the class descriptors for loaded dex files.
+ std::unordered_set<std::string> GetClassDescriptorsForResolvedClasses(
const std::set<DexCacheResolvedClasses>& classes)
REQUIRES(!Locks::dex_lock_);
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 627cc93f38..3467b60343 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -1039,15 +1039,22 @@ bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
return info_.Equals(other.info_);
}
-std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses() const {
+std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses(
+ const std::unordered_set<std::string>& dex_files_locations) const {
+ std::unordered_map<std::string, std::string> key_to_location_map;
+ for (const std::string& location : dex_files_locations) {
+ key_to_location_map.emplace(GetProfileDexFileKey(location), location);
+ }
std::set<DexCacheResolvedClasses> ret;
for (auto&& pair : info_) {
const std::string& profile_key = pair.first;
- const DexFileData& data = pair.second;
- // TODO: Is it OK to use the same location for both base and dex location here?
- DexCacheResolvedClasses classes(profile_key, profile_key, data.checksum);
- classes.AddClasses(data.class_set.begin(), data.class_set.end());
- ret.insert(classes);
+ auto it = key_to_location_map.find(profile_key);
+ if (it != key_to_location_map.end()) {
+ const DexFileData& data = pair.second;
+ DexCacheResolvedClasses classes(it->second, it->second, data.checksum);
+ classes.AddClasses(data.class_set.begin(), data.class_set.end());
+ ret.insert(classes);
+ }
}
return ret;
}
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index 4bfbfcd287..cf556bf3e1 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -218,9 +218,8 @@ class ProfileCompilationInfo {
bool Equals(const ProfileCompilationInfo& other);
// Return the class descriptors for all of the classes in the profiles' class sets.
- // Note the dex location is actually the profile key, the caller needs to call back in to the
- // profile info stuff to generate a map back to the dex location.
- std::set<DexCacheResolvedClasses> GetResolvedClasses() const;
+ std::set<DexCacheResolvedClasses> GetResolvedClasses(
+ const std::unordered_set<std::string>& dex_files_locations) const;
// Clear the resolved classes from the current object.
void ClearResolvedClasses();