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