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. 365fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravlestatic constexpr const uint64_t kMinSavePeriodNs = MsToNs(20 * 1000); // 20 seconds 37c15e566b36170237f01ccefc12129c1578a02140Calin Juravlestatic constexpr const uint64_t kSaveResolvedClassesDelayMs = 2 * 1000; // 2 seconds 38c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier// Minimum number of JIT samples during launch to include a method into the profile. 39c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartierstatic constexpr const size_t kStartupMethodSamples = 1; 404d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlestatic constexpr const uint32_t kMinimumNumberOfMethodsToSave = 10; 4285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravlestatic constexpr const uint32_t kMinimumNumberOfClassesToSave = 10; 435fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravlestatic constexpr const uint32_t kMinimumNumberOfNotificationBeforeWake = 445fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle kMinimumNumberOfMethodsToSave; 455fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravlestatic constexpr const uint32_t kMaximumNumberOfNotificationBeforeWake = 50; 465fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle 474d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin JuravleProfileSaver* ProfileSaver::instance_ = nullptr; 494d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlepthread_t ProfileSaver::profiler_pthread_ = 0U; 504d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 514d77b6a511659f26fdc711e23825ffa6e7feed7aCalin JuravleProfileSaver::ProfileSaver(const std::string& output_filename, 524d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle jit::JitCodeCache* jit_code_cache, 5386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::vector<std::string>& code_paths, 5486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& foreign_dex_profile_path, 5586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& app_data_dir) 56b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle : jit_code_cache_(jit_code_cache), 5786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle foreign_dex_profile_path_(foreign_dex_profile_path), 584d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle shutting_down_(false), 5985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle last_save_number_of_methods_(0), 600cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle last_save_number_of_classes_(0), 615fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle last_time_ns_saver_woke_up_(0), 625fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle jit_activity_notifications_(0), 634d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle wait_lock_("ProfileSaver wait lock"), 64c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle period_condition_("ProfileSaver period condition", wait_lock_), 65c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_bytes_written_(0), 66c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_number_of_writes_(0), 67c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_number_of_code_cache_queries_(0), 68c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_number_of_skipped_writes_(0), 69c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_number_of_failed_writes_(0), 7085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_ms_of_sleep_(0), 71c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_ns_of_work_(0), 7285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_number_of_foreign_dex_marks_(0), 735fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle max_number_of_profile_entries_cached_(0), 745fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_number_of_hot_spikes_(0), 755fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_number_of_wake_ups_(0) { 7620ae79370a14c17dfb037914995d6430774fe492Calin Juravle AddTrackedLocations(output_filename, app_data_dir, code_paths); 774d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 784d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 794d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlevoid ProfileSaver::Run() { 804d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle Thread* self = Thread::Current(); 814d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 825fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Fetch the resolved classes for the app images after sleeping for 835fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // kSaveResolvedClassesDelayMs. 845fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // TODO(calin) This only considers the case of the primary profile file. 855fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Anything that gets loaded in the same VM will not have their resolved 865fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // classes save (unless they started before the initial saving was done). 875fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle { 885fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle MutexLock mu(self, wait_lock_); 890ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier constexpr uint64_t kSleepTime = kSaveResolvedClassesDelayMs; 900ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier const uint64_t end_time = NanoTime() + MsToNs(kSleepTime); 910ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier while (true) { 920ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier const uint64_t current_time = NanoTime(); 930ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier if (current_time >= end_time) { 940ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier break; 950ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier } 960ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier period_condition_.TimedWait(self, NsToMs(end_time - current_time), 0); 970ec065d55ccc4eb0956b0a2231bcc8c1a6d1d273Mathieu Chartier } 985fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_ms_of_sleep_ += kSaveResolvedClassesDelayMs; 995fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle } 100c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier FetchAndCacheResolvedClassesAndMethods(); 1015fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle 1025fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Loop for the profiled methods. 1038913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier while (!ShuttingDown(self)) { 1045fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle uint64_t sleep_start = NanoTime(); 1054d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 1060233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle uint64_t sleep_time = 0; 1070233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle { 1080233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle MutexLock mu(self, wait_lock_); 1090233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle period_condition_.Wait(self); 110dc85bd757e7f27c38143536a9f4fa4c2c7d07272Calin Juravle sleep_time = NanoTime() - sleep_start; 1110233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle } 1120233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle // Check if the thread was woken up for shutdown. 1130233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle if (ShuttingDown(self)) { 1140233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle break; 1150233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle } 1165fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_number_of_wake_ups_++; 1175fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // We might have been woken up by a huge number of notifications to guarantee saving. 1185fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // If we didn't meet the minimum saving period go back to sleep (only if missed by 1195fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // a reasonable margin). 1208f15335d96eef7a3bcdd4f2b309a727791b67e68Brian Carlstrom while (kMinSavePeriodNs * 0.9 > sleep_time) { 1210233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle { 1220233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle MutexLock mu(self, wait_lock_); 1230233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle period_condition_.TimedWait(self, NsToMs(kMinSavePeriodNs - sleep_time), 0); 124dc85bd757e7f27c38143536a9f4fa4c2c7d07272Calin Juravle sleep_time = NanoTime() - sleep_start; 1250233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle } 1260233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle // Check if the thread was woken up for shutdown. 1270233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle if (ShuttingDown(self)) { 1280233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle break; 1290233a413ba42aa34a92c357c8dcfbe48871788b9Calin Juravle } 1305fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_number_of_wake_ups_++; 1315fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle } 1324d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 1335fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_ms_of_sleep_ += NsToMs(NanoTime() - sleep_start); 1345fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle 1354d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle if (ShuttingDown(self)) { 1364d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle break; 1374d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 1384d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 1395fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle uint16_t new_methods = 0; 1405fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle uint64_t start_work = NanoTime(); 1415fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle bool profile_saved_to_disk = ProcessProfilingInfo(&new_methods); 1425fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Update the notification counter based on result. Note that there might be contention on this 1435fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // but we don't care about to be 100% precise. 1445fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle if (!profile_saved_to_disk) { 1455fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // If we didn't save to disk it may be because we didn't have enough new methods. 1465fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Set the jit activity notifications to new_methods so we can wake up earlier if needed. 1475fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle jit_activity_notifications_ = new_methods; 1484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 1495fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_ns_of_work_ += NanoTime() - start_work; 1505fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle } 1515fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle} 152c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle 1535fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravlevoid ProfileSaver::NotifyJitActivity() { 1545fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 1555fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle if (instance_ == nullptr || instance_->shutting_down_) { 1565fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle return; 1575fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle } 1585fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle instance_->NotifyJitActivityInternal(); 1595fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle} 1605fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle 1615fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravlevoid ProfileSaver::WakeUpSaver() { 1625fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle jit_activity_notifications_ = 0; 1635fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle last_time_ns_saver_woke_up_ = NanoTime(); 1645fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle period_condition_.Signal(Thread::Current()); 1655fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle} 1665fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle 1675fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravlevoid ProfileSaver::NotifyJitActivityInternal() { 1685fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Unlikely to overflow but if it happens, 1695fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // we would have waken up the saver long before that. 1705fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle jit_activity_notifications_++; 1715fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Note that we are not as precise as we could be here but we don't want to wake the saver 1725fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // every time we see a hot method. 1735fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle if (jit_activity_notifications_ > kMinimumNumberOfNotificationBeforeWake) { 1745fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle MutexLock wait_mutex(Thread::Current(), wait_lock_); 1755fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle if ((NanoTime() - last_time_ns_saver_woke_up_) > kMinSavePeriodNs) { 1765fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle WakeUpSaver(); 1775fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle } 1785fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle } else if (jit_activity_notifications_ > kMaximumNumberOfNotificationBeforeWake) { 1795fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // Make sure to wake up the saver if we see a spike in the number of notifications. 1805fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // This is a precaution to avoid "loosing" a big number of methods in case 1815fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle // this is a spike with no jit after. 1825fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle total_number_of_hot_spikes_++; 1835fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle MutexLock wait_mutex(Thread::Current(), wait_lock_); 1845fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle WakeUpSaver(); 1854d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 1864d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 1874d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 18885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin JuravleProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) { 18985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle auto info_it = profile_cache_.find(filename); 19085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle if (info_it == profile_cache_.end()) { 19185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle info_it = profile_cache_.Put(filename, ProfileCompilationInfo()); 19285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle } 19385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle return &info_it->second; 19485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle} 19585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle 196c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier// Get resolved methods that have a profile info or more than kStartupMethodSamples samples. 197c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier// Excludes native methods and classes in the boot image. 198c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartierclass GetMethodsVisitor : public ClassVisitor { 199c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier public: 200c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier explicit GetMethodsVisitor(std::vector<MethodReference>* methods) : methods_(methods) {} 201c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier 202c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier virtual bool operator()(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_) { 203c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { 204c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier return true; 205c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 206c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier for (ArtMethod& method : klass->GetMethods(sizeof(void*))) { 207c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier if (!method.IsNative()) { 208c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier if (method.GetCounter() >= kStartupMethodSamples || 209c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier method.GetProfilingInfo(sizeof(void*)) != nullptr) { 210c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier // Have samples, add to profile. 211c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier const DexFile* dex_file = method.GetInterfaceMethodIfProxy(sizeof(void*))->GetDexFile(); 212c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier methods_->push_back(MethodReference(dex_file, method.GetDexMethodIndex())); 213c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 214c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 215c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 216c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier return true; 217c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 218c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier 219c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier private: 220c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier std::vector<MethodReference>* const methods_; 221c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier}; 222c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier 223c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartiervoid ProfileSaver::FetchAndCacheResolvedClassesAndMethods() { 224dabdc0fe183d4684f3cf4d70cb09d318cff81b42Mathieu Chartier ScopedTrace trace(__PRETTY_FUNCTION__); 22585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); 22685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle std::set<DexCacheResolvedClasses> resolved_classes = 22785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle class_linker->GetResolvedClasses(/*ignore boot classes*/ true); 228c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier 229c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier std::vector<MethodReference> methods; 230c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier { 231c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier ScopedTrace trace2("Get hot methods"); 232c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier GetMethodsVisitor visitor(&methods); 233c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier ScopedObjectAccess soa(Thread::Current()); 234c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier class_linker->VisitClasses(&visitor); 235c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier VLOG(profiler) << "Methods with samples greater than " 236c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier << kStartupMethodSamples << " = " << methods.size(); 237c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 23885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 23985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle uint64_t total_number_of_profile_entries_cached = 0; 2409275af6ec0d71d1a13a97a1d292806b73f755717Mathieu Chartier 24185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle for (const auto& it : tracked_dex_base_locations_) { 2429275af6ec0d71d1a13a97a1d292806b73f755717Mathieu Chartier std::set<DexCacheResolvedClasses> resolved_classes_for_location; 24385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle const std::string& filename = it.first; 24485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle const std::set<std::string>& locations = it.second; 245c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier std::vector<MethodReference> methods_for_location; 246c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier for (const MethodReference& ref : methods) { 247c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) { 248c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier methods_for_location.push_back(ref); 249c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 250c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier } 25185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle for (const DexCacheResolvedClasses& classes : resolved_classes) { 2529275af6ec0d71d1a13a97a1d292806b73f755717Mathieu Chartier if (locations.find(classes.GetBaseLocation()) != locations.end()) { 253c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier VLOG(profiler) << "Added " << classes.GetClasses().size() << " classes for location " 254c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier << classes.GetBaseLocation() << " (" << classes.GetDexLocation() << ")"; 25585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle resolved_classes_for_location.insert(classes); 2569275af6ec0d71d1a13a97a1d292806b73f755717Mathieu Chartier } else { 2579275af6ec0d71d1a13a97a1d292806b73f755717Mathieu Chartier VLOG(profiler) << "Location not found " << classes.GetBaseLocation() 2589275af6ec0d71d1a13a97a1d292806b73f755717Mathieu Chartier << " (" << classes.GetDexLocation() << ")"; 25985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle } 26085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle } 26185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle ProfileCompilationInfo* info = GetCachedProfiledInfo(filename); 262c600eaa1089342db81ac1869437199efc1f6053bMathieu Chartier info->AddMethodsAndClasses(methods_for_location, resolved_classes_for_location); 26385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_number_of_profile_entries_cached += resolved_classes_for_location.size(); 2644d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 26585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle max_number_of_profile_entries_cached_ = std::max( 26685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle max_number_of_profile_entries_cached_, 26785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_number_of_profile_entries_cached); 26885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle} 2694d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 2705fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravlebool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) { 27185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle ScopedTrace trace(__PRETTY_FUNCTION__); 272b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle SafeMap<std::string, std::set<std::string>> tracked_locations; 2734d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 274b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // Make a copy so that we don't hold the lock while doing I/O. 275b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 276b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle tracked_locations = tracked_dex_base_locations_; 2774d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 278c15e566b36170237f01ccefc12129c1578a02140Calin Juravle 27985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle bool profile_file_saved = false; 28085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle uint64_t total_number_of_profile_entries_cached = 0; 2815fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle *new_methods = 0; 2825fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle 283b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle for (const auto& it : tracked_locations) { 284b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle if (ShuttingDown(Thread::Current())) { 285b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle return true; 286b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } 287b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle const std::string& filename = it.first; 288b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle const std::set<std::string>& locations = it.second; 289e2d066d0337b7c81d47e4806e6025b70d83fcd56Calin Juravle std::vector<MethodReference> methods; 290b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle { 291b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle ScopedObjectAccess soa(Thread::Current()); 292e2d066d0337b7c81d47e4806e6025b70d83fcd56Calin Juravle jit_code_cache_->GetProfiledMethods(locations, methods); 293c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_number_of_code_cache_queries_++; 294b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } 295c15e566b36170237f01ccefc12129c1578a02140Calin Juravle 29685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle ProfileCompilationInfo* cached_info = GetCachedProfiledInfo(filename); 29785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle cached_info->AddMethodsAndClasses(methods, std::set<DexCacheResolvedClasses>()); 2980cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle int64_t delta_number_of_methods = 2990cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle cached_info->GetNumberOfMethods() - 3000cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle static_cast<int64_t>(last_save_number_of_methods_); 3010cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle int64_t delta_number_of_classes = 3020cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle cached_info->GetNumberOfResolvedClasses() - 3030cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle static_cast<int64_t>(last_save_number_of_classes_); 30485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle 30585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle if (delta_number_of_methods < kMinimumNumberOfMethodsToSave && 30685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle delta_number_of_classes < kMinimumNumberOfClassesToSave) { 3070cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle VLOG(profiler) << "Not enough information to save to: " << filename 30885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << " Nr of methods: " << delta_number_of_methods 30985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << " Nr of classes: " << delta_number_of_classes; 310c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_number_of_skipped_writes_++; 31185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle continue; 312b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } 3135fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle *new_methods = std::max(static_cast<uint16_t>(delta_number_of_methods), *new_methods); 314c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle uint64_t bytes_written; 315fe297a96bc6d3da11579709add9b4568730d2b4fCalin Juravle // Force the save. In case the profile data is corrupted or the the profile 316fe297a96bc6d3da11579709add9b4568730d2b4fCalin Juravle // has the wrong version this will "fix" the file to the correct format. 317fe297a96bc6d3da11579709add9b4568730d2b4fCalin Juravle if (cached_info->MergeAndSave(filename, &bytes_written, /*force*/ true)) { 31885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle last_save_number_of_methods_ = cached_info->GetNumberOfMethods(); 3190cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle last_save_number_of_classes_ = cached_info->GetNumberOfResolvedClasses(); 32085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle // Clear resolved classes. No need to store them around as 32185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle // they don't change after the first write. 32285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle cached_info->ClearResolvedClasses(); 323c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (bytes_written > 0) { 324c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_number_of_writes_++; 325c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle total_bytes_written_ += bytes_written; 3260cdaa6cdbeadceaee3a1acc641e7cc2548e125d9Calin Juravle profile_file_saved = true; 32785f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle } else { 32885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle // At this point we could still have avoided the write. 32985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle // We load and merge the data from the file lazily at its first ever 33085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle // save attempt. So, whatever we are trying to save could already be 33185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle // in the file. 33285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_number_of_skipped_writes_++; 333c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 33485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle } else { 33585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle LOG(WARNING) << "Could not save profiling info to " << filename; 33685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_number_of_failed_writes_++; 337b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } 33885f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_number_of_profile_entries_cached += 33985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle cached_info->GetNumberOfMethods() + 34085f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle cached_info->GetNumberOfResolvedClasses(); 341b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } 34285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle max_number_of_profile_entries_cached_ = std::max( 34385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle max_number_of_profile_entries_cached_, 34485f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle total_number_of_profile_entries_cached); 34585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle return profile_file_saved; 3464d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 3474d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlevoid* ProfileSaver::RunProfileSaverThread(void* arg) { 3494d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle Runtime* runtime = Runtime::Current(); 3504d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 351e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle bool attached = runtime->AttachCurrentThread("Profile Saver", 352e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle /*as_daemon*/true, 353e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle runtime->GetSystemThreadGroup(), 354e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle /*create_peer*/true); 355e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle if (!attached) { 356e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle CHECK(runtime->IsShuttingDown(Thread::Current())); 357e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle return nullptr; 358e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle } 359e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle 360e55fda1373abad5ace4409453c51aeb0daaf99efCalin Juravle ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg); 3614d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profile_saver->Run(); 3624d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3634d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle runtime->DetachCurrentThread(); 3644d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle VLOG(profiler) << "Profile saver shutdown"; 3654d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return nullptr; 3664d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 3674d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3686044fa747867413912d0de3049dc570c769d3cf8Calin Juravlestatic bool ShouldProfileLocation(const std::string& location) { 3697506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager(); 3707506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location); 3716044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (oat_file == nullptr) { 3726044fa747867413912d0de3049dc570c769d3cf8Calin Juravle // This can happen if we fallback to run code directly from the APK. 3736044fa747867413912d0de3049dc570c769d3cf8Calin Juravle // Profile it with the hope that the background dexopt will get us back into 3746044fa747867413912d0de3049dc570c769d3cf8Calin Juravle // a good state. 3757506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle VLOG(profiler) << "Asked to profile a location without an oat file:" << location; 3766044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return true; 3776044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 3786044fa747867413912d0de3049dc570c769d3cf8Calin Juravle CompilerFilter::Filter filter = oat_file->GetCompilerFilter(); 379d19dc4688b5b93f149d45435deb0a67217464e37Calin Juravle if ((filter == CompilerFilter::kSpeed) || (filter == CompilerFilter::kEverything)) { 3807506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle VLOG(profiler) 381d19dc4688b5b93f149d45435deb0a67217464e37Calin Juravle << "Skip profiling oat file because it's already speed|everything compiled: " 382d19dc4688b5b93f149d45435deb0a67217464e37Calin Juravle << location << " oat location: " << oat_file->GetLocation(); 3836044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return false; 3846044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 3856044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return true; 3866044fa747867413912d0de3049dc570c769d3cf8Calin Juravle} 3876044fa747867413912d0de3049dc570c769d3cf8Calin Juravle 3884d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlevoid ProfileSaver::Start(const std::string& output_filename, 3894d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle jit::JitCodeCache* jit_code_cache, 39086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::vector<std::string>& code_paths, 39186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& foreign_dex_profile_path, 39286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle const std::string& app_data_dir) { 393e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle DCHECK(Runtime::Current()->SaveProfileInfo()); 3944d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(!output_filename.empty()); 3954d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(jit_code_cache != nullptr); 3964d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 3976044fa747867413912d0de3049dc570c769d3cf8Calin Juravle std::vector<std::string> code_paths_to_profile; 3986044fa747867413912d0de3049dc570c769d3cf8Calin Juravle 3996044fa747867413912d0de3049dc570c769d3cf8Calin Juravle for (const std::string& location : code_paths) { 4006044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (ShouldProfileLocation(location)) { 4016044fa747867413912d0de3049dc570c769d3cf8Calin Juravle code_paths_to_profile.push_back(location); 4026044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 4036044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 4046044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (code_paths_to_profile.empty()) { 4057506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle VLOG(profiler) << "No code paths should be profiled."; 4066044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return; 4076044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 4086044fa747867413912d0de3049dc570c769d3cf8Calin Juravle 4094d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 4104d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle if (instance_ != nullptr) { 411b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // If we already have an instance, make sure it uses the same jit_code_cache. 412b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // This may be called multiple times via Runtime::registerAppInfo (e.g. for 413b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // apps which share the same runtime). 414b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache); 415b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle // Add the code_paths to the tracked locations. 41620ae79370a14c17dfb037914995d6430774fe492Calin Juravle instance_->AddTrackedLocations(output_filename, app_data_dir, code_paths_to_profile); 4174d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return; 4184d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 4194d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4204d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle VLOG(profiler) << "Starting profile saver using output file: " << output_filename 4217506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle << ". Tracking: " << Join(code_paths_to_profile, ':'); 4224d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 42386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle instance_ = new ProfileSaver(output_filename, 42486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle jit_code_cache, 4257506423b2b9ea13fc5fa9711ab0106977876a5a2Calin Juravle code_paths_to_profile, 42686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle foreign_dex_profile_path, 42786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle app_data_dir); 4284d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4294d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle // Create a new thread which does the saving. 4304d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle CHECK_PTHREAD_CALL( 4314d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle pthread_create, 4324d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)), 4334d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle "Profile saver thread"); 4344d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 4354d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 436c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::Stop(bool dump_info) { 4374d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle ProfileSaver* profile_saver = nullptr; 4384d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle pthread_t profiler_pthread = 0U; 4394d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4404d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 4414d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_); 442b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle VLOG(profiler) << "Stopping profile saver thread"; 4434d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profile_saver = instance_; 4444d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profiler_pthread = profiler_pthread_; 4454d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle if (instance_ == nullptr) { 4464d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(false) << "Tried to stop a profile saver which was not started"; 4474d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return; 4484d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 4494d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle if (instance_->shutting_down_) { 4504d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle DCHECK(false) << "Tried to stop the profile saver twice"; 4514d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return; 4524d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 4534d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle instance_->shutting_down_ = true; 454c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (dump_info) { 455c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle instance_->DumpInfo(LOG(INFO)); 456c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 4574d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 4584d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4594d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 4604d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle // Wake up the saver thread if it is sleeping to allow for a clean exit. 4614d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_); 4624d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profile_saver->period_condition_.Signal(Thread::Current()); 4634d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 4644d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4654d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle // Wait for the saver thread to stop. 4664d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown"); 4674d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4684d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle { 4694d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_); 4704d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle instance_ = nullptr; 4714d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle profiler_pthread_ = 0U; 4724d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle } 4734d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle delete profile_saver; 4744d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 4754d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4764d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlebool ProfileSaver::ShuttingDown(Thread* self) { 4774d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock mu(self, *Locks::profiler_lock_); 4784d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return shutting_down_; 4794d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 4804d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 4814d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravlebool ProfileSaver::IsStarted() { 4824d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 4834d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle return instance_ != nullptr; 4844d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} 4854d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle 486b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravlevoid ProfileSaver::AddTrackedLocations(const std::string& output_filename, 48720ae79370a14c17dfb037914995d6430774fe492Calin Juravle const std::string& app_data_dir, 488b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle const std::vector<std::string>& code_paths) { 489b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle auto it = tracked_dex_base_locations_.find(output_filename); 490b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle if (it == tracked_dex_base_locations_.end()) { 491b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle tracked_dex_base_locations_.Put(output_filename, 492b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle std::set<std::string>(code_paths.begin(), code_paths.end())); 493655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (!app_data_dir.empty()) { 494655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle app_data_dirs_.insert(app_data_dir); 495655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 496b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } else { 497b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle it->second.insert(code_paths.begin(), code_paths.end()); 498b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle } 499b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle} 500b4eddd21c364c51b6fc5c439cda6958ae255dcd5Calin Juravle 501655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle// TODO(calin): This may lead to several calls to realpath. 502655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle// Consider moving the logic to the saver thread (i.e. when notified, 503655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle// only cache the location, and then wake up the saver thread to do the 504655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle// comparisons with the real file paths and to create the markers). 50586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravlevoid ProfileSaver::NotifyDexUse(const std::string& dex_location) { 5066044fa747867413912d0de3049dc570c769d3cf8Calin Juravle if (!ShouldProfileLocation(dex_location)) { 5076044fa747867413912d0de3049dc570c769d3cf8Calin Juravle return; 5086044fa747867413912d0de3049dc570c769d3cf8Calin Juravle } 50986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle std::set<std::string> app_code_paths; 51086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle std::string foreign_dex_profile_path; 51120ae79370a14c17dfb037914995d6430774fe492Calin Juravle std::set<std::string> app_data_dirs; 51286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle { 51386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 514c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (instance_ == nullptr) { 515c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return; 516c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 51786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // Make a copy so that we don't hold the lock while doing I/O. 51886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle for (const auto& it : instance_->tracked_dex_base_locations_) { 51986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle app_code_paths.insert(it.second.begin(), it.second.end()); 52086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 52186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle foreign_dex_profile_path = instance_->foreign_dex_profile_path_; 52220ae79370a14c17dfb037914995d6430774fe492Calin Juravle app_data_dirs.insert(instance_->app_data_dirs_.begin(), instance_->app_data_dirs_.end()); 52386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 52486a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 525c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle bool mark_created = MaybeRecordDexUseInternal(dex_location, 526c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle app_code_paths, 527c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle foreign_dex_profile_path, 52820ae79370a14c17dfb037914995d6430774fe492Calin Juravle app_data_dirs); 529c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (mark_created) { 530c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 531c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (instance_ != nullptr) { 532c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle instance_->total_number_of_foreign_dex_marks_++; 533c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 534c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 53586a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle} 53686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 537655c3c317973c7e4a844a767dda31bc38727a248Calin Juravlestatic bool CheckContainsWithRealPath(const std::set<std::string>& paths_set, 538655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle const std::string& path_to_check) { 539655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle for (const auto& path : paths_set) { 540655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle UniqueCPtr<const char[]> real_path(realpath(path.c_str(), nullptr)); 541655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (real_path == nullptr) { 542655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle PLOG(WARNING) << "Could not get realpath for " << path; 543655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle continue; 5441fae45f7d777e3971b916dda531c8648304866c8Calin Juravle } 545655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle std::string real_path_str(real_path.get()); 546655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (real_path_str == path_to_check) { 547655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return true; 54886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 54986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 550655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 551655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle} 55286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 553655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle// After the call, dex_location_real_path will contain the marker's name. 554655c3c317973c7e4a844a767dda31bc38727a248Calin Juravlestatic bool CreateForeignDexMarker(const std::string& foreign_dex_profile_path, 555655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle /*in-out*/ std::string* dex_location_real_path) { 55686a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // For foreign dex files we record a flag on disk. PackageManager will (potentially) take this 55786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // into account when deciding how to optimize the loaded dex file. 55886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // The expected flag name is the canonical path of the apk where '/' is substituted to '@'. 55986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // (it needs to be kept in sync with 56086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle // frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java) 561655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle std::replace(dex_location_real_path->begin(), dex_location_real_path->end(), '/', '@'); 562655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle std::string flag_path = foreign_dex_profile_path + "/" + *dex_location_real_path; 56312e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler // We use O_RDONLY as the access mode because we must supply some access 56412e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler // mode, and there is no access mode that means 'create but do not read' the 56512e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler // file. We will not not actually read from the file. 56612e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler int fd = TEMP_FAILURE_RETRY(open(flag_path.c_str(), 56712e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler O_CREAT | O_RDONLY | O_EXCL | O_CLOEXEC | O_NOFOLLOW, 0)); 56886a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (fd != -1) { 56986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle if (close(fd) != 0) { 57086a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle PLOG(WARNING) << "Could not close file after flagging foreign dex use " << flag_path; 57186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 572c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return true; 57386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } else { 57412e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler if (errno != EEXIST && errno != EACCES) { 57512e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler // Another app could have already created the file, and selinux may not 57612e4157666bfdc2ca38f459f6447385b80c7ddffRichard Uhler // allow the read access to the file implied by the call to open. 57786a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle PLOG(WARNING) << "Could not create foreign dex use mark " << flag_path; 578c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return false; 57986a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 580c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle return true; 58186a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle } 58286a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle} 58386a9ebe4197e963249ffbbaa1830da97ed642fa5Calin Juravle 584655c3c317973c7e4a844a767dda31bc38727a248Calin Juravlebool ProfileSaver::MaybeRecordDexUseInternal( 585655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle const std::string& dex_location, 586655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle const std::set<std::string>& app_code_paths, 587655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle const std::string& foreign_dex_profile_path, 588655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle const std::set<std::string>& app_data_dirs) { 589655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (dex_location.empty()) { 590655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle LOG(WARNING) << "Asked to record foreign dex use with an empty dex location."; 591655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 592655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 593655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (foreign_dex_profile_path.empty()) { 594655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle LOG(WARNING) << "Asked to record foreign dex use without a valid profile path "; 595655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 596655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 597655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 598655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (app_code_paths.find(dex_location) != app_code_paths.end()) { 599655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // The dex location belongs to the application code paths. Nothing to record. 600655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 601655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 602655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 603655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (app_data_dirs.find(dex_location) != app_data_dirs.end()) { 604655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // The dex location is under the application folder. Nothing to record. 605655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 606655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 607655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 608655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // Do another round of checks with the real paths. 609655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // Application directory could be a symlink (e.g. /data/data instead of /data/user/0), and we 610655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // don't have control over how the dex files are actually loaded (symlink or canonical path), 611655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 612655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // Note that we could cache all the real locations in the saver (since it's an expensive 613655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // operation). However we expect that app_code_paths is small (usually 1 element), and 614655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise 615655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle // to save some bytes of memory usage. 616655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 617655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr)); 618655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (dex_location_real_path == nullptr) { 619655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle PLOG(WARNING) << "Could not get realpath for " << dex_location; 620655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 621655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 622655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle std::string dex_location_real_path_str(dex_location_real_path.get()); 623655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 624655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (CheckContainsWithRealPath(app_code_paths, dex_location_real_path_str)) { 625655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 626655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 627655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 628655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle if (CheckContainsWithRealPath(app_data_dirs, dex_location_real_path_str)) { 629655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return false; 630655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle } 631655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 632655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle return CreateForeignDexMarker(foreign_dex_profile_path, &dex_location_real_path_str); 633655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle} 634655c3c317973c7e4a844a767dda31bc38727a248Calin Juravle 635c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::DumpInstanceInfo(std::ostream& os) { 636c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 637c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle if (instance_ != nullptr) { 638c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle instance_->DumpInfo(os); 639c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle } 640c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle} 641c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle 642c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravlevoid ProfileSaver::DumpInfo(std::ostream& os) { 643c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle os << "ProfileSaver total_bytes_written=" << total_bytes_written_ << '\n' 644c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle << "ProfileSaver total_number_of_writes=" << total_number_of_writes_ << '\n' 64585f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver total_number_of_code_cache_queries=" 64685f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << total_number_of_code_cache_queries_ << '\n' 647c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle << "ProfileSaver total_number_of_skipped_writes=" << total_number_of_skipped_writes_ << '\n' 648c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle << "ProfileSaver total_number_of_failed_writes=" << total_number_of_failed_writes_ << '\n' 64985f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver total_ms_of_sleep=" << total_ms_of_sleep_ << '\n' 6506044fa747867413912d0de3049dc570c769d3cf8Calin Juravle << "ProfileSaver total_ms_of_work=" << NsToMs(total_ns_of_work_) << '\n' 65185f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver total_number_of_foreign_dex_marks=" 65285f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << total_number_of_foreign_dex_marks_ << '\n' 65385f7bf3bbfa17d65ff77e3e826b5f7aff45838a9Calin Juravle << "ProfileSaver max_number_profile_entries_cached=" 6545fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle << max_number_of_profile_entries_cached_ << '\n' 6555fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle << "ProfileSaver total_number_of_hot_spikes=" << total_number_of_hot_spikes_ << '\n' 6565fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle << "ProfileSaver total_number_of_wake_ups=" << total_number_of_wake_ups_ << '\n'; 657c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle} 658c19c1c2e1def1f4f5ab5fd9e71b1a6f76d42988fCalin Juravle 659e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle 660e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravlevoid ProfileSaver::ForceProcessProfiles() { 661e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle ProfileSaver* saver = nullptr; 662e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle { 663e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 664e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle saver = instance_; 665e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle } 666e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle // TODO(calin): this is not actually thread safe as the instance_ may have been deleted, 667e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle // but we only use this in testing when we now this won't happen. 668e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle // Refactor the way we handle the instance so that we don't end up in this situation. 669e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle if (saver != nullptr) { 6705fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle uint16_t new_methods; 6715fbb0fe0625a1f76aa33cd78ccf1a17b00d8f6d1Calin Juravle saver->ProcessProfilingInfo(&new_methods); 672e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle } 673e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle} 674e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle 675e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravlebool ProfileSaver::HasSeenMethod(const std::string& profile, 676e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle const DexFile* dex_file, 677e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle uint16_t method_idx) { 678e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 679e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle if (instance_ != nullptr) { 680e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle ProfileCompilationInfo* info = instance_->GetCachedProfiledInfo(profile); 681e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle if (info != nullptr) { 682e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle return info->ContainsMethod(MethodReference(dex_file, method_idx)); 683e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle } 684e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle } 685e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle return false; 686e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle} 687e5de54cfab5f14ba0b8ff25d8d60901c7021943fCalin Juravle 6884d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle} // namespace art 689