profile_saver.cc revision 20ae79370a14c17dfb037914995d6430774fe492
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); 16585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle info->AddMethodsAndClasses(std::vector<ArtMethod*>(), 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; 190b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle std::vector<ArtMethod*> methods; 191b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle { 192b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle ScopedObjectAccess soa(Thread::Current()); 193b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle jit_code_cache_->GetCompiledArtMethods(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 ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg); 2514d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 2524d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle CHECK(runtime->AttachCurrentThread("Profile Saver", 2534d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle /*as_daemon*/true, 2544d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle runtime->GetSystemThreadGroup(), 2554d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle /*create_peer*/true)); 2564d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profile_saver->Run(); 2574d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 2584d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle runtime->DetachCurrentThread(); 2594d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle VLOG(profiler) << "Profile saver shutdown"; 2604d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return nullptr; 2614d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 2624d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 2636044fa747867413912d0de3049dc570c769d3cf8Calin Juravlestatic bool ShouldProfileLocation(const std::string& location) { 2647506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager(); 2657506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location); 2666044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (oat_file == nullptr) { 2676044fa747867413912d0de3049dc570c769d3cf8Calin Juravle // This can happen if we fallback to run code directly from the APK. 2686044fa747867413912d0de3049dc570c769d3cf8Calin Juravle // Profile it with the hope that the background dexopt will get us back into 2696044fa747867413912d0de3049dc570c769d3cf8Calin Juravle // a good state. 2707506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle VLOG(profiler) << "Asked to profile a location without an oat file:" << location; 2716044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return true; 2726044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 2736044fa747867413912d0de3049dc570c769d3cf8Calin Juravle CompilerFilter::Filter filter = oat_file->GetCompilerFilter(); 2746044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (filter == CompilerFilter::kSpeed || CompilerFilter::kEverything) { 2757506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle VLOG(profiler) 2767506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle << "Skip profiling oat file because it's already speed|everything compiled:" 2777506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle << location; 2786044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return false; 2796044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 2806044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return true; 2816044fa747867413912d0de3049dc570c769d3cf8Calin Juravle} 2826044fa747867413912d0de3049dc570c769d3cf8Calin Juravle 2834d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlevoid ProfileSaver::Start(const std::string& output_filename, 2844d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle jit::JitCodeCache* jit_code_cache, 28586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::vector<std::string>& code_paths, 28686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& foreign_dex_profile_path, 28786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& app_data_dir) { 2884d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(Runtime::Current()->UseJit()); 2894d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(!output_filename.empty()); 2904d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(jit_code_cache != nullptr); 2914d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 2926044fa747867413912d0de3049dc570c769d3cf8Calin Juravle std::vector<std::string> code_paths_to_profile; 2936044fa747867413912d0de3049dc570c769d3cf8Calin Juravle 2946044fa747867413912d0de3049dc570c769d3cf8Calin Juravle for (const std::string& location : code_paths) { 2956044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (ShouldProfileLocation(location)) { 2966044fa747867413912d0de3049dc570c769d3cf8Calin Juravle code_paths_to_profile.push_back(location); 2976044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 2986044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 2996044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (code_paths_to_profile.empty()) { 3007506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle VLOG(profiler) << "No code paths should be profiled."; 3016044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return; 3026044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 3036044fa747867413912d0de3049dc570c769d3cf8Calin Juravle 3044d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 3054d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle if (instance_ != nullptr) { 306b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // If we already have an instance, make sure it uses the same jit_code_cache. 307b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // This may be called multiple times via Runtime::registerAppInfo (e.g. for 308b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // apps which share the same runtime). 309b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache); 310b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // Add the code_paths to the tracked locations. 31120ae79370a14c17dfb037914995d6430774fe492Calin Juravle instance_->AddTrackedLocations(output_filename, app_data_dir, code_paths_to_profile); 3124d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return; 3134d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 3144d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3154d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle VLOG(profiler) << "Starting profile saver using output file: " << output_filename 3167506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle << ". Tracking: " << Join(code_paths_to_profile, ':'); 3174d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 31886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle instance_ = new ProfileSaver(output_filename, 31986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle jit_code_cache, 3207506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle code_paths_to_profile, 32186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle foreign_dex_profile_path, 32286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle app_data_dir); 3234d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3244d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle // Create a new thread which does the saving. 3254d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle CHECK_PTHREAD_CALL( 3264d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle pthread_create, 3274d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)), 3284d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle "Profile saver thread"); 3294d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 3304d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 331c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::Stop(bool dump_info) { 3324d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle ProfileSaver* profile_saver = nullptr; 3334d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle pthread_t profiler_pthread = 0U; 3344d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3354d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 3364d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_); 337b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle VLOG(profiler) << "Stopping profile saver thread"; 3384d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profile_saver = instance_; 3394d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profiler_pthread = profiler_pthread_; 3404d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle if (instance_ == nullptr) { 3414d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(false) << "Tried to stop a profile saver which was not started"; 3424d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return; 3434d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 3444d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle if (instance_->shutting_down_) { 3454d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(false) << "Tried to stop the profile saver twice"; 3464d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return; 3474d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 3484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle instance_->shutting_down_ = true; 349c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (dump_info) { 350c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle instance_->DumpInfo(LOG(INFO)); 351c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 3524d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 3534d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3544d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 3554d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle // Wake up the saver thread if it is sleeping to allow for a clean exit. 3564d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_); 3574d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profile_saver->period_condition_.Signal(Thread::Current()); 3584d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 3594d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3604d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle // Wait for the saver thread to stop. 3614d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown"); 3624d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3634d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 3644d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_); 3654d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle instance_ = nullptr; 3664d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profiler_pthread_ = 0U; 3674d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 3684d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle delete profile_saver; 3694d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 3704d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3714d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlebool ProfileSaver::ShuttingDown(Thread* self) { 3724d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock mu(self, *Locks::profiler_lock_); 3734d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return shutting_down_; 3744d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 3754d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3764d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlebool ProfileSaver::IsStarted() { 3774d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 3784d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return instance_ != nullptr; 3794d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 3804d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 381b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravlevoid ProfileSaver::AddTrackedLocations(const std::string& output_filename, 38220ae79370a14c17dfb037914995d6430774fe492Calin Juravle const std::string& app_data_dir, 383b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle const std::vector<std::string>& code_paths) { 384b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle auto it = tracked_dex_base_locations_.find(output_filename); 385b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle if (it == tracked_dex_base_locations_.end()) { 386b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle tracked_dex_base_locations_.Put(output_filename, 387b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle std::set<std::string>(code_paths.begin(), code_paths.end())); 38820ae79370a14c17dfb037914995d6430774fe492Calin Juravle app_data_dirs_.insert(app_data_dir); 389b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } else { 390b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle it->second.insert(code_paths.begin(), code_paths.end()); 391b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } 392b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle} 393b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle 39486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravlevoid ProfileSaver::NotifyDexUse(const std::string& dex_location) { 3956044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (!ShouldProfileLocation(dex_location)) { 3966044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return; 3976044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 39886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle std::set<std::string> app_code_paths; 39986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle std::string foreign_dex_profile_path; 40020ae79370a14c17dfb037914995d6430774fe492Calin Juravle std::set<std::string> app_data_dirs; 40186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle { 40286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 403c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (instance_ == nullptr) { 404c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return; 405c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 40686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // Make a copy so that we don't hold the lock while doing I/O. 40786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle for (const auto& it : instance_->tracked_dex_base_locations_) { 40886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle app_code_paths.insert(it.second.begin(), it.second.end()); 40986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 41086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle foreign_dex_profile_path = instance_->foreign_dex_profile_path_; 41120ae79370a14c17dfb037914995d6430774fe492Calin Juravle app_data_dirs.insert(instance_->app_data_dirs_.begin(), instance_->app_data_dirs_.end()); 41286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 41386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 414c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle bool mark_created = MaybeRecordDexUseInternal(dex_location, 415c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle app_code_paths, 416c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle foreign_dex_profile_path, 41720ae79370a14c17dfb037914995d6430774fe492Calin Juravle app_data_dirs); 418c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (mark_created) { 419c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 420c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (instance_ != nullptr) { 421c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle instance_->total_number_of_foreign_dex_marks_++; 422c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 423c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 42486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle} 42586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 426c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlebool ProfileSaver::MaybeRecordDexUseInternal( 42786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& dex_location, 42886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::set<std::string>& app_code_paths, 42986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& foreign_dex_profile_path, 43020ae79370a14c17dfb037914995d6430774fe492Calin Juravle const std::set<std::string>& app_data_dirs) { 4311fae45f7d777e3971b916dda531c8648304866c8Calin Juravle if (dex_location.empty()) { 4321fae45f7d777e3971b916dda531c8648304866c8Calin Juravle LOG(WARNING) << "Asked to record foreign dex use with an empty dex location."; 433c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return false; 4341fae45f7d777e3971b916dda531c8648304866c8Calin Juravle } 43586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (foreign_dex_profile_path.empty()) { 43686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle LOG(WARNING) << "Asked to record foreign dex use without a valid profile path "; 437c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return false; 43886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 43986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 44086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr)); 4411fae45f7d777e3971b916dda531c8648304866c8Calin Juravle if (dex_location_real_path == nullptr) { 4421fae45f7d777e3971b916dda531c8648304866c8Calin Juravle PLOG(WARNING) << "Could not get realpath for " << dex_location; 4431fae45f7d777e3971b916dda531c8648304866c8Calin Juravle } 4441fae45f7d777e3971b916dda531c8648304866c8Calin Juravle std::string dex_location_real_path_str((dex_location_real_path == nullptr) 4451fae45f7d777e3971b916dda531c8648304866c8Calin Juravle ? dex_location.c_str() 4461fae45f7d777e3971b916dda531c8648304866c8Calin Juravle : dex_location_real_path.get()); 44786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 44820ae79370a14c17dfb037914995d6430774fe492Calin Juravle if (app_data_dirs.find(dex_location_real_path_str) != app_data_dirs.end()) { 44986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // The dex location is under the application folder. Nothing to record. 450c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return false; 45186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 45286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 45386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (app_code_paths.find(dex_location) != app_code_paths.end()) { 45486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // The dex location belongs to the application code paths. Nothing to record. 455c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return false; 45686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 45786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // Do another round of checks with the real paths. 45886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // Note that we could cache all the real locations in the saver (since it's an expensive 45986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // operation). However we expect that app_code_paths is small (usually 1 element), and 46086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise 46186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // to save some bytes of memory usage. 46286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle for (const auto& app_code_location : app_code_paths) { 46386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle UniqueCPtr<const char[]> real_app_code_location(realpath(app_code_location.c_str(), nullptr)); 4641fae45f7d777e3971b916dda531c8648304866c8Calin Juravle if (real_app_code_location == nullptr) { 4651fae45f7d777e3971b916dda531c8648304866c8Calin Juravle PLOG(WARNING) << "Could not get realpath for " << app_code_location; 4661fae45f7d777e3971b916dda531c8648304866c8Calin Juravle } 4671fae45f7d777e3971b916dda531c8648304866c8Calin Juravle std::string real_app_code_location_str((real_app_code_location == nullptr) 4681fae45f7d777e3971b916dda531c8648304866c8Calin Juravle ? app_code_location.c_str() 4691fae45f7d777e3971b916dda531c8648304866c8Calin Juravle : real_app_code_location.get()); 47086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (real_app_code_location_str == dex_location_real_path_str) { 47186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // The dex location belongs to the application code paths. Nothing to record. 472c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return false; 47386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 47486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 47586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 47686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // For foreign dex files we record a flag on disk. PackageManager will (potentially) take this 47786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // into account when deciding how to optimize the loaded dex file. 47886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // The expected flag name is the canonical path of the apk where '/' is substituted to '@'. 47986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // (it needs to be kept in sync with 48086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java) 48186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle std::replace(dex_location_real_path_str.begin(), dex_location_real_path_str.end(), '/', '@'); 48286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle std::string flag_path = foreign_dex_profile_path + "/" + dex_location_real_path_str; 48386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // No need to give any sort of access to flag_path. The system has enough permissions 48486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // to test for its existence. 48586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle int fd = TEMP_FAILURE_RETRY(open(flag_path.c_str(), O_CREAT | O_EXCL, 0)); 48686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (fd != -1) { 48786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (close(fd) != 0) { 48886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle PLOG(WARNING) << "Could not close file after flagging foreign dex use " << flag_path; 48986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 490c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return true; 49186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } else { 49286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (errno != EEXIST) { 49386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // Another app could have already created the file. 49486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle PLOG(WARNING) << "Could not create foreign dex use mark " << flag_path; 495c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return false; 49686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 497c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return true; 49886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 49986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle} 50086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 501c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::DumpInstanceInfo(std::ostream& os) { 502c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 503c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (instance_ != nullptr) { 504c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle instance_->DumpInfo(os); 505c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 506c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle} 507c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle 508c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::DumpInfo(std::ostream& os) { 509c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle os << "ProfileSaver total_bytes_written=" << total_bytes_written_ << '\n' 510c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle << "ProfileSaver total_number_of_writes=" << total_number_of_writes_ << '\n' 51185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver total_number_of_code_cache_queries=" 51285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << total_number_of_code_cache_queries_ << '\n' 513c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle << "ProfileSaver total_number_of_skipped_writes=" << total_number_of_skipped_writes_ << '\n' 514c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle << "ProfileSaver total_number_of_failed_writes=" << total_number_of_failed_writes_ << '\n' 51585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver total_ms_of_sleep=" << total_ms_of_sleep_ << '\n' 5166044fa747867413912d0de3049dc570c769d3cf8Calin Juravle << "ProfileSaver total_ms_of_work=" << NsToMs(total_ns_of_work_) << '\n' 51785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver total_number_of_foreign_dex_marks=" 51885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << total_number_of_foreign_dex_marks_ << '\n' 51985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver max_number_profile_entries_cached=" 52085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << max_number_of_profile_entries_cached_ << '\n'; 521c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle} 522c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle 5234d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} // namespace art 524