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