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/os.h"
     20 #include "base/unix_file/fd_file.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         const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn) {
     36   DCHECK(!profile_files.empty());
     37 
     38   ProfileCompilationInfo info;
     39   // Load the reference profile.
     40   if (!info.Load(reference_profile_file->Fd(), /*merge_classes*/ true, filter_fn)) {
     41     LOG(WARNING) << "Could not load reference profile file";
     42     return kErrorBadProfiles;
     43   }
     44 
     45   // Store the current state of the reference profile before merging with the current profiles.
     46   uint32_t number_of_methods = info.GetNumberOfMethods();
     47   uint32_t number_of_classes = info.GetNumberOfResolvedClasses();
     48 
     49   // Merge all current profiles.
     50   for (size_t i = 0; i < profile_files.size(); i++) {
     51     ProfileCompilationInfo cur_info;
     52     if (!cur_info.Load(profile_files[i]->Fd(), /*merge_classes*/ true, filter_fn)) {
     53       LOG(WARNING) << "Could not load profile file at index " << i;
     54       return kErrorBadProfiles;
     55     }
     56     if (!info.MergeWith(cur_info)) {
     57       LOG(WARNING) << "Could not merge profile file at index " << i;
     58       return kErrorBadProfiles;
     59     }
     60   }
     61 
     62   uint32_t min_change_in_methods_for_compilation = std::max(
     63       (kMinNewMethodsPercentChangeForCompilation * number_of_methods) / 100,
     64       kMinNewMethodsForCompilation);
     65   uint32_t min_change_in_classes_for_compilation = std::max(
     66       (kMinNewClassesPercentChangeForCompilation * number_of_classes) / 100,
     67       kMinNewClassesForCompilation);
     68   // Check if there is enough new information added by the current profiles.
     69   if (((info.GetNumberOfMethods() - number_of_methods) < min_change_in_methods_for_compilation) &&
     70       ((info.GetNumberOfResolvedClasses() - number_of_classes)
     71           < min_change_in_classes_for_compilation)) {
     72     return kSkipCompilation;
     73   }
     74 
     75   // We were successful in merging all profile information. Update the reference profile.
     76   if (!reference_profile_file->ClearContent()) {
     77     PLOG(WARNING) << "Could not clear reference profile file";
     78     return kErrorIO;
     79   }
     80   if (!info.Save(reference_profile_file->Fd())) {
     81     LOG(WARNING) << "Could not save reference profile file";
     82     return kErrorIO;
     83   }
     84 
     85   return kCompile;
     86 }
     87 
     88 class ScopedFlockList {
     89  public:
     90   explicit ScopedFlockList(size_t size) : flocks_(size) {}
     91 
     92   // Will block until all the locks are acquired.
     93   bool Init(const std::vector<std::string>& filenames, /* out */ std::string* error) {
     94     for (size_t i = 0; i < filenames.size(); i++) {
     95       flocks_[i] = LockedFile::Open(filenames[i].c_str(), O_RDWR, /* block */ true, error);
     96       if (flocks_[i].get() == nullptr) {
     97         *error += " (index=" + std::to_string(i) + ")";
     98         return false;
     99       }
    100     }
    101     return true;
    102   }
    103 
    104   // Will block until all the locks are acquired.
    105   bool Init(const std::vector<int>& fds, /* out */ std::string* error) {
    106     for (size_t i = 0; i < fds.size(); i++) {
    107       DCHECK_GE(fds[i], 0);
    108       flocks_[i] = LockedFile::DupOf(fds[i], "profile-file",
    109                                      true /* read_only_mode */, error);
    110       if (flocks_[i].get() == nullptr) {
    111         *error += " (index=" + std::to_string(i) + ")";
    112         return false;
    113       }
    114     }
    115     return true;
    116   }
    117 
    118   const std::vector<ScopedFlock>& Get() const { return flocks_; }
    119 
    120  private:
    121   std::vector<ScopedFlock> flocks_;
    122 };
    123 
    124 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles(
    125         const std::vector<int>& profile_files_fd,
    126         int reference_profile_file_fd,
    127         const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn) {
    128   DCHECK_GE(reference_profile_file_fd, 0);
    129 
    130   std::string error;
    131   ScopedFlockList profile_files(profile_files_fd.size());
    132   if (!profile_files.Init(profile_files_fd, &error)) {
    133     LOG(WARNING) << "Could not lock profile files: " << error;
    134     return kErrorCannotLock;
    135   }
    136 
    137   // The reference_profile_file is opened in read/write mode because it's
    138   // cleared after processing.
    139   ScopedFlock reference_profile_file = LockedFile::DupOf(reference_profile_file_fd,
    140                                                          "reference-profile",
    141                                                          false /* read_only_mode */,
    142                                                          &error);
    143   if (reference_profile_file.get() == nullptr) {
    144     LOG(WARNING) << "Could not lock reference profiled files: " << error;
    145     return kErrorCannotLock;
    146   }
    147 
    148   return ProcessProfilesInternal(profile_files.Get(),
    149                                  reference_profile_file,
    150                                  filter_fn);
    151 }
    152 
    153 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles(
    154         const std::vector<std::string>& profile_files,
    155         const std::string& reference_profile_file,
    156         const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn) {
    157   std::string error;
    158 
    159   ScopedFlockList profile_files_list(profile_files.size());
    160   if (!profile_files_list.Init(profile_files, &error)) {
    161     LOG(WARNING) << "Could not lock profile files: " << error;
    162     return kErrorCannotLock;
    163   }
    164 
    165   ScopedFlock locked_reference_profile_file = LockedFile::Open(
    166       reference_profile_file.c_str(), O_RDWR, /* block */ true, &error);
    167   if (locked_reference_profile_file.get() == nullptr) {
    168     LOG(WARNING) << "Could not lock reference profile files: " << error;
    169     return kErrorCannotLock;
    170   }
    171 
    172   return ProcessProfilesInternal(profile_files_list.Get(),
    173                                  locked_reference_profile_file,
    174                                  filter_fn);
    175 }
    176 
    177 }  // namespace art
    178