profile_saver.cc revision e55fda1373abad5ace4409453c51aeb0daaf99ef
14d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle/*
24d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * Copyright (C) 2015 The Android Open Source Project
34d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle *
44d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * Licensed under the Apache License, Version 2.0 (the "License");
54d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * you may not use this file except in compliance with the License.
64d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * You may obtain a copy of the License at
74d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle *
84d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle *      http://www.apache.org/licenses/LICENSE-2.0
94d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle *
104d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * Unless required by applicable law or agreed to in writing, software
114d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * distributed under the License is distributed on an "AS IS" BASIS,
124d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * See the License for the specific language governing permissions and
144d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle * limitations under the License.
154d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle */
164d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
174d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle#include "profile_saver.h"
184d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
1986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle#include <sys/types.h>
2086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle#include <sys/stat.h>
2186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle#include <fcntl.h>
2286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
234d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle#include "art_method-inl.h"
24dabdc0fe183d4684f3cf4d70cb09d318cff81b42Mathieu Chartier#include "base/systrace.h"
256044fa747867413912d0de3049dc570c769d3cf8Calin Juravle#include "base/time_utils.h"
266044fa747867413912d0de3049dc570c769d3cf8Calin Juravle#include "compiler_filter.h"
274d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle#include "oat_file_manager.h"
286044fa747867413912d0de3049dc570c769d3cf8Calin Juravle#include "scoped_thread_state_change.h"
294d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
304d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
316044fa747867413912d0de3049dc570c769d3cf8Calin Juravlenamespace art {
324d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
334d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle// TODO: read the constants from ProfileOptions,
344d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle// Add a random delay each time we go to sleep so that we don't hammer the CPU
354d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle// with all profile savers running at the same time.
3685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlestatic constexpr const uint64_t kRandomDelayMaxMs = 30 * 1000;  // 30 seconds
370cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravlestatic constexpr const uint64_t kMaxBackoffMs = 10 * 60 * 1000;  // 10 minutes
3885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlestatic constexpr const uint64_t kSavePeriodMs = 20 * 1000;  // 20 seconds
39c15e566b36170237f01ccefc12129c1578a02140Calin Juravlestatic constexpr const uint64_t kSaveResolvedClassesDelayMs = 2 * 1000;  // 2 seconds
400cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravlestatic constexpr const double kBackoffCoef = 2.0;
414d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
4285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlestatic constexpr const uint32_t kMinimumNumberOfMethodsToSave = 10;
4385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlestatic constexpr const uint32_t kMinimumNumberOfClassesToSave = 10;
444d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
454d77b6a511659f26fdc711e23825ffa6e7feed7aCalin JuravleProfileSaver* ProfileSaver::instance_ = nullptr;
464d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlepthread_t ProfileSaver::profiler_pthread_ = 0U;
474d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin JuravleProfileSaver::ProfileSaver(const std::string& output_filename,
494d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle                           jit::JitCodeCache* jit_code_cache,
5086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                           const std::vector<std::string>& code_paths,
5186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                           const std::string& foreign_dex_profile_path,
5286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                           const std::string& app_data_dir)
53b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    : jit_code_cache_(jit_code_cache),
5486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      foreign_dex_profile_path_(foreign_dex_profile_path),
554d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      shutting_down_(false),
5685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      last_save_number_of_methods_(0),
570cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle      last_save_number_of_classes_(0),
584d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      wait_lock_("ProfileSaver wait lock"),
59c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      period_condition_("ProfileSaver period condition", wait_lock_),
60c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_bytes_written_(0),
61c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_number_of_writes_(0),
62c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_number_of_code_cache_queries_(0),
63c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_number_of_skipped_writes_(0),
64c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_number_of_failed_writes_(0),
6585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      total_ms_of_sleep_(0),
66c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_ns_of_work_(0),
6785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      total_number_of_foreign_dex_marks_(0),
6885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      max_number_of_profile_entries_cached_(0) {
6920ae79370a14c17dfb037914995d6430774fe492Calin Juravle  AddTrackedLocations(output_filename, app_data_dir, code_paths);
7086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  if (!app_data_dir.empty()) {
7186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    // The application directory is used to determine which dex files are owned by app.
7286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    // Since it could be a symlink (e.g. /data/data instead of /data/user/0), and we
7386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    // don't have control over how the dex files are actually loaded (symlink or canonical path),
7486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    // store it's canonical form to be sure we use the same base when comparing.
7586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    UniqueCPtr<const char[]> app_data_dir_real_path(realpath(app_data_dir.c_str(), nullptr));
7686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    if (app_data_dir_real_path != nullptr) {
7720ae79370a14c17dfb037914995d6430774fe492Calin Juravle      app_data_dirs_.emplace(app_data_dir_real_path.get());
7886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    } else {
7920ae79370a14c17dfb037914995d6430774fe492Calin Juravle      LOG(WARNING) << "Failed to get the real path for app dir: " << app_data_dir
8086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle          << ". The app dir will not be used to determine which dex files belong to the app";
8186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    }
8286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  }
834d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
844d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
854d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlevoid ProfileSaver::Run() {
864d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  srand(MicroTime() * getpid());
874d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  Thread* self = Thread::Current();
884d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
894d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  uint64_t save_period_ms = kSavePeriodMs;
904d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  VLOG(profiler) << "Save profiling information every " << save_period_ms << " ms";
9185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  bool cache_resolved_classes = true;
928913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  while (!ShuttingDown(self)) {
938913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    uint64_t sleep_time_ms;
9485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    if (cache_resolved_classes) {
958913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      // Sleep less long for the first iteration since we want to record loaded classes shortly
968913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      // after app launch.
97c15e566b36170237f01ccefc12129c1578a02140Calin Juravle      sleep_time_ms = kSaveResolvedClassesDelayMs;
988913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    } else {
998913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      const uint64_t random_sleep_delay_ms = rand() % kRandomDelayMaxMs;
1008913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      sleep_time_ms = save_period_ms + random_sleep_delay_ms;
1018913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    }
1024d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    {
1034d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      MutexLock mu(self, wait_lock_);
1044d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      period_condition_.TimedWait(self, sleep_time_ms, 0);
1054d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    }
10685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    total_ms_of_sleep_ += sleep_time_ms;
1074d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    if (ShuttingDown(self)) {
1084d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      break;
1094d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    }
1104d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
111c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    uint64_t start = NanoTime();
11285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    if (cache_resolved_classes) {
11385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      // TODO(calin) This only considers the case of the primary profile file.
11485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      // Anything that gets loaded in the same VM will not have their resolved
11585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      // classes save (unless they started before the initial saving was done).
11685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      FetchAndCacheResolvedClasses();
1174d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    } else {
11885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      bool profile_saved_to_disk = ProcessProfilingInfo();
11928530daffc05fe376dbd0df3b1b44257bce5a16fCalin Juravle      if (profile_saved_to_disk) {
12028530daffc05fe376dbd0df3b1b44257bce5a16fCalin Juravle        // Reset the period to the initial value as it's highly likely to JIT again.
12128530daffc05fe376dbd0df3b1b44257bce5a16fCalin Juravle        save_period_ms = kSavePeriodMs;
12228530daffc05fe376dbd0df3b1b44257bce5a16fCalin Juravle        VLOG(profiler) << "Profile saver: saved something, period reset to: " << save_period_ms;
12328530daffc05fe376dbd0df3b1b44257bce5a16fCalin Juravle      } else {
12485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        // If we don't need to save now it is less likely that we will need to do
12585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        // so in the future. Increase the time between saves according to the
12685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        // kBackoffCoef, but make it no larger than kMaxBackoffMs.
12728530daffc05fe376dbd0df3b1b44257bce5a16fCalin Juravle        save_period_ms = std::min(kMaxBackoffMs,
12828530daffc05fe376dbd0df3b1b44257bce5a16fCalin Juravle                                  static_cast<uint64_t>(kBackoffCoef * save_period_ms));
1290cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle        VLOG(profiler) << "Profile saver: nothing to save, delaying period to: " << save_period_ms;
13085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      }
1314d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    }
13285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    cache_resolved_classes = false;
133c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle
134c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    total_ns_of_work_ += (NanoTime() - start);
1354d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  }
1364d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
1374d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
13885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin JuravleProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) {
13985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  auto info_it = profile_cache_.find(filename);
14085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  if (info_it == profile_cache_.end()) {
14185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    info_it = profile_cache_.Put(filename, ProfileCompilationInfo());
14285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  }
14385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  return &info_it->second;
14485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle}
14585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle
14685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlevoid ProfileSaver::FetchAndCacheResolvedClasses() {
147dabdc0fe183d4684f3cf4d70cb09d318cff81b42Mathieu Chartier  ScopedTrace trace(__PRETTY_FUNCTION__);
14885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle
14985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
15085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  std::set<DexCacheResolvedClasses> resolved_classes =
15185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      class_linker->GetResolvedClasses(/*ignore boot classes*/ true);
15285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
15385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  uint64_t total_number_of_profile_entries_cached = 0;
15485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  for (const auto& it : tracked_dex_base_locations_) {
15585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      std::set<DexCacheResolvedClasses> resolved_classes_for_location;
15685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    const std::string& filename = it.first;
15785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    const std::set<std::string>& locations = it.second;
15885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle
15985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    for (const DexCacheResolvedClasses& classes : resolved_classes) {
16085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      if (locations.find(classes.GetDexLocation()) != locations.end()) {
16185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        resolved_classes_for_location.insert(classes);
16285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      }
16385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    }
16485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    ProfileCompilationInfo* info = GetCachedProfiledInfo(filename);
165e2d066d0337b7c81d47e4806e6025b70d83fcd56Calin Juravle    info->AddMethodsAndClasses(std::vector<MethodReference>(), resolved_classes_for_location);
16685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    total_number_of_profile_entries_cached += resolved_classes_for_location.size();
1674d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  }
16885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  max_number_of_profile_entries_cached_ = std::max(
16985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      max_number_of_profile_entries_cached_,
17085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      total_number_of_profile_entries_cached);
17185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle}
1724d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
17385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlebool ProfileSaver::ProcessProfilingInfo() {
17485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  ScopedTrace trace(__PRETTY_FUNCTION__);
175b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle  SafeMap<std::string, std::set<std::string>> tracked_locations;
1764d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  {
177b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    // Make a copy so that we don't hold the lock while doing I/O.
178b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
179b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    tracked_locations = tracked_dex_base_locations_;
1804d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  }
181c15e566b36170237f01ccefc12129c1578a02140Calin Juravle
18285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  bool profile_file_saved = false;
18385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  uint64_t total_number_of_profile_entries_cached = 0;
184b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle  for (const auto& it : tracked_locations) {
185b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    if (ShuttingDown(Thread::Current())) {
186b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle      return true;
187b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    }
188b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    const std::string& filename = it.first;
189b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    const std::set<std::string>& locations = it.second;
190e2d066d0337b7c81d47e4806e6025b70d83fcd56Calin Juravle    std::vector<MethodReference> methods;
191b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    {
192b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle      ScopedObjectAccess soa(Thread::Current());
193e2d066d0337b7c81d47e4806e6025b70d83fcd56Calin Juravle      jit_code_cache_->GetProfiledMethods(locations, methods);
194c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_number_of_code_cache_queries_++;
195b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    }
196c15e566b36170237f01ccefc12129c1578a02140Calin Juravle
19785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    ProfileCompilationInfo* cached_info = GetCachedProfiledInfo(filename);
19885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    cached_info->AddMethodsAndClasses(methods, std::set<DexCacheResolvedClasses>());
1990cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle    int64_t delta_number_of_methods =
2000cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle        cached_info->GetNumberOfMethods() -
2010cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle        static_cast<int64_t>(last_save_number_of_methods_);
2020cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle    int64_t delta_number_of_classes =
2030cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle        cached_info->GetNumberOfResolvedClasses() -
2040cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle        static_cast<int64_t>(last_save_number_of_classes_);
20585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle
20685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    if (delta_number_of_methods < kMinimumNumberOfMethodsToSave &&
20785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        delta_number_of_classes < kMinimumNumberOfClassesToSave) {
2080cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle      VLOG(profiler) << "Not enough information to save to: " << filename
20985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle          << " Nr of methods: " << delta_number_of_methods
21085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle          << " Nr of classes: " << delta_number_of_classes;
211c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      total_number_of_skipped_writes_++;
21285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      continue;
213b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    }
214c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    uint64_t bytes_written;
215fe297a96bc6d3da11579709add9b4568730d2b4fCalin Juravle    // Force the save. In case the profile data is corrupted or the the profile
216fe297a96bc6d3da11579709add9b4568730d2b4fCalin Juravle    // has the wrong version this will "fix" the file to the correct format.
217fe297a96bc6d3da11579709add9b4568730d2b4fCalin Juravle    if (cached_info->MergeAndSave(filename, &bytes_written, /*force*/ true)) {
21885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      last_save_number_of_methods_ = cached_info->GetNumberOfMethods();
2190cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle      last_save_number_of_classes_ = cached_info->GetNumberOfResolvedClasses();
22085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      // Clear resolved classes. No need to store them around as
22185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      // they don't change after the first write.
22285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      cached_info->ClearResolvedClasses();
223c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      if (bytes_written > 0) {
224c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle        total_number_of_writes_++;
225c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle        total_bytes_written_ += bytes_written;
2260cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle        profile_file_saved = true;
22785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      } else {
22885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        // At this point we could still have avoided the write.
22985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        // We load and merge the data from the file lazily at its first ever
23085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        // save attempt. So, whatever we are trying to save could already be
23185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        // in the file.
23285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        total_number_of_skipped_writes_++;
233c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      }
23485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    } else {
23585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      LOG(WARNING) << "Could not save profiling info to " << filename;
23685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      total_number_of_failed_writes_++;
237b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    }
23885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    total_number_of_profile_entries_cached +=
23985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        cached_info->GetNumberOfMethods() +
24085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle        cached_info->GetNumberOfResolvedClasses();
241b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle  }
24285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  max_number_of_profile_entries_cached_ = std::max(
24385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      max_number_of_profile_entries_cached_,
24485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle      total_number_of_profile_entries_cached);
24585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle  return profile_file_saved;
2464d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
2474d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
2484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlevoid* ProfileSaver::RunProfileSaverThread(void* arg) {
2494d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  Runtime* runtime = Runtime::Current();
2504d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
251e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle  bool attached = runtime->AttachCurrentThread("Profile Saver",
252e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle                                               /*as_daemon*/true,
253e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle                                               runtime->GetSystemThreadGroup(),
254e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle                                               /*create_peer*/true);
255e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle  if (!attached) {
256e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle    CHECK(runtime->IsShuttingDown(Thread::Current()));
257e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle    return nullptr;
258e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle  }
259e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle
260e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle  ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg);
2614d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  profile_saver->Run();
2624d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
2634d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  runtime->DetachCurrentThread();
2644d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  VLOG(profiler) << "Profile saver shutdown";
2654d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  return nullptr;
2664d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
2674d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
2686044fa747867413912d0de3049dc570c769d3cf8Calin Juravlestatic bool ShouldProfileLocation(const std::string& location) {
2697506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle  OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager();
2707506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle  const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location);
2716044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  if (oat_file == nullptr) {
2726044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    // This can happen if we fallback to run code directly from the APK.
2736044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    // Profile it with the hope that the background dexopt will get us back into
2746044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    // a good state.
2757506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle    VLOG(profiler) << "Asked to profile a location without an oat file:" << location;
2766044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    return true;
2776044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  }
2786044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  CompilerFilter::Filter filter = oat_file->GetCompilerFilter();
279d19dc4688b5b93f149d45435deb0a67217464e37Calin Juravle  if ((filter == CompilerFilter::kSpeed) || (filter == CompilerFilter::kEverything)) {
2807506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle    VLOG(profiler)
281d19dc4688b5b93f149d45435deb0a67217464e37Calin Juravle        << "Skip profiling oat file because it's already speed|everything compiled: "
282d19dc4688b5b93f149d45435deb0a67217464e37Calin Juravle        << location << " oat location: " << oat_file->GetLocation();
2836044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    return false;
2846044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  }
2856044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  return true;
2866044fa747867413912d0de3049dc570c769d3cf8Calin Juravle}
2876044fa747867413912d0de3049dc570c769d3cf8Calin Juravle
2884d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlevoid ProfileSaver::Start(const std::string& output_filename,
2894d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle                         jit::JitCodeCache* jit_code_cache,
29086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                         const std::vector<std::string>& code_paths,
29186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                         const std::string& foreign_dex_profile_path,
29286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                         const std::string& app_data_dir) {
293e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  DCHECK(Runtime::Current()->SaveProfileInfo());
2944d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  DCHECK(!output_filename.empty());
2954d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  DCHECK(jit_code_cache != nullptr);
2964d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
2976044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  std::vector<std::string> code_paths_to_profile;
2986044fa747867413912d0de3049dc570c769d3cf8Calin Juravle
2996044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  for (const std::string& location : code_paths) {
3006044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    if (ShouldProfileLocation(location))  {
3016044fa747867413912d0de3049dc570c769d3cf8Calin Juravle      code_paths_to_profile.push_back(location);
3026044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    }
3036044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  }
3046044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  if (code_paths_to_profile.empty()) {
3057506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle    VLOG(profiler) << "No code paths should be profiled.";
3066044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    return;
3076044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  }
3086044fa747867413912d0de3049dc570c769d3cf8Calin Juravle
3094d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
3104d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  if (instance_ != nullptr) {
311b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    // If we already have an instance, make sure it uses the same jit_code_cache.
312b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    // This may be called multiple times via Runtime::registerAppInfo (e.g. for
313b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    // apps which share the same runtime).
314b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache);
315b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    // Add the code_paths to the tracked locations.
31620ae79370a14c17dfb037914995d6430774fe492Calin Juravle    instance_->AddTrackedLocations(output_filename, app_data_dir, code_paths_to_profile);
3174d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    return;
3184d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  }
3194d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3204d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  VLOG(profiler) << "Starting profile saver using output file: " << output_filename
3217506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle      << ". Tracking: " << Join(code_paths_to_profile, ':');
3224d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
32386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  instance_ = new ProfileSaver(output_filename,
32486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                               jit_code_cache,
3257506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle                               code_paths_to_profile,
32686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                               foreign_dex_profile_path,
32786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle                               app_data_dir);
3284d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3294d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  // Create a new thread which does the saving.
3304d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  CHECK_PTHREAD_CALL(
3314d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      pthread_create,
3324d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
3334d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      "Profile saver thread");
3344d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
3354d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
336c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::Stop(bool dump_info) {
3374d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  ProfileSaver* profile_saver = nullptr;
3384d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  pthread_t profiler_pthread = 0U;
3394d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3404d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  {
3414d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
342b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    VLOG(profiler) << "Stopping profile saver thread";
3434d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    profile_saver = instance_;
3444d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    profiler_pthread = profiler_pthread_;
3454d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    if (instance_ == nullptr) {
3464d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      DCHECK(false) << "Tried to stop a profile saver which was not started";
3474d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      return;
3484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    }
3494d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    if (instance_->shutting_down_) {
3504d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      DCHECK(false) << "Tried to stop the profile saver twice";
3514d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle      return;
3524d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    }
3534d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    instance_->shutting_down_ = true;
354c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    if (dump_info) {
355c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      instance_->DumpInfo(LOG(INFO));
356c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    }
3574d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  }
3584d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3594d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  {
3604d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    // Wake up the saver thread if it is sleeping to allow for a clean exit.
3614d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_);
3624d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    profile_saver->period_condition_.Signal(Thread::Current());
3634d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  }
3644d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3654d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  // Wait for the saver thread to stop.
3664d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
3674d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3684d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  {
3694d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
3704d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    instance_ = nullptr;
3714d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    profiler_pthread_ = 0U;
3724d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  }
3734d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  delete profile_saver;
3744d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
3754d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3764d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlebool ProfileSaver::ShuttingDown(Thread* self) {
3774d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  MutexLock mu(self, *Locks::profiler_lock_);
3784d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  return shutting_down_;
3794d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
3804d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
3814d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlebool ProfileSaver::IsStarted() {
3824d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
3834d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle  return instance_ != nullptr;
3844d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}
3854d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle
386b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravlevoid ProfileSaver::AddTrackedLocations(const std::string& output_filename,
38720ae79370a14c17dfb037914995d6430774fe492Calin Juravle                                       const std::string& app_data_dir,
388b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle                                       const std::vector<std::string>& code_paths) {
389b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle  auto it = tracked_dex_base_locations_.find(output_filename);
390b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle  if (it == tracked_dex_base_locations_.end()) {
391b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    tracked_dex_base_locations_.Put(output_filename,
392b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle                                    std::set<std::string>(code_paths.begin(), code_paths.end()));
39320ae79370a14c17dfb037914995d6430774fe492Calin Juravle    app_data_dirs_.insert(app_data_dir);
394b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle  } else {
395b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle    it->second.insert(code_paths.begin(), code_paths.end());
396b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle  }
397b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle}
398b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle
39986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravlevoid ProfileSaver::NotifyDexUse(const std::string& dex_location) {
4006044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  if (!ShouldProfileLocation(dex_location)) {
4016044fa747867413912d0de3049dc570c769d3cf8Calin Juravle    return;
4026044fa747867413912d0de3049dc570c769d3cf8Calin Juravle  }
40386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  std::set<std::string> app_code_paths;
40486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  std::string foreign_dex_profile_path;
40520ae79370a14c17dfb037914995d6430774fe492Calin Juravle  std::set<std::string> app_data_dirs;
40686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  {
40786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
408c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    if (instance_ == nullptr) {
409c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      return;
410c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    }
41186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    // Make a copy so that we don't hold the lock while doing I/O.
41286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    for (const auto& it : instance_->tracked_dex_base_locations_) {
41386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      app_code_paths.insert(it.second.begin(), it.second.end());
41486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    }
41586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    foreign_dex_profile_path = instance_->foreign_dex_profile_path_;
41620ae79370a14c17dfb037914995d6430774fe492Calin Juravle    app_data_dirs.insert(instance_->app_data_dirs_.begin(), instance_->app_data_dirs_.end());
41786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  }
41886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
419c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle  bool mark_created = MaybeRecordDexUseInternal(dex_location,
420c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle                                                app_code_paths,
421c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle                                                foreign_dex_profile_path,
42220ae79370a14c17dfb037914995d6430774fe492Calin Juravle                                                app_data_dirs);
423c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle  if (mark_created) {
424c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
425c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    if (instance_ != nullptr) {
426c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      instance_->total_number_of_foreign_dex_marks_++;
427c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    }
428c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle  }
42986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle}
43086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
431c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlebool ProfileSaver::MaybeRecordDexUseInternal(
43286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      const std::string& dex_location,
43386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      const std::set<std::string>& app_code_paths,
43486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      const std::string& foreign_dex_profile_path,
43520ae79370a14c17dfb037914995d6430774fe492Calin Juravle      const std::set<std::string>& app_data_dirs) {
4361fae45f7d777e3971b916dda531c8648304866c8Calin Juravle  if (dex_location.empty()) {
4371fae45f7d777e3971b916dda531c8648304866c8Calin Juravle    LOG(WARNING) << "Asked to record foreign dex use with an empty dex location.";
438c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    return false;
4391fae45f7d777e3971b916dda531c8648304866c8Calin Juravle  }
44086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  if (foreign_dex_profile_path.empty()) {
44186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    LOG(WARNING) << "Asked to record foreign dex use without a valid profile path ";
442c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    return false;
44386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  }
44486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
44586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr));
4461fae45f7d777e3971b916dda531c8648304866c8Calin Juravle  if (dex_location_real_path == nullptr) {
4471fae45f7d777e3971b916dda531c8648304866c8Calin Juravle    PLOG(WARNING) << "Could not get realpath for " << dex_location;
4481fae45f7d777e3971b916dda531c8648304866c8Calin Juravle  }
4491fae45f7d777e3971b916dda531c8648304866c8Calin Juravle  std::string dex_location_real_path_str((dex_location_real_path == nullptr)
4501fae45f7d777e3971b916dda531c8648304866c8Calin Juravle    ? dex_location.c_str()
4511fae45f7d777e3971b916dda531c8648304866c8Calin Juravle    : dex_location_real_path.get());
45286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
45320ae79370a14c17dfb037914995d6430774fe492Calin Juravle  if (app_data_dirs.find(dex_location_real_path_str) != app_data_dirs.end()) {
45486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    // The dex location is under the application folder. Nothing to record.
455c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    return false;
45686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  }
45786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
45886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  if (app_code_paths.find(dex_location) != app_code_paths.end()) {
45986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    // The dex location belongs to the application code paths. Nothing to record.
460c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    return false;
46186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  }
46286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // Do another round of checks with the real paths.
46386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // Note that we could cache all the real locations in the saver (since it's an expensive
46486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // operation). However we expect that app_code_paths is small (usually 1 element), and
46586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise
46686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // to save some bytes of memory usage.
46786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  for (const auto& app_code_location : app_code_paths) {
46886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    UniqueCPtr<const char[]> real_app_code_location(realpath(app_code_location.c_str(), nullptr));
4691fae45f7d777e3971b916dda531c8648304866c8Calin Juravle    if (real_app_code_location == nullptr) {
4701fae45f7d777e3971b916dda531c8648304866c8Calin Juravle      PLOG(WARNING) << "Could not get realpath for " << app_code_location;
4711fae45f7d777e3971b916dda531c8648304866c8Calin Juravle    }
4721fae45f7d777e3971b916dda531c8648304866c8Calin Juravle    std::string real_app_code_location_str((real_app_code_location == nullptr)
4731fae45f7d777e3971b916dda531c8648304866c8Calin Juravle        ? app_code_location.c_str()
4741fae45f7d777e3971b916dda531c8648304866c8Calin Juravle        : real_app_code_location.get());
47586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    if (real_app_code_location_str == dex_location_real_path_str) {
47686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      // The dex location belongs to the application code paths. Nothing to record.
477c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      return false;
47886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    }
47986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  }
48086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
48186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // For foreign dex files we record a flag on disk. PackageManager will (potentially) take this
48286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // into account when deciding how to optimize the loaded dex file.
48386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // The expected flag name is the canonical path of the apk where '/' is substituted to '@'.
48486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // (it needs to be kept in sync with
48586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java)
48686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  std::replace(dex_location_real_path_str.begin(), dex_location_real_path_str.end(), '/', '@');
48786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  std::string flag_path = foreign_dex_profile_path + "/" + dex_location_real_path_str;
48886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // No need to give any sort of access to flag_path. The system has enough permissions
48986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  // to test for its existence.
49086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  int fd = TEMP_FAILURE_RETRY(open(flag_path.c_str(), O_CREAT | O_EXCL, 0));
49186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  if (fd != -1) {
49286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    if (close(fd) != 0) {
49386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      PLOG(WARNING) << "Could not close file after flagging foreign dex use " << flag_path;
49486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    }
495c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    return true;
49686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  } else {
49786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    if (errno != EEXIST) {
49886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      // Another app could have already created the file.
49986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle      PLOG(WARNING) << "Could not create foreign dex use mark " << flag_path;
500c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle      return false;
50186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle    }
502c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    return true;
50386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle  }
50486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle}
50586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle
506c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::DumpInstanceInfo(std::ostream& os) {
507c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle  MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
508c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle  if (instance_ != nullptr) {
509c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle    instance_->DumpInfo(os);
510c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle  }
511c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle}
512c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle
513c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::DumpInfo(std::ostream& os) {
514c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle  os << "ProfileSaver total_bytes_written=" << total_bytes_written_ << '\n'
515c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle     << "ProfileSaver total_number_of_writes=" << total_number_of_writes_ << '\n'
51685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle     << "ProfileSaver total_number_of_code_cache_queries="
51785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle     << total_number_of_code_cache_queries_ << '\n'
518c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle     << "ProfileSaver total_number_of_skipped_writes=" << total_number_of_skipped_writes_ << '\n'
519c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle     << "ProfileSaver total_number_of_failed_writes=" << total_number_of_failed_writes_ << '\n'
52085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle     << "ProfileSaver total_ms_of_sleep=" << total_ms_of_sleep_ << '\n'
5216044fa747867413912d0de3049dc570c769d3cf8Calin Juravle     << "ProfileSaver total_ms_of_work=" << NsToMs(total_ns_of_work_) << '\n'
52285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle     << "ProfileSaver total_number_of_foreign_dex_marks="
52385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle     << total_number_of_foreign_dex_marks_ << '\n'
52485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle     << "ProfileSaver max_number_profile_entries_cached="
52585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle    << max_number_of_profile_entries_cached_ << '\n';
526c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle}
527c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle
528e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle
529e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravlevoid ProfileSaver::ForceProcessProfiles() {
530e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  ProfileSaver* saver = nullptr;
531e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  {
532e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle    MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
533e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle    saver = instance_;
534e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  }
535e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  // TODO(calin): this is not actually thread safe as the instance_ may have been deleted,
536e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  // but we only use this in testing when we now this won't happen.
537e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  // Refactor the way we handle the instance so that we don't end up in this situation.
538e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  if (saver != nullptr) {
539e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle    saver->ProcessProfilingInfo();
540e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  }
541e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle}
542e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle
543e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravlebool ProfileSaver::HasSeenMethod(const std::string& profile,
544e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle                                 const DexFile* dex_file,
545e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle                                 uint16_t method_idx) {
546e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
547e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  if (instance_ != nullptr) {
548e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle    ProfileCompilationInfo* info = instance_->GetCachedProfiledInfo(profile);
549e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle    if (info != nullptr) {
550e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle      return info->ContainsMethod(MethodReference(dex_file, method_idx));
551e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle    }
552e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  }
553e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle  return false;
554e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle}
555e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle
5564d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle}   // namespace art
557