diff options
Diffstat (limited to 'profman')
| -rw-r--r-- | profman/Android.bp | 22 | ||||
| -rw-r--r-- | profman/include/profman/profman_result.h | 69 | ||||
| -rw-r--r-- | profman/profile_assistant.cc | 46 | ||||
| -rw-r--r-- | profman/profile_assistant.h | 20 | ||||
| -rw-r--r-- | profman/profile_assistant_test.cc | 345 | ||||
| -rw-r--r-- | profman/profman.cc | 97 |
6 files changed, 450 insertions, 149 deletions
diff --git a/profman/Android.bp b/profman/Android.bp index b231499c99..ac80641fae 100644 --- a/profman/Android.bp +++ b/profman/Android.bp @@ -32,6 +32,7 @@ cc_defaults { "profman.cc", "profile_assistant.cc", ], + header_libs: ["profman_headers"], target: { android: { @@ -109,6 +110,7 @@ art_cc_binary { apex_available: [ "com.android.art", "com.android.art.debug", + "test_broken_com.android.art", ], } @@ -160,11 +162,31 @@ art_cc_binary { }, } +cc_library_headers { + name: "profman_headers", + defaults: ["art_defaults"], + export_include_dirs: ["include"], + host_supported: true, + target: { + darwin: { + enabled: false, + }, + windows: { + enabled: true, + }, + }, + apex_available: [ + "com.android.art", + "com.android.art.debug", + ], +} + art_cc_defaults { name: "art_profman_tests_defaults", data: [ ":art-gtest-jars-ProfileTestMultiDex", ], + header_libs: ["profman_headers"], tidy_timeout_srcs: ["profile_assistant_test.cc"], srcs: ["profile_assistant_test.cc"], } diff --git a/profman/include/profman/profman_result.h b/profman/include/profman/profman_result.h new file mode 100644 index 0000000000..9c9aca9e05 --- /dev/null +++ b/profman/include/profman/profman_result.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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_INCLUDE_PROFMAN_PROFMAN_RESULT_H_ +#define ART_PROFMAN_INCLUDE_PROFMAN_PROFMAN_RESULT_H_ + +namespace art { + +class ProfmanResult { + public: + static constexpr int kErrorUsage = 100; + + // The return codes of processing profiles (running profman in normal mode). + // + // On a successful run: + // - If `--force-merge` is specified, the return code can only be `kSuccess`. + // - If no `--profile-file(-fd)` is specified, the return code can only be + // `kSkipCompilationSmallDelta` or `kSkipCompilationEmptyProfiles`. + // - Otherwise, the return code can only be `kCompile`, `kSkipCompilationSmallDelta`, or + // `kSkipCompilationEmptyProfiles`. + // + // Note that installd consumes the returns codes with its own copy of these values + // (frameworks/native/cmds/installd/dexopt.cpp). + enum ProcessingResult { + // The success code for `--force-merge`. + // This is also the generic success code for non-analysis runs. + kSuccess = 0, + // A merge has been performed, meaning the reference profile has been changed. + kCompile = 1, + // `--profile-file(-fd)` is not specified, or the specified profiles are outdated (i.e., APK + // filename or checksum mismatch), empty, or don't contain enough number of new classes and + // methods that meets the threshold to trigger a merge. + kSkipCompilationSmallDelta = 2, + // All the input profiles (including the reference profile) are either outdated (i.e., APK + // filename or checksum mismatch) or empty. + kSkipCompilationEmptyProfiles = 7, + // Errors. + kErrorBadProfiles = 3, + kErrorIO = 4, + kErrorCannotLock = 5, + kErrorDifferentVersions = 6, + }; + + // The return codes of running profman with `--copy-and-update-profile-key`. + enum CopyAndUpdateResult { + kCopyAndUpdateSuccess = 0, + kCopyAndUpdateNoMatch = 21, + kCopyAndUpdateErrorFailedToUpdateProfile = 22, + kCopyAndUpdateErrorFailedToSaveProfile = 23, + kCopyAndUpdateErrorFailedToLoadProfile = 24, + }; +}; + +} // namespace art + +#endif // ART_PROFMAN_INCLUDE_PROFMAN_PROFMAN_RESULT_H_ diff --git a/profman/profile_assistant.cc b/profman/profile_assistant.cc index d098738845..abbde2d527 100644 --- a/profman/profile_assistant.cc +++ b/profman/profile_assistant.cc @@ -18,6 +18,7 @@ #include "base/os.h" #include "base/unix_file/fd_file.h" +#include "profman/profman_result.h" namespace art { @@ -26,25 +27,22 @@ namespace art { static constexpr const uint32_t kMinNewMethodsForCompilation = 100; static constexpr const uint32_t kMinNewClassesForCompilation = 50; - -ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal( - const std::vector<ScopedFlock>& profile_files, - const ScopedFlock& reference_profile_file, - const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn, - const Options& options) { - DCHECK(!profile_files.empty()); - +ProfmanResult::ProcessingResult ProfileAssistant::ProcessProfilesInternal( + const std::vector<ScopedFlock>& profile_files, + const ScopedFlock& reference_profile_file, + const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn, + const Options& options) { ProfileCompilationInfo info(options.IsBootImageMerge()); // Load the reference profile. if (!info.Load(reference_profile_file->Fd(), /*merge_classes=*/ true, filter_fn)) { LOG(WARNING) << "Could not load reference profile file"; - return kErrorBadProfiles; + return ProfmanResult::kErrorBadProfiles; } if (options.IsBootImageMerge() && !info.IsForBootImage()) { LOG(WARNING) << "Requested merge for boot image profile but the reference profile is regular."; - return kErrorBadProfiles; + return ProfmanResult::kErrorBadProfiles; } // Store the current state of the reference profile before merging with the current profiles. @@ -65,21 +63,21 @@ ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal( // TODO: Do we really need to use a different error code for version mismatch? ProfileCompilationInfo wrong_info(!options.IsBootImageMerge()); if (wrong_info.Load(profile_files[i]->Fd(), /*merge_classes=*/ true, filter_fn)) { - return kErrorDifferentVersions; + return ProfmanResult::kErrorDifferentVersions; } - return kErrorBadProfiles; + return ProfmanResult::kErrorBadProfiles; } if (!info.MergeWith(cur_info)) { LOG(WARNING) << "Could not merge profile file at index " << i; - return kErrorBadProfiles; + return ProfmanResult::kErrorBadProfiles; } } // If we perform a forced merge do not analyze the difference between profiles. if (!options.IsForceMerge()) { if (info.IsEmpty()) { - return kSkipCompilationEmptyProfiles; + return ProfmanResult::kSkipCompilationEmptyProfiles; } uint32_t min_change_in_methods_for_compilation = std::max( (options.GetMinNewMethodsPercentChangeForCompilation() * number_of_methods) / 100, @@ -91,21 +89,21 @@ ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal( if (((info.GetNumberOfMethods() - number_of_methods) < min_change_in_methods_for_compilation) && ((info.GetNumberOfResolvedClasses() - number_of_classes) < min_change_in_classes_for_compilation)) { - return kSkipCompilationSmallDelta; + return ProfmanResult::kSkipCompilationSmallDelta; } } // We were successful in merging all profile information. Update the reference profile. if (!reference_profile_file->ClearContent()) { PLOG(WARNING) << "Could not clear reference profile file"; - return kErrorIO; + return ProfmanResult::kErrorIO; } if (!info.Save(reference_profile_file->Fd())) { LOG(WARNING) << "Could not save reference profile file"; - return kErrorIO; + return ProfmanResult::kErrorIO; } - return options.IsForceMerge() ? kSuccess : kCompile; + return options.IsForceMerge() ? ProfmanResult::kSuccess : ProfmanResult::kCompile; } class ScopedFlockList { @@ -144,7 +142,7 @@ class ScopedFlockList { std::vector<ScopedFlock> flocks_; }; -ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( +ProfmanResult::ProcessingResult ProfileAssistant::ProcessProfiles( const std::vector<int>& profile_files_fd, int reference_profile_file_fd, const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn, @@ -155,7 +153,7 @@ ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( ScopedFlockList profile_files(profile_files_fd.size()); if (!profile_files.Init(profile_files_fd, &error)) { LOG(WARNING) << "Could not lock profile files: " << error; - return kErrorCannotLock; + return ProfmanResult::kErrorCannotLock; } // The reference_profile_file is opened in read/write mode because it's @@ -166,7 +164,7 @@ ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( &error); if (reference_profile_file.get() == nullptr) { LOG(WARNING) << "Could not lock reference profiled files: " << error; - return kErrorCannotLock; + return ProfmanResult::kErrorCannotLock; } return ProcessProfilesInternal(profile_files.Get(), @@ -175,7 +173,7 @@ ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( options); } -ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( +ProfmanResult::ProcessingResult ProfileAssistant::ProcessProfiles( const std::vector<std::string>& profile_files, const std::string& reference_profile_file, const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn, @@ -185,14 +183,14 @@ ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( ScopedFlockList profile_files_list(profile_files.size()); if (!profile_files_list.Init(profile_files, &error)) { LOG(WARNING) << "Could not lock profile files: " << error; - return kErrorCannotLock; + return ProfmanResult::kErrorCannotLock; } ScopedFlock locked_reference_profile_file = LockedFile::Open( reference_profile_file.c_str(), O_RDWR, /* block= */ true, &error); if (locked_reference_profile_file.get() == nullptr) { LOG(WARNING) << "Could not lock reference profile files: " << error; - return kErrorCannotLock; + return ProfmanResult::kErrorCannotLock; } return ProcessProfilesInternal(profile_files_list.Get(), diff --git a/profman/profile_assistant.h b/profman/profile_assistant.h index 0ef4f8895a..6b7a7a67f5 100644 --- a/profman/profile_assistant.h +++ b/profman/profile_assistant.h @@ -22,24 +22,12 @@ #include "base/scoped_flock.h" #include "profile/profile_compilation_info.h" +#include "profman/profman_result.h" namespace art { class ProfileAssistant { public: - // These also serve as return codes of profman and are processed by installd - // (frameworks/native/cmds/installd/commands.cpp) - enum ProcessingResult { - kSuccess = 0, // Generic success code for non-analysis runs. - kCompile = 1, - kSkipCompilationSmallDelta = 2, - kErrorBadProfiles = 3, - kErrorIO = 4, - kErrorCannotLock = 5, - kErrorDifferentVersions = 6, - kSkipCompilationEmptyProfiles = 7, - }; - class Options { public: static constexpr bool kForceMergeDefault = false; @@ -101,14 +89,14 @@ class ProfileAssistant { // this case no file will be updated. A variation of this code is // kSkipCompilationEmptyProfiles which indicates that all the profiles are empty. // This allow the caller to make fine grain decisions on the compilation strategy. - static ProcessingResult ProcessProfiles( + static ProfmanResult::ProcessingResult ProcessProfiles( const std::vector<std::string>& profile_files, const std::string& reference_profile_file, const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn = ProfileCompilationInfo::ProfileFilterFnAcceptAll, const Options& options = Options()); - static ProcessingResult ProcessProfiles( + static ProfmanResult::ProcessingResult ProcessProfiles( const std::vector<int>& profile_files_fd_, int reference_profile_file_fd, const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn @@ -116,7 +104,7 @@ class ProfileAssistant { const Options& options = Options()); private: - static ProcessingResult ProcessProfilesInternal( + static ProfmanResult::ProcessingResult ProcessProfilesInternal( const std::vector<ScopedFlock>& profile_files, const ScopedFlock& reference_profile_file, const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn, diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index f446c0919b..f7c4255071 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -14,7 +14,8 @@ * limitations under the License. */ -#include <gtest/gtest.h> +#include "profile_assistant.h" + #include <sstream> #include <string> @@ -31,12 +32,13 @@ #include "dex/dex_instruction_iterator.h" #include "dex/type_reference.h" #include "exec_utils.h" +#include "gtest/gtest.h" #include "linear_alloc.h" #include "mirror/class-inl.h" #include "obj_ptr-inl.h" #include "profile/profile_compilation_info.h" #include "profile/profile_test_helper.h" -#include "profile_assistant.h" +#include "profman/profman_result.h" #include "scoped_thread_state_change-inl.h" namespace art { @@ -50,13 +52,13 @@ class ProfileAssistantTest : public CommonRuntimeTest, public ProfileTestHelper void PostRuntimeCreate() override { allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); - dex1 = BuildDex("location1", /*checksum=*/ 1, "LUnique1;", /*num_method_ids=*/ 10001); - dex2 = BuildDex("location2", /*checksum=*/ 2, "LUnique2;", /*num_method_ids=*/ 10002); - dex3 = BuildDex("location3", /*checksum=*/ 3, "LUnique3;", /*num_method_ids=*/ 10003); - dex4 = BuildDex("location4", /*checksum=*/ 4, "LUnique4;", /*num_method_ids=*/ 10004); + dex1 = BuildDex("location1", /*location_checksum=*/ 1, "LUnique1;", /*num_method_ids=*/ 10001); + dex2 = BuildDex("location2", /*location_checksum=*/ 2, "LUnique2;", /*num_method_ids=*/ 10002); + dex3 = BuildDex("location3", /*location_checksum=*/ 3, "LUnique3;", /*num_method_ids=*/ 10003); + dex4 = BuildDex("location4", /*location_checksum=*/ 4, "LUnique4;", /*num_method_ids=*/ 10004); dex1_checksum_missmatch = - BuildDex("location1", /*checksum=*/ 12, "LUnique1;", /*num_method_ids=*/ 10001); + BuildDex("location1", /*location_checksum=*/ 12, "LUnique1;", /*num_method_ids=*/ 10001); } protected: @@ -267,7 +269,7 @@ class ProfileAssistantTest : public CommonRuntimeTest, public ProfileTestHelper bool CreateAndDump(const std::string& input_file_contents, std::string* output_file_contents, - std::optional<const std::string> target = std::nullopt) { + const std::optional<const std::string>& target = std::nullopt) { ScratchFile profile_file; EXPECT_TRUE(CreateProfile(input_file_contents, profile_file.GetFilename(), @@ -442,10 +444,16 @@ class ProfileAssistantTest : public CommonRuntimeTest, public ProfileTestHelper const std::vector<const std::string>& extra_args = std::vector<const std::string>()) { uint16_t max_classes = std::max(classes_in_cur_profile, classes_in_ref_profile); - const DexFile* dex1_x = BuildDex( - "location1_x", /*checksum=*/ 0x101, "LUnique1_x;", /*num_method_ids=*/ 0, max_classes); - const DexFile* dex2_x = BuildDex( - "location2_x", /*checksum=*/ 0x102, "LUnique2_x;", /*num_method_ids=*/ 0, max_classes); + const DexFile* dex1_x = BuildDex("location1_x", + /*location_checksum=*/ 0x101, + "LUnique1_x;", + /*num_method_ids=*/ 0, + max_classes); + const DexFile* dex2_x = BuildDex("location2_x", + /*location_checksum=*/ 0x102, + "LUnique2_x;", + /*num_method_ids=*/ 0, + max_classes); ScratchFile profile; ScratchFile reference_profile; @@ -486,8 +494,7 @@ TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) { SetupProfile(dex3, dex4, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - ProcessProfiles(profile_fds, reference_profile_fd)); + ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd)); // The resulting compilation info must be equal to the merge of the inputs. ProfileCompilationInfo result; ASSERT_TRUE(result.Load(reference_profile_fd)); @@ -506,15 +513,15 @@ TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) { TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) { const uint16_t kNumberOfClassesToEnableCompilation = 100; const DexFile* dex1_100 = BuildDex("location1_100", - /*checksum=*/ 101, + /*location_checksum=*/ 101, "LUnique1_100;", /*num_method_ids=*/ 0, - /*num_type_ids=*/ 100); + /*num_class_ids=*/ 100); const DexFile* dex2_100 = BuildDex("location2_100", - /*checksum=*/ 102, + /*location_checksum=*/ 102, "LUnique2_100;", /*num_method_ids=*/ 0, - /*num_type_ids=*/ 100); + /*num_class_ids=*/ 100); ScratchFile profile1; ScratchFile reference_profile; @@ -527,8 +534,7 @@ TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) { SetupProfile(dex1_100, dex2_100, 0, kNumberOfClassesToEnableCompilation, profile1, &info1); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - ProcessProfiles(profile_fds, reference_profile_fd)); + ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd)); // The resulting compilation info must be equal to the merge of the inputs. ProfileCompilationInfo result; ASSERT_TRUE(result.Load(reference_profile_fd)); @@ -566,8 +572,7 @@ TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) { &reference_info, kNumberOfMethodsToEnableCompilation / 2); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - ProcessProfiles(profile_fds, reference_profile_fd)); + ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd)); // The resulting compilation info must be equal to the merge of the inputs ProfileCompilationInfo result; @@ -600,7 +605,7 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilationEmptyProfile) { SetupProfile(dex3, dex4, /*number_of_methods=*/ 0, /*number_of_classes*/ 0, profile2, &info2); // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kSkipCompilationEmptyProfiles, + ASSERT_EQ(ProfmanResult::kSkipCompilationEmptyProfiles, ProcessProfiles(profile_fds, reference_profile_fd)); // The information from profiles must remain the same. @@ -637,7 +642,7 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) { SetupProfile(dex3, dex4, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2); // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kSkipCompilationSmallDelta, + ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta, ProcessProfiles(profile_fds, reference_profile_fd)); // The information from profiles must remain the same. @@ -663,10 +668,9 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) { std::vector<const std::string> extra_args({"--min-new-methods-percent-change=2"}); // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kSkipCompilationSmallDelta, - CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile, - kNumberOfMethodsInRefProfile, - extra_args)); + ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta, + CheckCompilationMethodPercentChange( + kNumberOfMethodsInCurProfile, kNumberOfMethodsInRefProfile, extra_args)); } TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) { @@ -675,10 +679,9 @@ TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) { std::vector<const std::string> extra_args({"--min-new-methods-percent-change=2"}); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile, - kNumberOfMethodsInRefProfile, - extra_args)); + ASSERT_EQ(ProfmanResult::kCompile, + CheckCompilationMethodPercentChange( + kNumberOfMethodsInCurProfile, kNumberOfMethodsInRefProfile, extra_args)); } TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentageWithNewMin) { @@ -686,7 +689,7 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentageWithNewMin) { const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 20%. // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kSkipCompilationSmallDelta, + ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta, CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile, kNumberOfMethodsInRefProfile)); } @@ -697,10 +700,9 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilationClassPercentage) { std::vector<const std::string> extra_args({"--min-new-classes-percent-change=2"}); // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kSkipCompilationSmallDelta, - CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile, - kNumberOfClassesInRefProfile, - extra_args)); + ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta, + CheckCompilationClassPercentChange( + kNumberOfClassesInCurProfile, kNumberOfClassesInRefProfile, extra_args)); } TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) { @@ -709,10 +711,9 @@ TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) { std::vector<const std::string> extra_args({"--min-new-classes-percent-change=2"}); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile, - kNumberOfClassesInRefProfile, - extra_args)); + ASSERT_EQ(ProfmanResult::kCompile, + CheckCompilationClassPercentChange( + kNumberOfClassesInCurProfile, kNumberOfClassesInRefProfile, extra_args)); } TEST_F(ProfileAssistantTest, DoNotAdviseCompilationClassPercentageWithNewMin) { @@ -720,7 +721,7 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilationClassPercentageWithNewMin) { const uint16_t kNumberOfClassesInCurProfile = 6200; // Threshold is 20%. // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kSkipCompilationSmallDelta, + ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta, CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile, kNumberOfClassesInRefProfile)); } @@ -744,8 +745,7 @@ TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) { dex1_checksum_missmatch, dex2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2); // We should fail processing. - ASSERT_EQ(ProfileAssistant::kErrorBadProfiles, - ProcessProfiles(profile_fds, reference_profile_fd)); + ASSERT_EQ(ProfmanResult::kErrorBadProfiles, ProcessProfiles(profile_fds, reference_profile_fd)); // The information from profiles must remain the same. CheckProfileInfo(profile1, info1); @@ -776,8 +776,7 @@ TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) { &reference_info); // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kErrorBadProfiles, - ProcessProfiles(profile_fds, reference_profile_fd)); + ASSERT_EQ(ProfmanResult::kErrorBadProfiles, ProcessProfiles(profile_fds, reference_profile_fd)); // The information from profiles must remain the same. CheckProfileInfo(profile1, info1); @@ -971,7 +970,7 @@ TEST_F(ProfileAssistantTest, TestBootImageProfile) { /*for_boot_image=*/ true)); ProfileCompilationInfo bootProfile(/*for_boot_image=*/ true); - bootProfile.Load(profile.GetFilename(), /*clear_if_invalid=*/ true); + EXPECT_TRUE(bootProfile.Load(profile.GetFilename(), /*clear_if_invalid=*/ false)); // Generate the boot profile. ScratchFile out_profile; @@ -1065,10 +1064,10 @@ TEST_F(ProfileAssistantTest, TestBootImageProfileWith2RawProfiles) { core_dex, /*for_boot_image=*/ true)); - ProfileCompilationInfo boot_profile1; - ProfileCompilationInfo boot_profile2; - boot_profile1.Load(profile1.GetFilename(), /*for_boot_image=*/ true); - boot_profile2.Load(profile2.GetFilename(), /*for_boot_image=*/ true); + ProfileCompilationInfo boot_profile1(/*for_boot_image=*/ true); + ProfileCompilationInfo boot_profile2(/*for_boot_image=*/ true); + EXPECT_TRUE(boot_profile1.Load(profile1.GetFilename(), /*clear_if_invalid=*/ false)); + EXPECT_TRUE(boot_profile2.Load(profile2.GetFilename(), /*clear_if_invalid=*/ false)); // Generate the boot profile. ScratchFile out_profile; @@ -1525,8 +1524,7 @@ TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) { &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order=*/true); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - ProcessProfiles(profile_fds, reference_profile_fd)); + ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd)); // The resulting compilation info must be equal to the merge of the inputs. ProfileCompilationInfo result; @@ -1787,7 +1785,7 @@ TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) { argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); std::string error; - EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfileAssistant::kCompile) << error; + EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kCompile) << error; // Verify that we can load the result. @@ -1820,6 +1818,169 @@ TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) { ASSERT_TRUE(expected.Equals(result)); } +TEST_F(ProfileAssistantTest, MergeProfilesNoProfile) { + ScratchFile reference_profile; + + // Use a real dex file to generate profile test data. + std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex"); + const DexFile& d1 = *dex_files[0]; + const DexFile& d2 = *dex_files[0]; + + // The reference profile info will contain the methods with indices 0-100. + ProfileCompilationInfo reference_info; + SetupProfile(&d1, + &d2, + /*number_of_methods=*/ 100, + /*number_of_classes=*/ 0, + reference_profile, + &reference_info); + + std::string content_before; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before)); + + // Run profman and pass the dex file with --apk-fd. + android::base::unique_fd apk_fd( + // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec() + open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); + ASSERT_GE(apk_fd.get(), 0); + + std::string profman_cmd = GetProfmanCmd(); + std::vector<std::string> argv_str; + argv_str.push_back(profman_cmd); + argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd())); + argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); + + // Must return kSkipCompilationSmallDelta. + std::string error; + EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationSmallDelta) + << error; + + // Verify that the content has not changed. + std::string content_after; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after)); + EXPECT_EQ(content_before, content_after); +} + +TEST_F(ProfileAssistantTest, MergeProfilesNoProfilePassByFilename) { + ScratchFile reference_profile; + + // Use a real dex file to generate profile test data. + std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex"); + const DexFile& d1 = *dex_files[0]; + const DexFile& d2 = *dex_files[0]; + + // The reference profile info will contain the methods with indices 0-100. + ProfileCompilationInfo reference_info; + SetupProfile(&d1, + &d2, + /*number_of_methods=*/100, + /*number_of_classes=*/0, + reference_profile, + &reference_info); + + std::string content_before; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before)); + + // Run profman and pass the dex file with --apk-fd. + android::base::unique_fd apk_fd( + // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec() + open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); + ASSERT_GE(apk_fd.get(), 0); + + std::string profman_cmd = GetProfmanCmd(); + std::vector<std::string> argv_str; + argv_str.push_back(profman_cmd); + argv_str.push_back("--reference-profile-file=" + reference_profile.GetFilename()); + argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); + + // Must return kSkipCompilationSmallDelta. + std::string error; + EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationSmallDelta) + << error; + + // Verify that the content has not changed. + std::string content_after; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after)); + EXPECT_EQ(content_before, content_after); +} + +TEST_F(ProfileAssistantTest, MergeProfilesNoProfileEmptyReferenceProfile) { + ScratchFile reference_profile; + + // The reference profile info will only contain the header. + ProfileCompilationInfo reference_info; + SetupProfile(/*dex_file1=*/ nullptr, + /*dex_file2=*/ nullptr, + /*number_of_methods=*/ 0, + /*number_of_classes=*/ 0, + reference_profile, + &reference_info); + + std::string content_before; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before)); + + // Run profman and pass the dex file with --apk-fd. + android::base::unique_fd apk_fd( + // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec() + open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); + ASSERT_GE(apk_fd.get(), 0); + + std::string profman_cmd = GetProfmanCmd(); + std::vector<std::string> argv_str; + argv_str.push_back(profman_cmd); + argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd())); + argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); + + // Must return kSkipCompilationEmptyProfiles. + std::string error; + EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationEmptyProfiles) + << error; + + // Verify that the content has not changed. + std::string content_after; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after)); + EXPECT_EQ(content_before, content_after); +} + +TEST_F(ProfileAssistantTest, MergeProfilesNoProfileEmptyReferenceProfileAfterFiltering) { + ScratchFile reference_profile; + + // Use fake dex files to generate profile test data. + // All the methods will be filtered out during the profman invocation. + ProfileCompilationInfo reference_info; + SetupProfile(dex1, + dex2, + /*number_of_methods=*/ 100, + /*number_of_classes=*/ 0, + reference_profile, + &reference_info); + + std::string content_before; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before)); + + // Run profman and pass the real dex file with --apk-fd. + android::base::unique_fd apk_fd( + // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec() + open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); + ASSERT_GE(apk_fd.get(), 0); + + std::string profman_cmd = GetProfmanCmd(); + std::vector<std::string> argv_str; + argv_str.push_back(profman_cmd); + argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd())); + argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); + + // Must return kSkipCompilationEmptyProfiles. + std::string error; + EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationEmptyProfiles) + << error; + + // Verify that the content has not changed. + std::string content_after; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after)); + EXPECT_EQ(content_before, content_after); +} + TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) { ScratchFile profile1; ScratchFile reference_profile; @@ -1846,7 +2007,8 @@ TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) { // Run profman and pass the dex file with --apk-fd. android::base::unique_fd apk_fd( - open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); // NOLINT + // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec() + open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); ASSERT_GE(apk_fd.get(), 0); std::string profman_cmd = GetProfmanCmd(); @@ -1858,7 +2020,8 @@ TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) { argv_str.push_back("--copy-and-update-profile-key"); std::string error; - ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error; + // Must return kCopyAndUpdateSuccess. + ASSERT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kCopyAndUpdateSuccess) << error; // Verify that we can load the result. ProfileCompilationInfo result; @@ -1874,6 +2037,46 @@ TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) { } } +TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKeyNoUpdate) { + ScratchFile profile1; + ScratchFile reference_profile; + + // Use fake dex files to generate profile test data. + ProfileCompilationInfo info1; + SetupProfile(dex1, + dex2, + /*number_of_methods=*/ 100, + /*number_of_classes=*/ 0, + profile1, + &info1); + + std::string input_content; + ASSERT_TRUE(android::base::ReadFileToString(profile1.GetFilename(), &input_content)); + + // Run profman and pass the real dex file with --apk-fd. It won't match any entry in the profile. + android::base::unique_fd apk_fd( + // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec() + open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); + ASSERT_GE(apk_fd.get(), 0); + + std::string profman_cmd = GetProfmanCmd(); + std::vector<std::string> argv_str; + argv_str.push_back(profman_cmd); + argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd())); + argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd())); + argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); + argv_str.push_back("--copy-and-update-profile-key"); + std::string error; + + // Must return kCopyAndUpdateNoMatch. + ASSERT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kCopyAndUpdateNoMatch) << error; + + // Verify that the content is the same. + std::string output_content; + ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &output_content)); + EXPECT_EQ(input_content, output_content); +} + TEST_F(ProfileAssistantTest, BootImageMerge) { ScratchFile profile; ScratchFile reference_profile; @@ -1900,7 +2103,7 @@ TEST_F(ProfileAssistantTest, BootImageMerge) { int return_code = ProcessProfiles(profile_fds, reference_profile_fd, extra_args); - ASSERT_EQ(return_code, ProfileAssistant::kSuccess); + ASSERT_EQ(return_code, ProfmanResult::kSuccess); // Verify the result: it should be equal to info2 since info1 is a regular profile // and should be ignored. @@ -1918,15 +2121,15 @@ TEST_F(ProfileAssistantTest, ForceMerge) { const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%. const DexFile* dex1_7000 = BuildDex("location1_7000", - /*checksum=*/ 7001, + /*location_checksum=*/ 7001, "LUnique1_7000;", /*num_method_ids=*/ 0, - /*num_type_ids=*/ 7000); + /*num_class_ids=*/ 7000); const DexFile* dex2_7000 = BuildDex("location2_7000", - /*checksum=*/ 7002, + /*location_checksum=*/ 7002, "LUnique2_7000;", /*num_method_ids=*/ 0, - /*num_type_ids=*/ 7000); + /*num_class_ids=*/ 7000); ScratchFile profile; ScratchFile reference_profile; @@ -1942,7 +2145,7 @@ TEST_F(ProfileAssistantTest, ForceMerge) { std::vector<const std::string> extra_args({"--force-merge"}); int return_code = ProcessProfiles(profile_fds, reference_profile_fd, extra_args); - ASSERT_EQ(return_code, ProfileAssistant::kSuccess); + ASSERT_EQ(return_code, ProfmanResult::kSuccess); // Check that the result is the aggregation. ProfileCompilationInfo result; @@ -1974,7 +2177,8 @@ TEST_F(ProfileAssistantTest, BootImageMergeWithAnnotations) { // Run profman and pass the dex file with --apk-fd. android::base::unique_fd apk_fd( - open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); // NOLINT + // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec() + open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); ASSERT_GE(apk_fd.get(), 0); std::string profman_cmd = GetProfmanCmd(); @@ -1987,7 +2191,7 @@ TEST_F(ProfileAssistantTest, BootImageMergeWithAnnotations) { argv_str.push_back("--boot-image-merge"); std::string error; - EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfileAssistant::kSuccess) << error; + EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSuccess) << error; // Verify that we can load the result and that it equals to what we saved. ProfileCompilationInfo result(/*for_boot_image=*/ true); @@ -2009,17 +2213,16 @@ TEST_F(ProfileAssistantTest, DifferentProfileVersions) { int reference_profile_fd = GetFd(profile2); std::vector<const std::string> boot_image_args({"--boot-image-merge"}); ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, boot_image_args), - ProfileAssistant::kErrorDifferentVersions); - ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd), - ProfileAssistant::kErrorBadProfiles); + ProfmanResult::kErrorDifferentVersions); + ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd), ProfmanResult::kErrorBadProfiles); // Reverse the order of the profiles to verify we get the same behaviour. profile_fds[0] = GetFd(profile2); reference_profile_fd = GetFd(profile1); ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, boot_image_args), - ProfileAssistant::kErrorBadProfiles); + ProfmanResult::kErrorBadProfiles); ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd), - ProfileAssistant::kErrorDifferentVersions); + ProfmanResult::kErrorDifferentVersions); } // Under default behaviour we will abort if we cannot load a profile during a merge @@ -2042,7 +2245,7 @@ TEST_F(ProfileAssistantTest, ForceMergeIgnoreProfilesItCannotLoad) { // With force-merge we should merge successfully. std::vector<const std::string> extra_args({"--force-merge", "--boot-image-merge"}); ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, extra_args), - ProfileAssistant::kSuccess); + ProfmanResult::kSuccess); ProfileCompilationInfo result(/*for_boot_image=*/ true); ASSERT_TRUE(result.Load(reference_profile_fd)); @@ -2051,7 +2254,7 @@ TEST_F(ProfileAssistantTest, ForceMergeIgnoreProfilesItCannotLoad) { // Without force-merge we should fail. std::vector<const std::string> extra_args2({"--boot-image-merge"}); ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, extra_args2), - ProfileAssistant::kErrorBadProfiles); + ProfmanResult::kErrorBadProfiles); } } // namespace art diff --git a/profman/profman.cc b/profman/profman.cc index 1968468f9c..375a489821 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -36,7 +36,6 @@ #include "android-base/parsebool.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" - #include "base/array_ref.h" #include "base/dumpable.h" #include "base/logging.h" // For InitLogging. @@ -64,6 +63,7 @@ #include "profile/profile_boot_info.h" #include "profile/profile_compilation_info.h" #include "profile_assistant.h" +#include "profman/profman_result.h" namespace art { @@ -118,7 +118,10 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(""); UsageError(" --profile-file=<filename>: specify profiler output file to use for compilation."); UsageError(" Can be specified multiple time, in which case the data from the different"); - UsageError(" profiles will be aggregated."); + UsageError(" profiles will be aggregated. Can also be specified zero times, in which case"); + UsageError(" profman will still analyze the reference profile against the given --apk and"); + UsageError(" return exit code based on whether the reference profile is empty and whether"); + UsageError(" an error occurs, but no merge will happen."); UsageError(""); UsageError(" --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor."); UsageError(" Cannot be used together with --profile-file."); @@ -126,8 +129,8 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(" --reference-profile-file=<filename>: specify a reference profile."); UsageError(" The data in this file will be compared with the data obtained by merging"); UsageError(" all the files specified with --profile-file or --profile-file-fd."); - UsageError(" If the exit code is EXIT_COMPILE then all --profile-file will be merged into"); - UsageError(" --reference-profile-file. "); + UsageError(" If the exit code is ProfmanResult::kCompile then all --profile-file will be"); + UsageError(" merged into --reference-profile-file. "); UsageError(""); UsageError(" --reference-profile-file-fd=<number>: same as --reference-profile-file but"); UsageError(" accepts a file descriptor. Cannot be used together with"); @@ -194,7 +197,7 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(" the min percent of new classes to trigger a compilation."); UsageError(""); - exit(EXIT_FAILURE); + exit(ProfmanResult::kErrorUsage); } // Note: make sure you update the Usage if you change these values. @@ -501,11 +504,10 @@ class ProfMan final { } }; - ProfileAssistant::ProcessingResult ProcessProfiles() { - // Validate that at least one profile file was passed, as well as a reference profile. - if (profile_files_.empty() && profile_files_fd_.empty()) { - Usage("No profile files specified."); - } + ProfmanResult::ProcessingResult ProcessProfiles() { + // Validate that a reference profile was passed, at the very least. It's okay that profiles are + // missing, in which case profman will still analyze the reference profile (to check whether + // it's empty), but no merge will happen. if (reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) { Usage("No reference profile file specified."); } @@ -518,7 +520,7 @@ class ProfMan final { // Check if we have any apks which we should use to filter the profile data. std::set<ProfileFilterKey> profile_filter_keys; if (!GetProfileFilterKeyFromApks(&profile_filter_keys)) { - return ProfileAssistant::kErrorIO; + return ProfmanResult::kErrorIO; } // Build the profile filter function. If the set of keys is empty it means we @@ -536,9 +538,9 @@ class ProfMan final { } }; - ProfileAssistant::ProcessingResult result; + ProfmanResult::ProcessingResult result; - if (profile_files_.empty()) { + if (reference_profile_file_.empty()) { // The file doesn't need to be flushed here (ProcessProfiles will do it) // so don't check the usage. File file(reference_profile_file_fd_, false); @@ -605,25 +607,29 @@ class ProfMan final { static constexpr bool kVerifyChecksum = true; for (size_t i = 0; i < dex_locations_.size(); ++i) { std::string error_msg; - const ArtDexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files_for_location; // We do not need to verify the apk for processing profiles. if (use_apk_fd_list) { - if (dex_file_loader.OpenZip(apks_fd_[i], - dex_locations_[i], - /* verify= */ false, - kVerifyChecksum, - &error_msg, - &dex_files_for_location)) { - } else { - LOG(ERROR) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg; + ArtDexFileLoader dex_file_loader(apks_fd_[i], dex_locations_[i]); + if (dex_file_loader.Open(/*verify=*/false, + kVerifyChecksum, + /*allow_no_dex_files=*/true, + &error_msg, + &dex_files_for_location)) { + } else { + LOG(ERROR) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg; + return false; + } + } else { + File file(apk_files_[i], O_RDONLY, /*check_usage=*/false); + if (file.Fd() < 0) { + PLOG(ERROR) << "Unable to open '" << apk_files_[i] << "'"; return false; } - } else { - if (dex_file_loader.Open(apk_files_[i].c_str(), - dex_locations_[i], - /* verify= */ false, + ArtDexFileLoader dex_file_loader(file.Release(), dex_locations_[i]); + if (dex_file_loader.Open(/*verify=*/false, kVerifyChecksum, + /*allow_no_dex_files=*/true, &error_msg, &dex_files_for_location)) { } else { @@ -1205,8 +1211,23 @@ class ProfMan final { for (std::string_view t : SplitString(ic_line.substr(1), kProfileParsingInlineChacheTargetSep)) { InlineCacheSegment out; - DCHECK_EQ(t[0], 'L') << "Target is not a class? " << t; - size_t recv_end = t.find_first_of(';'); + // The target may be an array for methods defined in `j.l.Object`, such as `clone()`. + size_t recv_end; + if (UNLIKELY(t[0] == '[')) { + recv_end = t.find_first_not_of('[', 1u); + DCHECK_NE(recv_end, std::string_view::npos); + if (t[recv_end] == 'L') { + recv_end = t.find_first_of(';', recv_end + 1u); + DCHECK_NE(recv_end, std::string_view::npos); + } else { + // Primitive array. + DCHECK_NE(Primitive::GetType(t[recv_end]), Primitive::kPrimNot); + } + } else { + DCHECK_EQ(t[0], 'L') << "Target is not a class? " << t; + recv_end = t.find_first_of(';', 1u); + DCHECK_NE(recv_end, std::string_view::npos); + } out.receiver_ = t.substr(0, recv_end + 1); Split(t.substr(recv_end + 1), kProfileParsingTypeSep, &out.inline_caches_); res->push_back(out); @@ -1854,7 +1875,7 @@ class ProfMan final { return copy_and_update_profile_key_; } - int32_t CopyAndUpdateProfileKey() { + ProfmanResult::CopyAndUpdateResult CopyAndUpdateProfileKey() { // Validate that at least one profile file was passed, as well as a reference profile. if (!(profile_files_.size() == 1 ^ profile_files_fd_.size() == 1)) { Usage("Only one profile file should be specified."); @@ -1867,10 +1888,6 @@ class ProfMan final { Usage("No apk files specified"); } - static constexpr int32_t kErrorFailedToUpdateProfile = -1; - static constexpr int32_t kErrorFailedToSaveProfile = -2; - static constexpr int32_t kErrorFailedToLoadProfile = -3; - bool use_fds = profile_files_fd_.size() == 1; ProfileCompilationInfo profile; @@ -1882,15 +1899,19 @@ class ProfMan final { // Open the dex files to look up classes and methods. std::vector<std::unique_ptr<const DexFile>> dex_files; OpenApkFilesFromLocations(&dex_files); - if (!profile.UpdateProfileKeys(dex_files)) { - return kErrorFailedToUpdateProfile; + bool matched = false; + if (!profile.UpdateProfileKeys(dex_files, &matched)) { + return ProfmanResult::kCopyAndUpdateErrorFailedToUpdateProfile; } bool result = use_fds ? profile.Save(reference_profile_file_fd_) : profile.Save(reference_profile_file_, /*bytes_written=*/ nullptr); - return result ? 0 : kErrorFailedToSaveProfile; + if (!result) { + return ProfmanResult::kCopyAndUpdateErrorFailedToSaveProfile; + } + return matched ? ProfmanResult::kCopyAndUpdateSuccess : ProfmanResult::kCopyAndUpdateNoMatch; } else { - return kErrorFailedToLoadProfile; + return ProfmanResult::kCopyAndUpdateErrorFailedToLoadProfile; } } @@ -1950,7 +1971,7 @@ std::ostream& operator<<(std::ostream& os, const ProfMan::InlineCacheSegment& ic return ics.Dump(os); } -// See ProfileAssistant::ProcessingResult for return codes. +// See ProfmanResult for return codes. static int profman(int argc, char** argv) { ProfMan profman; |