diff options
author | 2016-02-22 22:37:52 +0000 | |
---|---|---|
committer | 2016-02-22 22:37:52 +0000 | |
commit | 3da74687e42de7d33a8e75df9bd64374e650f75e (patch) | |
tree | f3bf62678200380dc672647af1da136c562f60b3 | |
parent | 6caefd983a800a063b219f1d3ed71b1416cecd70 (diff) |
Revert "Add profman tool: responsible to process profiles"
Needs a profile_assistant_test fix.
Bug: 26719109
Bug: 26563023
This reverts commit 6caefd983a800a063b219f1d3ed71b1416cecd70.
Change-Id: Ibdeb7385737dd7846ed861e0a95f083abb9aa974
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | build/Android.gtest.mk | 8 | ||||
-rw-r--r-- | compiler/Android.mk | 3 | ||||
-rw-r--r-- | compiler/profile_assistant.cc (renamed from profman/profile_assistant.cc) | 120 | ||||
-rw-r--r-- | compiler/profile_assistant.h | 72 | ||||
-rw-r--r-- | compiler/profile_assistant_test.cc (renamed from profman/profile_assistant_test.cc) | 204 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 112 | ||||
-rw-r--r-- | profman/Android.mk | 45 | ||||
-rw-r--r-- | profman/profile_assistant.h | 72 | ||||
-rw-r--r-- | profman/profman.cc | 208 | ||||
-rw-r--r-- | runtime/base/scoped_flock.cc | 10 | ||||
-rw-r--r-- | runtime/base/unix_file/fd_file.cc | 31 | ||||
-rw-r--r-- | runtime/base/unix_file/fd_file.h | 4 | ||||
-rw-r--r-- | runtime/jit/offline_profiling_info.cc | 10 | ||||
-rw-r--r-- | runtime/jit/offline_profiling_info.h | 7 | ||||
-rw-r--r-- | runtime/utils.cc | 27 | ||||
-rw-r--r-- | runtime/utils.h | 3 |
17 files changed, 353 insertions, 584 deletions
diff --git a/Android.mk b/Android.mk index e762814385..2e05d33209 100644 --- a/Android.mk +++ b/Android.mk @@ -86,7 +86,6 @@ include $(art_path)/disassembler/Android.mk include $(art_path)/oatdump/Android.mk include $(art_path)/imgdiag/Android.mk include $(art_path)/patchoat/Android.mk -include $(art_path)/profman/Android.mk include $(art_path)/dalvikvm/Android.mk include $(art_path)/tools/Android.mk include $(art_path)/tools/ahat/Android.mk diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 22c0e8d7d0..704d69a37a 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -144,12 +144,6 @@ ART_GTEST_oatdump_test_TARGET_DEPS := \ $(TARGET_CORE_IMAGE_default_no-pic_32) \ oatdump -# Profile assistant tests requires profman utility. -ART_GTEST_profile_assistant_test_HOST_DEPS := \ - $(HOST_OUT_EXECUTABLES)/profmand -ART_GTEST_profile_assistant_test_TARGET_DEPS := \ - profman - # The path for which all the source files are relative, not actually the current directory. LOCAL_PATH := art @@ -159,7 +153,6 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ dexlist/dexlist_test.cc \ imgdiag/imgdiag_test.cc \ oatdump/oatdump_test.cc \ - profman/profile_assistant_test.cc \ runtime/arch/arch_test.cc \ runtime/arch/instruction_set_test.cc \ runtime/arch/instruction_set_features_test.cc \ @@ -277,6 +270,7 @@ COMPILER_GTEST_COMMON_SRC_FILES := \ compiler/optimizing/ssa_test.cc \ compiler/optimizing/stack_map_test.cc \ compiler/optimizing/suspend_check_test.cc \ + compiler/profile_assistant_test.cc \ compiler/utils/arena_allocator_test.cc \ compiler/utils/dedupe_set_test.cc \ compiler/utils/swap_space_test.cc \ diff --git a/compiler/Android.mk b/compiler/Android.mk index 3dfb4b1fd4..b16494248f 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -108,7 +108,8 @@ LIBART_COMPILER_SRC_FILES := \ elf_writer.cc \ elf_writer_quick.cc \ image_writer.cc \ - oat_writer.cc + oat_writer.cc \ + profile_assistant.cc LIBART_COMPILER_SRC_FILES_arm := \ dex/quick/arm/assemble_arm.cc \ diff --git a/profman/profile_assistant.cc b/compiler/profile_assistant.cc index 58e8a3a7d1..85335efcc4 100644 --- a/profman/profile_assistant.cc +++ b/compiler/profile_assistant.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2015 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. @@ -24,10 +24,13 @@ namespace art { // Minimum number of new methods that profiles must contain to enable recompilation. static constexpr const uint32_t kMinNewMethodsForCompilation = 10; -ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal( +bool ProfileAssistant::ProcessProfilesInternal( const std::vector<ScopedFlock>& profile_files, - const ScopedFlock& reference_profile_file) { + const std::vector<ScopedFlock>& reference_profile_files, + /*out*/ ProfileCompilationInfo** profile_compilation_info) { DCHECK(!profile_files.empty()); + DCHECK(!reference_profile_files.empty() || + (profile_files.size() == reference_profile_files.size())); std::vector<ProfileCompilationInfo> new_info(profile_files.size()); bool should_compile = false; @@ -35,53 +38,51 @@ ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal( for (size_t i = 0; i < new_info.size(); i++) { if (!new_info[i].Load(profile_files[i].GetFile()->Fd())) { LOG(WARNING) << "Could not load profile file at index " << i; - return kErrorBadProfiles; + return false; } // Do we have enough new profiled methods that will make the compilation worthwhile? should_compile |= (new_info[i].GetNumberOfMethods() > kMinNewMethodsForCompilation); } if (!should_compile) { - return kSkipCompilation; + return true; } + std::unique_ptr<ProfileCompilationInfo> result(new ProfileCompilationInfo()); // Merge information. - ProfileCompilationInfo info; - if (!info.Load(reference_profile_file.GetFile()->Fd())) { - LOG(WARNING) << "Could not load reference profile file"; - return kErrorBadProfiles; - } - for (size_t i = 0; i < new_info.size(); i++) { + if (!reference_profile_files.empty()) { + if (!new_info[i].Load(reference_profile_files[i].GetFile()->Fd())) { + LOG(WARNING) << "Could not load reference profile file at index " << i; + return false; + } + } // Merge all data into a single object. - if (!info.Load(new_info[i])) { + if (!result->Load(new_info[i])) { LOG(WARNING) << "Could not merge profile data at index " << i; - return kErrorBadProfiles; + return false; } } - // We were successful in merging all profile information. Update the reference profile. - if (!reference_profile_file.GetFile()->ClearContent()) { - PLOG(WARNING) << "Could not clear reference profile file"; - return kErrorIO; - } - if (!info.Save(reference_profile_file.GetFile()->Fd())) { - LOG(WARNING) << "Could not save reference profile file"; - return kErrorIO; + // We were successful in merging all profile information. Update the files. + for (size_t i = 0; i < new_info.size(); i++) { + if (!reference_profile_files.empty()) { + if (!reference_profile_files[i].GetFile()->ClearContent()) { + PLOG(WARNING) << "Could not clear reference profile file at index " << i; + return false; + } + if (!new_info[i].Save(reference_profile_files[i].GetFile()->Fd())) { + LOG(WARNING) << "Could not save reference profile file at index " << i; + return false; + } + if (!profile_files[i].GetFile()->ClearContent()) { + PLOG(WARNING) << "Could not clear profile file at index " << i; + return false; + } + } } - return kCompile; -} - -static bool InitFlock(const std::string& filename, ScopedFlock& flock, std::string* error) { - return flock.Init(filename.c_str(), O_RDWR, /* block */ true, error); -} - -static bool InitFlock(int fd, ScopedFlock& flock, std::string* error) { - DCHECK_GE(fd, 0); - // We do not own the descriptor, so disable auto-close and don't check usage. - File file(fd, false); - file.DisableAutoClose(); - return flock.Init(&file, error); + *profile_compilation_info = result.release(); + return true; } class ScopedCollectionFlock { @@ -91,7 +92,7 @@ class ScopedCollectionFlock { // Will block until all the locks are acquired. bool Init(const std::vector<std::string>& filenames, /* out */ std::string* error) { for (size_t i = 0; i < filenames.size(); i++) { - if (!InitFlock(filenames[i], flocks_[i], error)) { + if (!flocks_[i].Init(filenames[i].c_str(), O_RDWR, /* block */ true, error)) { *error += " (index=" + std::to_string(i) + ")"; return false; } @@ -100,10 +101,12 @@ class ScopedCollectionFlock { } // Will block until all the locks are acquired. - bool Init(const std::vector<int>& fds, /* out */ std::string* error) { + bool Init(const std::vector<uint32_t>& fds, /* out */ std::string* error) { for (size_t i = 0; i < fds.size(); i++) { - DCHECK_GE(fds[i], 0); - if (!InitFlock(fds[i], flocks_[i], error)) { + // We do not own the descriptor, so disable auto-close and don't check usage. + File file(fds[i], false); + file.DisableAutoClose(); + if (!flocks_[i].Init(&file, error)) { *error += " (index=" + std::to_string(i) + ")"; return false; } @@ -117,43 +120,50 @@ class ScopedCollectionFlock { std::vector<ScopedFlock> flocks_; }; -ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( - const std::vector<int>& profile_files_fd, - int reference_profile_file_fd) { - DCHECK_GE(reference_profile_file_fd, 0); +bool ProfileAssistant::ProcessProfiles( + const std::vector<uint32_t>& profile_files_fd, + const std::vector<uint32_t>& reference_profile_files_fd, + /*out*/ ProfileCompilationInfo** profile_compilation_info) { + *profile_compilation_info = nullptr; + std::string error; ScopedCollectionFlock profile_files_flocks(profile_files_fd.size()); if (!profile_files_flocks.Init(profile_files_fd, &error)) { LOG(WARNING) << "Could not lock profile files: " << error; - return kErrorCannotLock; + return false; } - ScopedFlock reference_profile_file_flock; - if (!InitFlock(reference_profile_file_fd, reference_profile_file_flock, &error)) { - LOG(WARNING) << "Could not lock reference profiled files: " << error; - return kErrorCannotLock; + ScopedCollectionFlock reference_profile_files_flocks(reference_profile_files_fd.size()); + if (!reference_profile_files_flocks.Init(reference_profile_files_fd, &error)) { + LOG(WARNING) << "Could not lock reference profile files: " << error; + return false; } return ProcessProfilesInternal(profile_files_flocks.Get(), - reference_profile_file_flock); + reference_profile_files_flocks.Get(), + profile_compilation_info); } -ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( +bool ProfileAssistant::ProcessProfiles( const std::vector<std::string>& profile_files, - const std::string& reference_profile_file) { + const std::vector<std::string>& reference_profile_files, + /*out*/ ProfileCompilationInfo** profile_compilation_info) { + *profile_compilation_info = nullptr; + std::string error; ScopedCollectionFlock profile_files_flocks(profile_files.size()); if (!profile_files_flocks.Init(profile_files, &error)) { LOG(WARNING) << "Could not lock profile files: " << error; - return kErrorCannotLock; + return false; } - ScopedFlock reference_profile_file_flock; - if (!InitFlock(reference_profile_file, reference_profile_file_flock, &error)) { + ScopedCollectionFlock reference_profile_files_flocks(reference_profile_files.size()); + if (!reference_profile_files_flocks.Init(reference_profile_files, &error)) { LOG(WARNING) << "Could not lock reference profile files: " << error; - return kErrorCannotLock; + return false; } return ProcessProfilesInternal(profile_files_flocks.Get(), - reference_profile_file_flock); + reference_profile_files_flocks.Get(), + profile_compilation_info); } } // namespace art diff --git a/compiler/profile_assistant.h b/compiler/profile_assistant.h new file mode 100644 index 0000000000..ad5e2163cf --- /dev/null +++ b/compiler/profile_assistant.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 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_COMPILER_PROFILE_ASSISTANT_H_ +#define ART_COMPILER_PROFILE_ASSISTANT_H_ + +#include <string> +#include <vector> + +#include "base/scoped_flock.h" +#include "jit/offline_profiling_info.cc" + +namespace art { + +class ProfileAssistant { + public: + // Process the profile information present in the given files. Returns true + // if the analysis ended up successfully (i.e. no errors during reading, + // merging or writing of profile files). + // + // If the returned value is true and there is a significant difference between + // profile_files and reference_profile_files: + // - profile_compilation_info is set to a not null object that + // can be used to drive compilation. It will be the merge of all the data + // found in profile_files and reference_profile_files. + // - the data from profile_files[i] is merged into + // reference_profile_files[i] and the corresponding backing file is + // updated. + // + // If the returned value is false or the difference is insignificant, + // profile_compilation_info will be set to null. + // + // Additional notes: + // - as mentioned above, this function may update the content of the files + // passed with the reference_profile_files. + // - if reference_profile_files is not empty it must be the same size as + // profile_files. + static bool ProcessProfiles( + const std::vector<std::string>& profile_files, + const std::vector<std::string>& reference_profile_files, + /*out*/ ProfileCompilationInfo** profile_compilation_info); + + static bool ProcessProfiles( + const std::vector<uint32_t>& profile_files_fd_, + const std::vector<uint32_t>& reference_profile_files_fd_, + /*out*/ ProfileCompilationInfo** profile_compilation_info); + + private: + static bool ProcessProfilesInternal( + const std::vector<ScopedFlock>& profile_files, + const std::vector<ScopedFlock>& reference_profile_files, + /*out*/ ProfileCompilationInfo** profile_compilation_info); + + DISALLOW_COPY_AND_ASSIGN(ProfileAssistant); +}; + +} // namespace art + +#endif // ART_COMPILER_PROFILE_ASSISTANT_H_ diff --git a/profman/profile_assistant_test.cc b/compiler/profile_assistant_test.cc index 543be5d181..58b7513377 100644 --- a/profman/profile_assistant_test.cc +++ b/compiler/profile_assistant_test.cc @@ -18,9 +18,8 @@ #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" -#include "profile_assistant.h" +#include "compiler/profile_assistant.h" #include "jit/offline_profiling_info.h" -#include "utils.h" namespace art { @@ -45,51 +44,23 @@ class ProfileAssistantTest : public CommonRuntimeTest { ASSERT_TRUE(profile.GetFile()->ResetOffset()); } - int GetFd(const ScratchFile& file) const { - return static_cast<int>(file.GetFd()); - } - - void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) { - ProfileCompilationInfo file_info; - ASSERT_TRUE(file.GetFile()->ResetOffset()); - ASSERT_TRUE(file_info.Load(GetFd(file))); - ASSERT_TRUE(file_info.Equals(info)); - } - - // Runs test with given arguments. - int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) { - std::string file_path = GetTestAndroidRoot(); - if (IsHost()) { - file_path += "/bin/profman"; - } else { - file_path += "/xbin/profman"; - } - if (kIsDebugBuild) { - file_path += "d"; - } - - EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path"; - std::vector<std::string> argv_str; - argv_str.push_back(file_path); - for (size_t k = 0; k < profiles_fd.size(); k++) { - argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k])); - } - argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd)); - - std::string error; - return ExecAndReturnCode(argv_str, &error); + uint32_t GetFd(const ScratchFile& file) const { + return static_cast<uint32_t>(file.GetFd()); } }; TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) { ScratchFile profile1; ScratchFile profile2; - ScratchFile reference_profile; + ScratchFile reference_profile1; + ScratchFile reference_profile2; - std::vector<int> profile_fds({ + std::vector<uint32_t> profile_fds({ GetFd(profile1), GetFd(profile2)}); - int reference_profile_fd = GetFd(reference_profile); + std::vector<uint32_t> reference_profile_fds({ + GetFd(reference_profile1), + GetFd(reference_profile2)}); const uint16_t kNumberOfMethodsToEnableCompilation = 100; ProfileCompilationInfo info1; @@ -98,32 +69,44 @@ TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) { SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, profile2, &info2); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - ProcessProfiles(profile_fds, reference_profile_fd)); - // The resulting compilation info must be equal to the merge of the inputs. - ProfileCompilationInfo result; - ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); - ASSERT_TRUE(result.Load(reference_profile_fd)); + ProfileCompilationInfo* result; + ASSERT_TRUE(ProfileAssistant::ProcessProfiles(profile_fds, reference_profile_fds, &result)); + ASSERT_TRUE(result != nullptr); + // The resulting compilation info must be equal to the merge of the inputs. ProfileCompilationInfo expected; ASSERT_TRUE(expected.Load(info1)); ASSERT_TRUE(expected.Load(info2)); - ASSERT_TRUE(expected.Equals(result)); + ASSERT_TRUE(expected.Equals(*result)); - // The information from profiles must remain the same. - CheckProfileInfo(profile1, info1); - CheckProfileInfo(profile2, info2); + // The information from profiles must be transfered to the reference profiles. + ProfileCompilationInfo file_info1; + ASSERT_TRUE(reference_profile1.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info1.Load(GetFd(reference_profile1))); + ASSERT_TRUE(file_info1.Equals(info1)); + + ProfileCompilationInfo file_info2; + ASSERT_TRUE(reference_profile2.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info2.Load(GetFd(reference_profile2))); + ASSERT_TRUE(file_info2.Equals(info2)); + + // Initial profiles must be cleared. + ASSERT_EQ(0, profile1.GetFile()->GetLength()); + ASSERT_EQ(0, profile2.GetFile()->GetLength()); } TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) { ScratchFile profile1; ScratchFile profile2; - ScratchFile reference_profile; + ScratchFile reference_profile1; + ScratchFile reference_profile2; - std::vector<int> profile_fds({ + std::vector<uint32_t> profile_fds({ GetFd(profile1), GetFd(profile2)}); - int reference_profile_fd = GetFd(reference_profile); + std::vector<uint32_t> reference_profile_fds({ + GetFd(reference_profile1), + GetFd(reference_profile2)}); // The new profile info will contain the methods with indices 0-100. const uint16_t kNumberOfMethodsToEnableCompilation = 100; @@ -135,39 +118,60 @@ TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) { // The reference profile info will contain the methods with indices 50-150. const uint16_t kNumberOfMethodsAlreadyCompiled = 100; - ProfileCompilationInfo reference_info; - SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, reference_profile, - &reference_info, kNumberOfMethodsToEnableCompilation / 2); + ProfileCompilationInfo reference_info1; + SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, reference_profile1, + &reference_info1, kNumberOfMethodsToEnableCompilation / 2); + ProfileCompilationInfo reference_info2; + SetupProfile("p2", 2, kNumberOfMethodsAlreadyCompiled, reference_profile2, + &reference_info2, kNumberOfMethodsToEnableCompilation / 2); // We should advise compilation. - ASSERT_EQ(ProfileAssistant::kCompile, - ProcessProfiles(profile_fds, reference_profile_fd)); + ProfileCompilationInfo* result; + ASSERT_TRUE(ProfileAssistant::ProcessProfiles(profile_fds, reference_profile_fds, &result)); + ASSERT_TRUE(result != nullptr); // The resulting compilation info must be equal to the merge of the inputs - ProfileCompilationInfo result; - ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); - ASSERT_TRUE(result.Load(reference_profile_fd)); - ProfileCompilationInfo expected; ASSERT_TRUE(expected.Load(info1)); ASSERT_TRUE(expected.Load(info2)); - ASSERT_TRUE(expected.Load(reference_info)); - ASSERT_TRUE(expected.Equals(result)); + ASSERT_TRUE(expected.Load(reference_info1)); + ASSERT_TRUE(expected.Load(reference_info2)); + ASSERT_TRUE(expected.Equals(*result)); - // The information from profiles must remain the same. - CheckProfileInfo(profile1, info1); - CheckProfileInfo(profile2, info2); + // The information from profiles must be transfered to the reference profiles. + ProfileCompilationInfo file_info1; + ProfileCompilationInfo merge1; + ASSERT_TRUE(merge1.Load(info1)); + ASSERT_TRUE(merge1.Load(reference_info1)); + ASSERT_TRUE(reference_profile1.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info1.Load(GetFd(reference_profile1))); + ASSERT_TRUE(file_info1.Equals(merge1)); + + ProfileCompilationInfo file_info2; + ProfileCompilationInfo merge2; + ASSERT_TRUE(merge2.Load(info2)); + ASSERT_TRUE(merge2.Load(reference_info2)); + ASSERT_TRUE(reference_profile2.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info2.Load(GetFd(reference_profile2))); + ASSERT_TRUE(file_info2.Equals(merge2)); + + // Initial profiles must be cleared. + ASSERT_EQ(0, profile1.GetFile()->GetLength()); + ASSERT_EQ(0, profile2.GetFile()->GetLength()); } TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) { ScratchFile profile1; ScratchFile profile2; - ScratchFile reference_profile; + ScratchFile reference_profile1; + ScratchFile reference_profile2; - std::vector<int> profile_fds({ + std::vector<uint32_t> profile_fds({ GetFd(profile1), GetFd(profile2)}); - int reference_profile_fd = GetFd(reference_profile); + std::vector<uint32_t> reference_profile_fds({ + GetFd(reference_profile1), + GetFd(reference_profile2)}); const uint16_t kNumberOfMethodsToSkipCompilation = 1; ProfileCompilationInfo info1; @@ -176,8 +180,9 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) { SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, profile2, &info2); // We should not advise compilation. - ASSERT_EQ(ProfileAssistant::kSkipCompilation, - ProcessProfiles(profile_fds, reference_profile_fd)); + ProfileCompilationInfo* result = nullptr; + ASSERT_TRUE(ProfileAssistant::ProcessProfiles(profile_fds, reference_profile_fds, &result)); + ASSERT_TRUE(result == nullptr); // The information from profiles must remain the same. ProfileCompilationInfo file_info1; @@ -191,22 +196,22 @@ TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) { ASSERT_TRUE(file_info2.Equals(info2)); // Reference profile files must remain empty. - ASSERT_EQ(0, reference_profile.GetFile()->GetLength()); - - // The information from profiles must remain the same. - CheckProfileInfo(profile1, info1); - CheckProfileInfo(profile2, info2); + ASSERT_EQ(0, reference_profile1.GetFile()->GetLength()); + ASSERT_EQ(0, reference_profile2.GetFile()->GetLength()); } TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) { ScratchFile profile1; ScratchFile profile2; - ScratchFile reference_profile; + ScratchFile reference_profile1; + ScratchFile reference_profile2; - std::vector<int> profile_fds({ + std::vector<uint32_t> profile_fds({ GetFd(profile1), GetFd(profile2)}); - int reference_profile_fd = GetFd(reference_profile); + std::vector<uint32_t> reference_profile_fds({ + GetFd(reference_profile1), + GetFd(reference_profile2)}); const uint16_t kNumberOfMethodsToEnableCompilation = 100; // Assign different hashes for the same dex file. This will make merging of information to fail. @@ -216,24 +221,34 @@ TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) { SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, profile2, &info2); // We should fail processing. - ASSERT_EQ(ProfileAssistant::kErrorBadProfiles, - ProcessProfiles(profile_fds, reference_profile_fd)); + ProfileCompilationInfo* result = nullptr; + ASSERT_FALSE(ProfileAssistant::ProcessProfiles(profile_fds, reference_profile_fds, &result)); + ASSERT_TRUE(result == nullptr); - // The information from profiles must remain the same. - CheckProfileInfo(profile1, info1); - CheckProfileInfo(profile2, info2); + // The information from profiles must still remain the same. + ProfileCompilationInfo file_info1; + ASSERT_TRUE(profile1.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info1.Load(GetFd(profile1))); + ASSERT_TRUE(file_info1.Equals(info1)); + + ProfileCompilationInfo file_info2; + ASSERT_TRUE(profile2.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info2.Load(GetFd(profile2))); + ASSERT_TRUE(file_info2.Equals(info2)); // Reference profile files must still remain empty. - ASSERT_EQ(0, reference_profile.GetFile()->GetLength()); + ASSERT_EQ(0, reference_profile1.GetFile()->GetLength()); + ASSERT_EQ(0, reference_profile2.GetFile()->GetLength()); } TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) { ScratchFile profile1; ScratchFile reference_profile; - std::vector<int> profile_fds({ + std::vector<uint32_t> profile_fds({ GetFd(profile1)}); - int reference_profile_fd = GetFd(reference_profile); + std::vector<uint32_t> reference_profile_fds({ + GetFd(reference_profile)}); const uint16_t kNumberOfMethodsToEnableCompilation = 100; // Assign different hashes for the same dex file. This will make merging of information to fail. @@ -243,13 +258,22 @@ TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) { SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, reference_profile, &reference_info); // We should not advise compilation. + ProfileCompilationInfo* result = nullptr; ASSERT_TRUE(profile1.GetFile()->ResetOffset()); ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); - ASSERT_EQ(ProfileAssistant::kErrorBadProfiles, - ProcessProfiles(profile_fds, reference_profile_fd)); + ASSERT_FALSE(ProfileAssistant::ProcessProfiles(profile_fds, reference_profile_fds, &result)); + ASSERT_TRUE(result == nullptr); - // The information from profiles must remain the same. - CheckProfileInfo(profile1, info1); + // The information from profiles must still remain the same. + ProfileCompilationInfo file_info1; + ASSERT_TRUE(profile1.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info1.Load(GetFd(profile1))); + ASSERT_TRUE(file_info1.Equals(info1)); + + ProfileCompilationInfo file_info2; + ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); + ASSERT_TRUE(file_info2.Load(GetFd(reference_profile))); + ASSERT_TRUE(file_info2.Equals(reference_info)); } } // namespace art diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index f7efdc5bac..541fb5a423 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -40,7 +40,6 @@ #include "art_method-inl.h" #include "base/dumpable.h" #include "base/macros.h" -#include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/stringpiece.h" #include "base/time_utils.h" @@ -72,6 +71,7 @@ #include "mirror/object_array-inl.h" #include "oat_writer.h" #include "os.h" +#include "profile_assistant.h" #include "runtime.h" #include "runtime_options.h" #include "ScopedLocalRef.h" @@ -339,10 +339,23 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" Example: --runtime-arg -Xms256m"); 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(""); + UsageError(" --reference-profile-file=<filename>: specify a reference profile file to use when"); + UsageError(" compiling. The data in this file will be compared with the data in the"); + UsageError(" associated --profile-file and the compilation will proceed only if there is"); + UsageError(" a significant difference (--reference-profile-file is paired with"); + UsageError(" --profile-file in the natural order). If the compilation was attempted then"); + UsageError(" --profile-file will be merged into --reference-profile-file. Valid only when"); + UsageError(" specified together with --profile-file."); UsageError(""); UsageError(" --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor."); UsageError(" Cannot be used together with --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"); + UsageError(" --reference-profile-file."); UsageError(" --print-pass-names: print a list of pass names"); UsageError(""); UsageError(" --disable-passes=<pass-names>: disable one or more passes separated by comma."); @@ -504,6 +517,14 @@ static bool UseSwap(bool is_image, std::vector<const DexFile*>& dex_files) { return dex_files_size >= kMinDexFileCumulativeSizeForSwap; } +static void CloseAllFds(const std::vector<uint32_t>& fds, const char* descriptor) { + for (size_t i = 0; i < fds.size(); i++) { + if (close(fds[i]) < 0) { + PLOG(WARNING) << "Failed to close descriptor for " << descriptor << " at index " << i; + } + } +} + class Dex2Oat FINAL { public: explicit Dex2Oat(TimingLogger* timings) : @@ -546,12 +567,10 @@ class Dex2Oat FINAL { dump_passes_(false), dump_timing_(false), dump_slow_timing_(kIsDebugBuild), - swap_fd_(kInvalidFd), + swap_fd_(-1), app_image_fd_(kInvalidFd), - profile_file_fd_(kInvalidFd), timings_(timings), - force_determinism_(false) - {} + force_determinism_(false) {} ~Dex2Oat() { // Log completion time before deleting the runtime_, because this accesses @@ -805,8 +824,25 @@ class Dex2Oat FINAL { } } - if (!profile_file_.empty() && (profile_file_fd_ != kInvalidFd)) { - Usage("Profile file should not be specified with both --profile-file-fd and --profile-file"); + if (!profile_files_.empty() && !profile_files_fd_.empty()) { + Usage("Profile files should not be specified with both --profile-file-fd and --profile-file"); + } + if (!profile_files_.empty()) { + if (!reference_profile_files_.empty() && + (reference_profile_files_.size() != profile_files_.size())) { + Usage("If specified, --reference-profile-file should match the number of --profile-file."); + } + } else if (!reference_profile_files_.empty()) { + Usage("--reference-profile-file should only be supplied with --profile-file"); + } + if (!profile_files_fd_.empty()) { + if (!reference_profile_files_fd_.empty() && + (reference_profile_files_fd_.size() != profile_files_fd_.size())) { + Usage("If specified, --reference-profile-file-fd should match the number", + " of --profile-file-fd."); + } + } else if (!reference_profile_files_fd_.empty()) { + Usage("--reference-profile-file-fd should only be supplied with --profile-file-fd"); } if (!parser_options->oat_symbols.empty()) { @@ -1117,9 +1153,16 @@ class Dex2Oat FINAL { } else if (option.starts_with("--compiler-backend=")) { ParseCompilerBackend(option, parser_options.get()); } else if (option.starts_with("--profile-file=")) { - profile_file_ = option.substr(strlen("--profile-file=")).ToString(); + profile_files_.push_back(option.substr(strlen("--profile-file=")).ToString()); + } else if (option.starts_with("--reference-profile-file=")) { + reference_profile_files_.push_back( + option.substr(strlen("--reference-profile-file=")).ToString()); } else if (option.starts_with("--profile-file-fd=")) { - ParseUintOption(option, "--profile-file-fd", &profile_file_fd_, Usage); + ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_); + } else if (option.starts_with("--reference-profile-file-fd=")) { + ParseFdForCollection(option, "--reference_profile-file-fd", &reference_profile_files_fd_); + } else if (option == "--no-profile-file") { + // No profile } else if (option == "--host") { is_host_ = true; } else if (option == "--runtime-arg") { @@ -1822,44 +1865,33 @@ class Dex2Oat FINAL { } bool UseProfileGuidedCompilation() const { - return !profile_file_.empty() || (profile_file_fd_ != kInvalidFd); + return !profile_files_.empty() || !profile_files_fd_.empty(); } - bool LoadProfile() { + bool ProcessProfiles() { DCHECK(UseProfileGuidedCompilation()); - - profile_compilation_info_.reset(new ProfileCompilationInfo()); - ScopedFlock flock; - bool success = false; - std::string error; - if (profile_file_fd_ != -1) { - // The file doesn't need to be flushed so don't check the usage. - // Pass a bogus path so that we can easily attribute any reported error. - File file(profile_file_fd_, "profile", /*check_usage*/ false, /*read_only_mode*/ true); - if (flock.Init(&file, &error)) { - success = profile_compilation_info_->Load(profile_file_fd_); - } + ProfileCompilationInfo* info = nullptr; + bool result = false; + if (profile_files_.empty()) { + DCHECK(!profile_files_fd_.empty()); + result = ProfileAssistant::ProcessProfiles( + profile_files_fd_, reference_profile_files_fd_, &info); + CloseAllFds(profile_files_fd_, "profile_files_fd_"); + CloseAllFds(reference_profile_files_fd_, "reference_profile_files_fd_"); } else { - if (flock.Init(profile_file_.c_str(), O_RDONLY, /* block */ true, &error)) { - success = profile_compilation_info_->Load(flock.GetFile()->Fd()); - } - } - if (!error.empty()) { - LOG(WARNING) << "Cannot lock profiles: " << error; + result = ProfileAssistant::ProcessProfiles( + profile_files_, reference_profile_files_, &info); } - if (!success) { - profile_compilation_info_.reset(nullptr); - } + profile_compilation_info_.reset(info); - return success; + return result; } bool ShouldCompileBasedOnProfiles() const { DCHECK(UseProfileGuidedCompilation()); - // If we are given a profile, compile only if we have some data in it. - return (profile_compilation_info_ != nullptr) && - (profile_compilation_info_->GetNumberOfMethods() != 0); + // If we are given profiles, compile only if we have new information. + return profile_compilation_info_ != nullptr; } private: @@ -2428,8 +2460,10 @@ class Dex2Oat FINAL { int swap_fd_; std::string app_image_file_name_; int app_image_fd_; - std::string profile_file_; - int profile_file_fd_; + std::vector<std::string> profile_files_; + std::vector<std::string> reference_profile_files_; + std::vector<uint32_t> profile_files_fd_; + std::vector<uint32_t> reference_profile_files_fd_; std::unique_ptr<ProfileCompilationInfo> profile_compilation_info_; TimingLogger* timings_; std::unique_ptr<CumulativeLogger> compiler_phases_timings_; @@ -2558,7 +2592,7 @@ static int dex2oat(int argc, char** argv) { // Process profile information and assess if we need to do a profile guided compilation. // This operation involves I/O. if (dex2oat.UseProfileGuidedCompilation()) { - if (dex2oat.LoadProfile()) { + if (dex2oat.ProcessProfiles()) { if (!dex2oat.ShouldCompileBasedOnProfiles()) { LOG(INFO) << "Skipped compilation because of insignificant profile delta"; return EXIT_SUCCESS; diff --git a/profman/Android.mk b/profman/Android.mk deleted file mode 100644 index d38d107d21..0000000000 --- a/profman/Android.mk +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (C) 2016 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. -# - -LOCAL_PATH := $(call my-dir) - -include art/build/Android.executable.mk - -PROFMAN_SRC_FILES := \ - profman.cc \ - profile_assistant.cc - -# TODO: Remove this when the framework (installd) supports pushing the -# right instruction-set parameter for the primary architecture. -ifneq ($(filter ro.zygote=zygote64,$(PRODUCT_DEFAULT_PROPERTY_OVERRIDES)),) - profman_arch := 64 -else - profman_arch := 32 -endif - -ifeq ($(ART_BUILD_TARGET_NDEBUG),true) - $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,target,ndebug,$(profman_arch))) -endif -ifeq ($(ART_BUILD_TARGET_DEBUG),true) - $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,target,debug,$(profman_arch))) -endif - -ifeq ($(ART_BUILD_HOST_NDEBUG),true) - $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,host,ndebug)) -endif -ifeq ($(ART_BUILD_HOST_DEBUG),true) - $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,host,debug)) -endif diff --git a/profman/profile_assistant.h b/profman/profile_assistant.h deleted file mode 100644 index d3c75b817a..0000000000 --- a/profman/profile_assistant.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2016 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_PROFILE_ASSISTANT_H_ -#define ART_PROFMAN_PROFILE_ASSISTANT_H_ - -#include <string> -#include <vector> - -#include "base/scoped_flock.h" -#include "jit/offline_profiling_info.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 { - kCompile = 0, - kSkipCompilation = 1, - kErrorBadProfiles = 2, - kErrorIO = 3, - kErrorCannotLock = 4 - }; - - // Process the profile information present in the given files. Returns one of - // ProcessingResult values depending on profile information and whether or not - // the analysis ended up successfully (i.e. no errors during reading, - // merging or writing of profile files). - // - // When the returned value is kCompile there is a significant difference - // between profile_files and reference_profile_files. In this case - // reference_profile will be updated with the profiling info obtain after - // merging all profiles. - // - // When the returned value is kSkipCompilation, the difference between the - // merge of the current profiles and the reference one is insignificant. In - // this case no file will be updated. - // - static ProcessingResult ProcessProfiles( - const std::vector<std::string>& profile_files, - const std::string& reference_profile_file); - - static ProcessingResult ProcessProfiles( - const std::vector<int>& profile_files_fd_, - int reference_profile_file_fd); - - private: - static ProcessingResult ProcessProfilesInternal( - const std::vector<ScopedFlock>& profile_files, - const ScopedFlock& reference_profile_file); - - DISALLOW_COPY_AND_ASSIGN(ProfileAssistant); -}; - -} // namespace art - -#endif // ART_PROFMAN_PROFILE_ASSISTANT_H_ diff --git a/profman/profman.cc b/profman/profman.cc deleted file mode 100644 index 7c9e449ed5..0000000000 --- a/profman/profman.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2016 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 <stdio.h> -#include <stdlib.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <string> -#include <vector> - -#include "base/dumpable.h" -#include "base/scoped_flock.h" -#include "base/stringpiece.h" -#include "base/stringprintf.h" -#include "base/time_utils.h" -#include "base/unix_file/fd_file.h" -#include "jit/offline_profiling_info.h" -#include "utils.h" -#include "profile_assistant.h" - -namespace art { - -static int original_argc; -static char** original_argv; - -static std::string CommandLine() { - std::vector<std::string> command; - for (int i = 0; i < original_argc; ++i) { - command.push_back(original_argv[i]); - } - return Join(command, ' '); -} - -static void UsageErrorV(const char* fmt, va_list ap) { - std::string error; - StringAppendV(&error, fmt, ap); - LOG(ERROR) << error; -} - -static void UsageError(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - UsageErrorV(fmt, ap); - va_end(ap); -} - -NO_RETURN static void Usage(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - UsageErrorV(fmt, ap); - va_end(ap); - - UsageError("Command: %s", CommandLine().c_str()); - UsageError("Usage: profman [options]..."); - 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(""); - UsageError(" --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor."); - UsageError(" Cannot be used together with --profile-file."); - UsageError(""); - 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(""); - UsageError(" --reference-profile-file-fd=<number>: same as --reference-profile-file but"); - UsageError(" accepts a file descriptor. Cannot be used together with"); - UsageError(" --reference-profile-file."); - UsageError(""); - - exit(EXIT_FAILURE); -} - -class ProfMan FINAL { - public: - ProfMan() : - reference_profile_file_fd_(-1), - start_ns_(NanoTime()) {} - - ~ProfMan() { - LogCompletionTime(); - } - - void ParseArgs(int argc, char **argv) { - original_argc = argc; - original_argv = argv; - - InitLogging(argv); - - // Skip over the command name. - argv++; - argc--; - - if (argc == 0) { - Usage("No arguments specified"); - } - - for (int i = 0; i < argc; ++i) { - const StringPiece option(argv[i]); - const bool log_options = false; - if (log_options) { - LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i]; - } - if (option.starts_with("--profile-file=")) { - profile_files_.push_back(option.substr(strlen("--profile-file=")).ToString()); - } else if (option.starts_with("--profile-file-fd=")) { - ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_); - } else if (option.starts_with("--reference-profile-file=")) { - reference_profile_file_ = option.substr(strlen("--reference-profile-file=")).ToString(); - } else if (option.starts_with("--reference-profile-file-fd=")) { - ParseUintOption(option, "--reference-profile-file-fd", &reference_profile_file_fd_, Usage); - } else { - Usage("Unknown argument %s", option.data()); - } - } - - if (profile_files_.empty() && profile_files_fd_.empty()) { - Usage("No profile files specified."); - } - if (!profile_files_.empty() && !profile_files_fd_.empty()) { - Usage("Profile files should not be specified with both --profile-file-fd and --profile-file"); - } - if (!reference_profile_file_.empty() && (reference_profile_file_fd_ != -1)) { - Usage("--reference-profile-file-fd should only be supplied with --profile-file-fd"); - } - if (reference_profile_file_.empty() && (reference_profile_file_fd_ == -1)) { - Usage("Reference profile file not specified"); - } - } - - ProfileAssistant::ProcessingResult ProcessProfiles() { - ProfileAssistant::ProcessingResult result; - if (profile_files_.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); - result = ProfileAssistant::ProcessProfiles(profile_files_fd_, reference_profile_file_fd_); - CloseAllFds(profile_files_fd_, "profile_files_fd_"); - } else { - result = ProfileAssistant::ProcessProfiles(profile_files_, reference_profile_file_); - } - return result; - } - - private: - static void ParseFdForCollection(const StringPiece& option, - const char* arg_name, - std::vector<int>* fds) { - int fd; - ParseUintOption(option, arg_name, &fd, Usage); - fds->push_back(fd); - } - - static void CloseAllFds(const std::vector<int>& fds, const char* descriptor) { - for (size_t i = 0; i < fds.size(); i++) { - if (close(fds[i]) < 0) { - PLOG(WARNING) << "Failed to close descriptor for " << descriptor << " at index " << i; - } - } - } - - void LogCompletionTime() { - LOG(INFO) << "profman took " << PrettyDuration(NanoTime() - start_ns_); - } - - std::vector<std::string> profile_files_; - std::vector<int> profile_files_fd_; - std::string reference_profile_file_; - int reference_profile_file_fd_; - uint64_t start_ns_; -}; - -// See ProfileAssistant::ProcessingResult for return codes. -static int profman(int argc, char** argv) { - ProfMan profman; - - // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError. - profman.ParseArgs(argc, argv); - - // Process profile information and assess if we need to do a profile guided compilation. - // This operation involves I/O. - return profman.ProcessProfiles(); -} - -} // namespace art - -int main(int argc, char **argv) { - return art::profman(argc, argv); -} - diff --git a/runtime/base/scoped_flock.cc b/runtime/base/scoped_flock.cc index 0e8031f4f2..814cbd093a 100644 --- a/runtime/base/scoped_flock.cc +++ b/runtime/base/scoped_flock.cc @@ -83,7 +83,7 @@ bool ScopedFlock::Init(const char* filename, int flags, bool block, std::string* } bool ScopedFlock::Init(File* file, std::string* error_msg) { - file_.reset(new File(dup(file->Fd()), file->GetPath(), file->CheckUsage(), file->ReadOnlyMode())); + file_.reset(new File(dup(file->Fd()), true)); if (file_->Fd() == -1) { file_.reset(); *error_msg = StringPrintf("Failed to duplicate open file '%s': %s", @@ -114,13 +114,7 @@ ScopedFlock::~ScopedFlock() { if (file_.get() != nullptr) { int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN)); CHECK_EQ(0, flock_result); - int close_result = -1; - if (file_->ReadOnlyMode()) { - close_result = file_->Close(); - } else { - close_result = file_->FlushCloseOrErase(); - } - if (close_result != 0) { + if (file_->FlushCloseOrErase() != 0) { PLOG(WARNING) << "Could not close scoped file lock file."; } } diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc index 4672948f31..e17bebb4fb 100644 --- a/runtime/base/unix_file/fd_file.cc +++ b/runtime/base/unix_file/fd_file.cc @@ -35,22 +35,18 @@ namespace unix_file { -FdFile::FdFile() - : guard_state_(GuardState::kClosed), fd_(-1), auto_close_(true), read_only_mode_(false) { +FdFile::FdFile() : guard_state_(GuardState::kClosed), fd_(-1), auto_close_(true) { } FdFile::FdFile(int fd, bool check_usage) : guard_state_(check_usage ? GuardState::kBase : GuardState::kNoCheck), - fd_(fd), auto_close_(true), read_only_mode_(false) { + fd_(fd), auto_close_(true) { } FdFile::FdFile(int fd, const std::string& path, bool check_usage) - : FdFile(fd, path, check_usage, false) { -} - -FdFile::FdFile(int fd, const std::string& path, bool check_usage, bool read_only_mode) : guard_state_(check_usage ? GuardState::kBase : GuardState::kNoCheck), - fd_(fd), file_path_(path), auto_close_(true), read_only_mode_(read_only_mode) { + fd_(fd), file_path_(path), auto_close_(true) { + CHECK_NE(0U, path.size()); } FdFile::~FdFile() { @@ -103,7 +99,6 @@ bool FdFile::Open(const std::string& path, int flags) { bool FdFile::Open(const std::string& path, int flags, mode_t mode) { CHECK_EQ(fd_, -1) << path; - read_only_mode_ = (flags & O_RDONLY) != 0; fd_ = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)); if (fd_ == -1) { return false; @@ -141,7 +136,6 @@ int FdFile::Close() { } int FdFile::Flush() { - DCHECK(!read_only_mode_); #ifdef __linux__ int rc = TEMP_FAILURE_RETRY(fdatasync(fd_)); #else @@ -161,7 +155,6 @@ int64_t FdFile::Read(char* buf, int64_t byte_count, int64_t offset) const { } int FdFile::SetLength(int64_t new_length) { - DCHECK(!read_only_mode_); #ifdef __linux__ int rc = TEMP_FAILURE_RETRY(ftruncate64(fd_, new_length)); #else @@ -178,7 +171,6 @@ int64_t FdFile::GetLength() const { } int64_t FdFile::Write(const char* buf, int64_t byte_count, int64_t offset) { - DCHECK(!read_only_mode_); #ifdef __linux__ int rc = TEMP_FAILURE_RETRY(pwrite64(fd_, buf, byte_count, offset)); #else @@ -192,14 +184,6 @@ int FdFile::Fd() const { return fd_; } -bool FdFile::ReadOnlyMode() const { - return read_only_mode_; -} - -bool FdFile::CheckUsage() const { - return guard_state_ != GuardState::kNoCheck; -} - bool FdFile::IsOpened() const { return fd_ >= 0; } @@ -235,7 +219,6 @@ bool FdFile::PreadFully(void* buffer, size_t byte_count, size_t offset) { } bool FdFile::WriteFully(const void* buffer, size_t byte_count) { - DCHECK(!read_only_mode_); const char* ptr = static_cast<const char*>(buffer); moveTo(GuardState::kBase, GuardState::kClosed, "Writing into closed file."); while (byte_count > 0) { @@ -250,7 +233,6 @@ bool FdFile::WriteFully(const void* buffer, size_t byte_count) { } bool FdFile::Copy(FdFile* input_file, int64_t offset, int64_t size) { - DCHECK(!read_only_mode_); off_t off = static_cast<off_t>(offset); off_t sz = static_cast<off_t>(size); if (offset < 0 || static_cast<int64_t>(off) != offset || @@ -297,14 +279,12 @@ bool FdFile::Copy(FdFile* input_file, int64_t offset, int64_t size) { } void FdFile::Erase() { - DCHECK(!read_only_mode_); TEMP_FAILURE_RETRY(SetLength(0)); TEMP_FAILURE_RETRY(Flush()); TEMP_FAILURE_RETRY(Close()); } int FdFile::FlushCloseOrErase() { - DCHECK(!read_only_mode_); int flush_result = TEMP_FAILURE_RETRY(Flush()); if (flush_result != 0) { LOG(::art::ERROR) << "CloseOrErase failed while flushing a file."; @@ -321,7 +301,6 @@ int FdFile::FlushCloseOrErase() { } int FdFile::FlushClose() { - DCHECK(!read_only_mode_); int flush_result = TEMP_FAILURE_RETRY(Flush()); if (flush_result != 0) { LOG(::art::ERROR) << "FlushClose failed while flushing a file."; @@ -338,7 +317,6 @@ void FdFile::MarkUnchecked() { } bool FdFile::ClearContent() { - DCHECK(!read_only_mode_); if (SetLength(0) < 0) { PLOG(art::ERROR) << "Failed to reset the length"; return false; @@ -347,7 +325,6 @@ bool FdFile::ClearContent() { } bool FdFile::ResetOffset() { - DCHECK(!read_only_mode_); off_t rc = TEMP_FAILURE_RETRY(lseek(fd_, 0, SEEK_SET)); if (rc == static_cast<off_t>(-1)) { PLOG(art::ERROR) << "Failed to reset the offset"; diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h index 8040afe9b7..1e2d8af151 100644 --- a/runtime/base/unix_file/fd_file.h +++ b/runtime/base/unix_file/fd_file.h @@ -37,7 +37,6 @@ class FdFile : public RandomAccessFile { // file descriptor. (Use DisableAutoClose to retain ownership.) FdFile(int fd, bool checkUsage); FdFile(int fd, const std::string& path, bool checkUsage); - FdFile(int fd, const std::string& path, bool checkUsage, bool read_only_mode); // Destroys an FdFile, closing the file descriptor if Close hasn't already // been called. (If you care about the return value of Close, call it @@ -69,8 +68,6 @@ class FdFile : public RandomAccessFile { // Bonus API. int Fd() const; - bool ReadOnlyMode() const; - bool CheckUsage() const; bool IsOpened() const; const std::string& GetPath() const { return file_path_; @@ -122,7 +119,6 @@ class FdFile : public RandomAccessFile { int fd_; std::string file_path_; bool auto_close_; - bool read_only_mode_; DISALLOW_COPY_AND_ASSIGN(FdFile); }; diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc index 747b112f57..0aff1f7ec3 100644 --- a/runtime/jit/offline_profiling_info.cc +++ b/runtime/jit/offline_profiling_info.cc @@ -125,8 +125,8 @@ static constexpr const char kLineSeparator = '\n'; * app.apk,131232145,11,23,454,54 * app.apk:classes5.dex,218490184,39,13,49,1 **/ -bool ProfileCompilationInfo::Save(int fd) { - DCHECK_GE(fd, 0); +bool ProfileCompilationInfo::Save(uint32_t fd) { + DCHECK_GE(fd, 0u); // TODO(calin): Profile this and see how much memory it takes. If too much, // write to file directly. std::ostringstream os; @@ -232,8 +232,8 @@ static int GetLineFromBuffer(char* buffer, int n, int start_from, std::string& l return new_line_pos == -1 ? new_line_pos : new_line_pos + 1; } -bool ProfileCompilationInfo::Load(int fd) { - DCHECK_GE(fd, 0); +bool ProfileCompilationInfo::Load(uint32_t fd) { + DCHECK_GE(fd, 0u); std::string current_line; const int kBufferSize = 1024; @@ -343,7 +343,7 @@ std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* return os.str(); } -bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) { +bool ProfileCompilationInfo::Equals(ProfileCompilationInfo& other) { return info_.Equals(other.info_); } diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h index edc591c2eb..c388c4a42f 100644 --- a/runtime/jit/offline_profiling_info.h +++ b/runtime/jit/offline_profiling_info.h @@ -46,11 +46,11 @@ class ProfileCompilationInfo { const std::vector<ArtMethod*>& methods); // Loads profile information from the given file descriptor. - bool Load(int fd); + bool Load(uint32_t fd); // Loads the data from another ProfileCompilationInfo object. bool Load(const ProfileCompilationInfo& info); // Saves the profile data to the given file descriptor. - bool Save(int fd); + bool Save(uint32_t fd); // Returns the number of methods that were profiled. uint32_t GetNumberOfMethods() const; @@ -65,7 +65,8 @@ class ProfileCompilationInfo { bool print_full_dex_location = true) const; // For testing purposes. - bool Equals(const ProfileCompilationInfo& other); + bool Equals(ProfileCompilationInfo& other); + // Exposed for testing purpose. static std::string GetProfileDexFileKey(const std::string& dex_location); private: diff --git a/runtime/utils.cc b/runtime/utils.cc index 13564a6a0f..07f94c0766 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -1392,8 +1392,9 @@ std::string GetSystemImageFilename(const char* location, const InstructionSet is return filename; } -int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg) { +bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { const std::string command_line(Join(arg_vector, ' ')); + CHECK_GE(arg_vector.size(), 1U) << command_line; // Convert the args to char pointers. @@ -1416,6 +1417,7 @@ int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_m setpgid(0, 0); execv(program, &args[0]); + PLOG(ERROR) << "Failed to execv(" << command_line << ")"; // _exit to avoid atexit handlers in child. _exit(1); @@ -1423,32 +1425,23 @@ int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_m if (pid == -1) { *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", command_line.c_str(), strerror(errno)); - return -1; + return false; } // wait for subprocess to finish - int status = -1; + int status; pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); if (got_pid != pid) { *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " "wanted %d, got %d: %s", command_line.c_str(), pid, got_pid, strerror(errno)); - return -1; + return false; } - if (WIFEXITED(status)) { - return WEXITSTATUS(status); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", + command_line.c_str()); + return false; } - return -1; - } -} - -bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { - int status = ExecAndReturnCode(arg_vector, error_msg); - if (status != 0) { - const std::string command_line(Join(arg_vector, ' ')); - *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", - command_line.c_str()); - return false; } return true; } diff --git a/runtime/utils.h b/runtime/utils.h index 36f9abfe7b..c00db11c16 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -287,7 +287,6 @@ std::string GetSystemImageFilename(const char* location, InstructionSet isa); // Wrapper on fork/execv to run a command in a subprocess. bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg); -int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg); // Returns true if the file exists. bool FileExists(const std::string& filename); @@ -344,7 +343,7 @@ static void ParseUintOption(const StringPiece& option, UsageFn Usage, bool is_long_option = true) { std::string option_prefix = option_name + (is_long_option ? "=" : ""); - DCHECK(option.starts_with(option_prefix)) << option << " " << option_prefix; + DCHECK(option.starts_with(option_prefix)); const char* value_string = option.substr(option_prefix.size()).data(); int64_t parsed_integer_value = 0; if (!ParseInt(value_string, &parsed_integer_value)) { |