/*
 * 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 "profile_assistant.h"

#include "base/os.h"
#include "base/unix_file/fd_file.h"

namespace art {

// Minimum number of new methods/classes that profiles
// must contain to enable recompilation.
static constexpr const uint32_t kMinNewMethodsForCompilation = 100;
static constexpr const uint32_t kMinNewMethodsPercentChangeForCompilation = 2;
static constexpr const uint32_t kMinNewClassesForCompilation = 50;
static constexpr const uint32_t kMinNewClassesPercentChangeForCompilation = 2;


ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal(
        const std::vector<ScopedFlock>& profile_files,
        const ScopedFlock& reference_profile_file,
        const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn,
        const Options& options) {
  DCHECK(!profile_files.empty());

  ProfileCompilationInfo info(options.IsBootImageMerge());

  // Load the reference profile.
  if (!info.Load(reference_profile_file->Fd(), /*merge_classes=*/ true, filter_fn)) {
    LOG(WARNING) << "Could not load reference profile file";
    return kErrorBadProfiles;
  }

  if (options.IsBootImageMerge() && !info.IsForBootImage()) {
    LOG(WARNING) << "Requested merge for boot image profile but the reference profile is regular.";
    return kErrorBadProfiles;
  }

  // Store the current state of the reference profile before merging with the current profiles.
  uint32_t number_of_methods = info.GetNumberOfMethods();
  uint32_t number_of_classes = info.GetNumberOfResolvedClasses();

  // Merge all current profiles.
  for (size_t i = 0; i < profile_files.size(); i++) {
    ProfileCompilationInfo cur_info;
    if (!cur_info.Load(profile_files[i]->Fd(), /*merge_classes=*/ true, filter_fn)) {
      LOG(WARNING) << "Could not load profile file at index " << i;
      return kErrorBadProfiles;
    }

    // Check version mismatch.
    // This may happen during profile analysis if one profile is regular and
    // the other one is for the boot image. For example when switching on-off
    // the boot image profiles.
    if (!info.SameVersion(cur_info)) {
      if (options.IsForceMerge()) {
        // If we have to merge forcefully, ignore the current profile and
        // continue to the next one.
        continue;
      } else {
        // Otherwise, return an error.
        return kErrorDifferentVersions;
      }
    }

    if (!info.MergeWith(cur_info)) {
      LOG(WARNING) << "Could not merge profile file at index " << i;
      return kErrorBadProfiles;
    }
  }

  // If we perform a forced merge do not analyze the difference between profiles.
  if (!options.IsForceMerge()) {
    uint32_t min_change_in_methods_for_compilation = std::max(
        (kMinNewMethodsPercentChangeForCompilation * number_of_methods) / 100,
        kMinNewMethodsForCompilation);
    uint32_t min_change_in_classes_for_compilation = std::max(
        (kMinNewClassesPercentChangeForCompilation * number_of_classes) / 100,
        kMinNewClassesForCompilation);
    // Check if there is enough new information added by the current profiles.
    if (((info.GetNumberOfMethods() - number_of_methods) < min_change_in_methods_for_compilation) &&
        ((info.GetNumberOfResolvedClasses() - number_of_classes)
            < min_change_in_classes_for_compilation)) {
      return kSkipCompilation;
    }
  }

  // We were successful in merging all profile information. Update the reference profile.
  if (!reference_profile_file->ClearContent()) {
    PLOG(WARNING) << "Could not clear reference profile file";
    return kErrorIO;
  }
  if (!info.Save(reference_profile_file->Fd())) {
    LOG(WARNING) << "Could not save reference profile file";
    return kErrorIO;
  }

  return options.IsForceMerge() ? kSuccess : kCompile;
}

class ScopedFlockList {
 public:
  explicit ScopedFlockList(size_t size) : flocks_(size) {}

  // 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++) {
      flocks_[i] = LockedFile::Open(filenames[i].c_str(), O_RDWR, /* block= */ true, error);
      if (flocks_[i].get() == nullptr) {
        *error += " (index=" + std::to_string(i) + ")";
        return false;
      }
    }
    return true;
  }

  // Will block until all the locks are acquired.
  bool Init(const std::vector<int>& fds, /* out */ std::string* error) {
    for (size_t i = 0; i < fds.size(); i++) {
      DCHECK_GE(fds[i], 0);
      flocks_[i] = LockedFile::DupOf(fds[i], "profile-file",
                                     /* read_only_mode= */ true, error);
      if (flocks_[i].get() == nullptr) {
        *error += " (index=" + std::to_string(i) + ")";
        return false;
      }
    }
    return true;
  }

  const std::vector<ScopedFlock>& Get() const { return flocks_; }

 private:
  std::vector<ScopedFlock> flocks_;
};

ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles(
        const std::vector<int>& profile_files_fd,
        int reference_profile_file_fd,
        const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn,
        const Options& options) {
  DCHECK_GE(reference_profile_file_fd, 0);

  std::string error;
  ScopedFlockList profile_files(profile_files_fd.size());
  if (!profile_files.Init(profile_files_fd, &error)) {
    LOG(WARNING) << "Could not lock profile files: " << error;
    return kErrorCannotLock;
  }

  // The reference_profile_file is opened in read/write mode because it's
  // cleared after processing.
  ScopedFlock reference_profile_file = LockedFile::DupOf(reference_profile_file_fd,
                                                         "reference-profile",
                                                         /* read_only_mode= */ false,
                                                         &error);
  if (reference_profile_file.get() == nullptr) {
    LOG(WARNING) << "Could not lock reference profiled files: " << error;
    return kErrorCannotLock;
  }

  return ProcessProfilesInternal(profile_files.Get(),
                                 reference_profile_file,
                                 filter_fn,
                                 options);
}

ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfiles(
        const std::vector<std::string>& profile_files,
        const std::string& reference_profile_file,
        const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn,
        const Options& options) {
  std::string error;

  ScopedFlockList profile_files_list(profile_files.size());
  if (!profile_files_list.Init(profile_files, &error)) {
    LOG(WARNING) << "Could not lock profile files: " << error;
    return kErrorCannotLock;
  }

  ScopedFlock locked_reference_profile_file = LockedFile::Open(
      reference_profile_file.c_str(), O_RDWR, /* block= */ true, &error);
  if (locked_reference_profile_file.get() == nullptr) {
    LOG(WARNING) << "Could not lock reference profile files: " << error;
    return kErrorCannotLock;
  }

  return ProcessProfilesInternal(profile_files_list.Get(),
                                 locked_reference_profile_file,
                                 filter_fn,
                                 options);
}

}  // namespace art
