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 = 10;
     27 static constexpr const uint32_t kMinNewClassesForCompilation = 10;
     28 
     29 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal(
     30         const std::vector<ScopedFlock>& profile_files,
     31         const ScopedFlock& reference_profile_file) {
     32   DCHECK(!profile_files.empty());
     33 
     34   ProfileCompilationInfo info;
     35   // Load the reference profile.
     36   if (!info.Load(reference_profile_file.GetFile()->Fd())) {
     37     LOG(WARNING) << "Could not load reference profile file";
     38     return kErrorBadProfiles;
     39   }
     40 
     41   // Store the current state of the reference profile before merging with the current profiles.
     42   uint32_t number_of_methods = info.GetNumberOfMethods();
     43   uint32_t number_of_classes = info.GetNumberOfResolvedClasses();
     44 
     45   // Merge all current profiles.
     46   for (size_t i = 0; i < profile_files.size(); i++) {
     47     ProfileCompilationInfo cur_info;
     48     if (!cur_info.Load(profile_files[i].GetFile()->Fd())) {
     49       LOG(WARNING) << "Could not load profile file at index " << i;
     50       return kErrorBadProfiles;
     51     }
     52     if (!info.MergeWith(cur_info)) {
     53       LOG(WARNING) << "Could not merge profile file at index " << i;
     54       return kErrorBadProfiles;
     55     }
     56   }
     57 
     58   // Check if there is enough new information added by the current profiles.
     59   if (((info.GetNumberOfMethods() - number_of_methods) < kMinNewMethodsForCompilation) &&
     60       ((info.GetNumberOfResolvedClasses() - number_of_classes) < kMinNewClassesForCompilation)) {
     61     return kSkipCompilation;
     62   }
     63 
     64   // We were successful in merging all profile information. Update the reference profile.
     65   if (!reference_profile_file.GetFile()->ClearContent()) {
     66     PLOG(WARNING) << "Could not clear reference profile file";
     67     return kErrorIO;
     68   }
     69   if (!info.Save(reference_profile_file.GetFile()->Fd())) {
     70     LOG(WARNING) << "Could not save reference profile file";
     71     return kErrorIO;
     72   }
     73 
     74   return kCompile;
     75 }
     76 
     77 static bool InitFlock(const std::string& filename, ScopedFlock& flock, std::string* error) {
     78   return flock.Init(filename.c_str(), O_RDWR, /* block */ true, error);
     79 }
     80 
     81 static bool InitFlock(int fd, ScopedFlock& flock, std::string* error) {
     82   DCHECK_GE(fd, 0);
     83   // We do not own the descriptor, so disable auto-close and don't check usage.
     84   File file(fd, false);
     85   file.DisableAutoClose();
     86   return flock.Init(&file, error);
     87 }
     88 
     89 class ScopedCollectionFlock {
     90  public:
     91   explicit ScopedCollectionFlock(size_t size) : flocks_(size) {}
     92 
     93   // Will block until all the locks are acquired.
     94   bool Init(const std::vector<std::string>& filenames, /* out */ std::string* error) {
     95     for (size_t i = 0; i < filenames.size(); i++) {
     96       if (!InitFlock(filenames[i], flocks_[i], error)) {
     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       if (!InitFlock(fds[i], flocks_[i], error)) {
    109         *error += " (index=" + std::to_string(i) + ")";
    110         return false;
    111       }
    112     }
    113     return true;
    114   }
    115 
    116   const std::vector<ScopedFlock>& Get() const { return flocks_; }
    117 
    118  private:
    119   std::vector<ScopedFlock> flocks_;
    120 };
    121 
    122 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles(
    123         const std::vector<int>& profile_files_fd,
    124         int reference_profile_file_fd) {
    125   DCHECK_GE(reference_profile_file_fd, 0);
    126   std::string error;
    127   ScopedCollectionFlock profile_files_flocks(profile_files_fd.size());
    128   if (!profile_files_flocks.Init(profile_files_fd, &error)) {
    129     LOG(WARNING) << "Could not lock profile files: " << error;
    130     return kErrorCannotLock;
    131   }
    132   ScopedFlock reference_profile_file_flock;
    133   if (!InitFlock(reference_profile_file_fd, reference_profile_file_flock, &error)) {
    134     LOG(WARNING) << "Could not lock reference profiled files: " << error;
    135     return kErrorCannotLock;
    136   }
    137 
    138   return ProcessProfilesInternal(profile_files_flocks.Get(),
    139                                  reference_profile_file_flock);
    140 }
    141 
    142 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles(
    143         const std::vector<std::string>& profile_files,
    144         const std::string& reference_profile_file) {
    145   std::string error;
    146   ScopedCollectionFlock profile_files_flocks(profile_files.size());
    147   if (!profile_files_flocks.Init(profile_files, &error)) {
    148     LOG(WARNING) << "Could not lock profile files: " << error;
    149     return kErrorCannotLock;
    150   }
    151   ScopedFlock reference_profile_file_flock;
    152   if (!InitFlock(reference_profile_file, reference_profile_file_flock, &error)) {
    153     LOG(WARNING) << "Could not lock reference profile files: " << error;
    154     return kErrorCannotLock;
    155   }
    156 
    157   return ProcessProfilesInternal(profile_files_flocks.Get(),
    158                                  reference_profile_file_flock);
    159 }
    160 
    161 }  // namespace art
    162