1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "profile_assistant.h" 18 19 #include "base/unix_file/fd_file.h" 20 #include "os.h" 21 22 namespace art { 23 24 // Minimum number of new methods/classes that profiles 25 // must contain to enable recompilation. 26 static constexpr const uint32_t kMinNewMethodsForCompilation = 100; 27 static constexpr const uint32_t kMinNewMethodsPercentChangeForCompilation = 2; 28 static constexpr const uint32_t kMinNewClassesForCompilation = 50; 29 static constexpr const uint32_t kMinNewClassesPercentChangeForCompilation = 2; 30 31 32 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal( 33 const std::vector<ScopedFlock>& profile_files, 34 const ScopedFlock& reference_profile_file) { 35 DCHECK(!profile_files.empty()); 36 37 ProfileCompilationInfo info; 38 // Load the reference profile. 39 if (!info.Load(reference_profile_file->Fd())) { 40 LOG(WARNING) << "Could not load reference profile file"; 41 return kErrorBadProfiles; 42 } 43 44 // Store the current state of the reference profile before merging with the current profiles. 45 uint32_t number_of_methods = info.GetNumberOfMethods(); 46 uint32_t number_of_classes = info.GetNumberOfResolvedClasses(); 47 48 // Merge all current profiles. 49 for (size_t i = 0; i < profile_files.size(); i++) { 50 ProfileCompilationInfo cur_info; 51 if (!cur_info.Load(profile_files[i]->Fd())) { 52 LOG(WARNING) << "Could not load profile file at index " << i; 53 return kErrorBadProfiles; 54 } 55 if (!info.MergeWith(cur_info)) { 56 LOG(WARNING) << "Could not merge profile file at index " << i; 57 return kErrorBadProfiles; 58 } 59 } 60 61 uint32_t min_change_in_methods_for_compilation = std::max( 62 (kMinNewMethodsPercentChangeForCompilation * number_of_methods) / 100, 63 kMinNewMethodsForCompilation); 64 uint32_t min_change_in_classes_for_compilation = std::max( 65 (kMinNewClassesPercentChangeForCompilation * number_of_classes) / 100, 66 kMinNewClassesForCompilation); 67 // Check if there is enough new information added by the current profiles. 68 if (((info.GetNumberOfMethods() - number_of_methods) < min_change_in_methods_for_compilation) && 69 ((info.GetNumberOfResolvedClasses() - number_of_classes) 70 < min_change_in_classes_for_compilation)) { 71 return kSkipCompilation; 72 } 73 74 // We were successful in merging all profile information. Update the reference profile. 75 if (!reference_profile_file->ClearContent()) { 76 PLOG(WARNING) << "Could not clear reference profile file"; 77 return kErrorIO; 78 } 79 if (!info.Save(reference_profile_file->Fd())) { 80 LOG(WARNING) << "Could not save reference profile file"; 81 return kErrorIO; 82 } 83 84 return kCompile; 85 } 86 87 class ScopedFlockList { 88 public: 89 explicit ScopedFlockList(size_t size) : flocks_(size) {} 90 91 // Will block until all the locks are acquired. 92 bool Init(const std::vector<std::string>& filenames, /* out */ std::string* error) { 93 for (size_t i = 0; i < filenames.size(); i++) { 94 flocks_[i] = LockedFile::Open(filenames[i].c_str(), O_RDWR, /* block */ true, error); 95 if (flocks_[i].get() == nullptr) { 96 *error += " (index=" + std::to_string(i) + ")"; 97 return false; 98 } 99 } 100 return true; 101 } 102 103 // Will block until all the locks are acquired. 104 bool Init(const std::vector<int>& fds, /* out */ std::string* error) { 105 for (size_t i = 0; i < fds.size(); i++) { 106 DCHECK_GE(fds[i], 0); 107 flocks_[i] = LockedFile::DupOf(fds[i], "profile-file", 108 true /* read_only_mode */, error); 109 if (flocks_[i].get() == nullptr) { 110 *error += " (index=" + std::to_string(i) + ")"; 111 return false; 112 } 113 } 114 return true; 115 } 116 117 const std::vector<ScopedFlock>& Get() const { return flocks_; } 118 119 private: 120 std::vector<ScopedFlock> flocks_; 121 }; 122 123 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( 124 const std::vector<int>& profile_files_fd, 125 int reference_profile_file_fd) { 126 DCHECK_GE(reference_profile_file_fd, 0); 127 128 std::string error; 129 ScopedFlockList profile_files(profile_files_fd.size()); 130 if (!profile_files.Init(profile_files_fd, &error)) { 131 LOG(WARNING) << "Could not lock profile files: " << error; 132 return kErrorCannotLock; 133 } 134 135 // The reference_profile_file is opened in read/write mode because it's 136 // cleared after processing. 137 ScopedFlock reference_profile_file = LockedFile::DupOf(reference_profile_file_fd, 138 "reference-profile", 139 false /* read_only_mode */, 140 &error); 141 if (reference_profile_file.get() == nullptr) { 142 LOG(WARNING) << "Could not lock reference profiled files: " << error; 143 return kErrorCannotLock; 144 } 145 146 return ProcessProfilesInternal(profile_files.Get(), reference_profile_file); 147 } 148 149 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles( 150 const std::vector<std::string>& profile_files, 151 const std::string& reference_profile_file) { 152 std::string error; 153 154 ScopedFlockList profile_files_list(profile_files.size()); 155 if (!profile_files_list.Init(profile_files, &error)) { 156 LOG(WARNING) << "Could not lock profile files: " << error; 157 return kErrorCannotLock; 158 } 159 160 ScopedFlock locked_reference_profile_file = LockedFile::Open( 161 reference_profile_file.c_str(), O_RDWR, /* block */ true, &error); 162 if (locked_reference_profile_file.get() == nullptr) { 163 LOG(WARNING) << "Could not lock reference profile files: " << error; 164 return kErrorCannotLock; 165 } 166 167 return ProcessProfilesInternal(profile_files_list.Get(), locked_reference_profile_file); 168 } 169 170 } // namespace art 171