Home | History | Annotate | Download | only in profman
      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