blob: 11d601e8c811e8c44b6683238d576440e340c34d [file] [log] [blame]
Calin Juravle4d77b6a2015-12-01 18:38:09 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "profile_saver.h"
18
Calin Juravle86a9ebe2016-02-24 10:13:09 +000019#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22
Calin Juravle4d77b6a2015-12-01 18:38:09 +000023#include "art_method-inl.h"
Andreas Gampe542451c2016-07-26 09:02:02 -070024#include "base/enums.h"
Mathieu Chartierdabdc0f2016-03-04 14:58:03 -080025#include "base/systrace.h"
Calin Juravle6044fa72016-03-25 17:17:09 +000026#include "base/time_utils.h"
27#include "compiler_filter.h"
Calin Juravle4d77b6a2015-12-01 18:38:09 +000028#include "oat_file_manager.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070029#include "scoped_thread_state_change-inl.h"
Calin Juravle6044fa72016-03-25 17:17:09 +000030
Calin Juravle4d77b6a2015-12-01 18:38:09 +000031
32namespace art {
33
Calin Juravle4d77b6a2015-12-01 18:38:09 +000034ProfileSaver* ProfileSaver::instance_ = nullptr;
35pthread_t ProfileSaver::profiler_pthread_ = 0U;
36
Calin Juravle138dbff2016-06-28 19:36:58 +010037ProfileSaver::ProfileSaver(const ProfileSaverOptions& options,
38 const std::string& output_filename,
Calin Juravle4d77b6a2015-12-01 18:38:09 +000039 jit::JitCodeCache* jit_code_cache,
Calin Juravle86a9ebe2016-02-24 10:13:09 +000040 const std::vector<std::string>& code_paths,
41 const std::string& foreign_dex_profile_path,
42 const std::string& app_data_dir)
Calin Juravleb4eddd22016-01-13 15:52:33 -080043 : jit_code_cache_(jit_code_cache),
Calin Juravle86a9ebe2016-02-24 10:13:09 +000044 foreign_dex_profile_path_(foreign_dex_profile_path),
Calin Juravle4d77b6a2015-12-01 18:38:09 +000045 shutting_down_(false),
Calin Juravle85f7bf32016-03-18 16:23:40 +000046 last_save_number_of_methods_(0),
Calin Juravle0cdaa6c2016-03-30 18:18:58 +010047 last_save_number_of_classes_(0),
Calin Juravle5fbb0fe2016-04-29 16:44:11 +010048 last_time_ns_saver_woke_up_(0),
49 jit_activity_notifications_(0),
Calin Juravle4d77b6a2015-12-01 18:38:09 +000050 wait_lock_("ProfileSaver wait lock"),
Calin Juravlec19c1c22016-03-09 15:37:48 +000051 period_condition_("ProfileSaver period condition", wait_lock_),
52 total_bytes_written_(0),
53 total_number_of_writes_(0),
54 total_number_of_code_cache_queries_(0),
55 total_number_of_skipped_writes_(0),
56 total_number_of_failed_writes_(0),
Calin Juravle85f7bf32016-03-18 16:23:40 +000057 total_ms_of_sleep_(0),
Calin Juravlec19c1c22016-03-09 15:37:48 +000058 total_ns_of_work_(0),
Calin Juravle85f7bf32016-03-18 16:23:40 +000059 total_number_of_foreign_dex_marks_(0),
Calin Juravle5fbb0fe2016-04-29 16:44:11 +010060 max_number_of_profile_entries_cached_(0),
61 total_number_of_hot_spikes_(0),
Calin Juravle138dbff2016-06-28 19:36:58 +010062 total_number_of_wake_ups_(0),
63 options_(options) {
64 DCHECK(options_.IsEnabled());
Calin Juravle20ae7932016-04-18 18:59:22 +010065 AddTrackedLocations(output_filename, app_data_dir, code_paths);
Calin Juravle4d77b6a2015-12-01 18:38:09 +000066}
67
68void ProfileSaver::Run() {
Calin Juravle4d77b6a2015-12-01 18:38:09 +000069 Thread* self = Thread::Current();
70
Calin Juravle5fbb0fe2016-04-29 16:44:11 +010071 // Fetch the resolved classes for the app images after sleeping for
Calin Juravle138dbff2016-06-28 19:36:58 +010072 // options_.GetSaveResolvedClassesDelayMs().
Calin Juravle5fbb0fe2016-04-29 16:44:11 +010073 // TODO(calin) This only considers the case of the primary profile file.
74 // Anything that gets loaded in the same VM will not have their resolved
75 // classes save (unless they started before the initial saving was done).
76 {
77 MutexLock mu(self, wait_lock_);
Calin Juravle138dbff2016-06-28 19:36:58 +010078 const uint64_t end_time = NanoTime() + MsToNs(options_.GetSaveResolvedClassesDelayMs());
Mathieu Chartier0ec065d2016-05-18 19:51:23 -070079 while (true) {
80 const uint64_t current_time = NanoTime();
81 if (current_time >= end_time) {
82 break;
83 }
84 period_condition_.TimedWait(self, NsToMs(end_time - current_time), 0);
85 }
Calin Juravle138dbff2016-06-28 19:36:58 +010086 total_ms_of_sleep_ += options_.GetSaveResolvedClassesDelayMs();
Calin Juravle5fbb0fe2016-04-29 16:44:11 +010087 }
Mathieu Chartierc600eaa2016-05-18 08:51:52 -070088 FetchAndCacheResolvedClassesAndMethods();
Calin Juravle5fbb0fe2016-04-29 16:44:11 +010089
90 // Loop for the profiled methods.
Mathieu Chartier8913fc12015-12-09 16:38:30 -080091 while (!ShuttingDown(self)) {
Calin Juravle5fbb0fe2016-04-29 16:44:11 +010092 uint64_t sleep_start = NanoTime();
Calin Juravle4d77b6a2015-12-01 18:38:09 +000093 {
Calin Juravle0233a412016-05-18 15:49:36 -070094 uint64_t sleep_time = 0;
95 {
96 MutexLock mu(self, wait_lock_);
97 period_condition_.Wait(self);
Calin Juravledc85bd72016-05-25 18:09:53 +010098 sleep_time = NanoTime() - sleep_start;
Calin Juravle0233a412016-05-18 15:49:36 -070099 }
100 // Check if the thread was woken up for shutdown.
101 if (ShuttingDown(self)) {
102 break;
103 }
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100104 total_number_of_wake_ups_++;
105 // We might have been woken up by a huge number of notifications to guarantee saving.
106 // If we didn't meet the minimum saving period go back to sleep (only if missed by
107 // a reasonable margin).
Calin Juravle138dbff2016-06-28 19:36:58 +0100108 uint64_t min_save_period_ns = MsToNs(options_.GetMinSavePeriodMs());
109 while (min_save_period_ns * 0.9 > sleep_time) {
Calin Juravle0233a412016-05-18 15:49:36 -0700110 {
111 MutexLock mu(self, wait_lock_);
Calin Juravle138dbff2016-06-28 19:36:58 +0100112 period_condition_.TimedWait(self, NsToMs(min_save_period_ns - sleep_time), 0);
Calin Juravledc85bd72016-05-25 18:09:53 +0100113 sleep_time = NanoTime() - sleep_start;
Calin Juravle0233a412016-05-18 15:49:36 -0700114 }
115 // Check if the thread was woken up for shutdown.
116 if (ShuttingDown(self)) {
117 break;
118 }
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100119 total_number_of_wake_ups_++;
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100120 }
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000121 }
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100122 total_ms_of_sleep_ += NsToMs(NanoTime() - sleep_start);
123
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000124 if (ShuttingDown(self)) {
125 break;
126 }
127
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100128 uint16_t new_methods = 0;
129 uint64_t start_work = NanoTime();
130 bool profile_saved_to_disk = ProcessProfilingInfo(&new_methods);
131 // Update the notification counter based on result. Note that there might be contention on this
132 // but we don't care about to be 100% precise.
133 if (!profile_saved_to_disk) {
134 // If we didn't save to disk it may be because we didn't have enough new methods.
135 // Set the jit activity notifications to new_methods so we can wake up earlier if needed.
136 jit_activity_notifications_ = new_methods;
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000137 }
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100138 total_ns_of_work_ += NanoTime() - start_work;
139 }
140}
Calin Juravlec19c1c22016-03-09 15:37:48 +0000141
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100142void ProfileSaver::NotifyJitActivity() {
143 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
144 if (instance_ == nullptr || instance_->shutting_down_) {
145 return;
146 }
147 instance_->NotifyJitActivityInternal();
148}
149
150void ProfileSaver::WakeUpSaver() {
151 jit_activity_notifications_ = 0;
152 last_time_ns_saver_woke_up_ = NanoTime();
153 period_condition_.Signal(Thread::Current());
154}
155
156void ProfileSaver::NotifyJitActivityInternal() {
157 // Unlikely to overflow but if it happens,
158 // we would have waken up the saver long before that.
159 jit_activity_notifications_++;
160 // Note that we are not as precise as we could be here but we don't want to wake the saver
161 // every time we see a hot method.
Calin Juravle138dbff2016-06-28 19:36:58 +0100162 if (jit_activity_notifications_ > options_.GetMinNotificationBeforeWake()) {
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100163 MutexLock wait_mutex(Thread::Current(), wait_lock_);
Calin Juravle138dbff2016-06-28 19:36:58 +0100164 if ((NanoTime() - last_time_ns_saver_woke_up_) > MsToNs(options_.GetMinSavePeriodMs())) {
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100165 WakeUpSaver();
Serguei Katkov87de9cf2016-08-01 17:47:04 +0700166 } else if (jit_activity_notifications_ > options_.GetMaxNotificationBeforeWake()) {
167 // Make sure to wake up the saver if we see a spike in the number of notifications.
168 // This is a precaution to avoid losing a big number of methods in case
169 // this is a spike with no jit after.
170 total_number_of_hot_spikes_++;
171 WakeUpSaver();
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100172 }
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000173 }
174}
175
Calin Juravle85f7bf32016-03-18 16:23:40 +0000176ProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) {
177 auto info_it = profile_cache_.find(filename);
178 if (info_it == profile_cache_.end()) {
179 info_it = profile_cache_.Put(filename, ProfileCompilationInfo());
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000180 }
Calin Juravle85f7bf32016-03-18 16:23:40 +0000181 return &info_it->second;
182}
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000183
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700184// Get resolved methods that have a profile info or more than kStartupMethodSamples samples.
185// Excludes native methods and classes in the boot image.
186class GetMethodsVisitor : public ClassVisitor {
187 public:
Calin Juravle138dbff2016-06-28 19:36:58 +0100188 GetMethodsVisitor(std::vector<MethodReference>* methods, uint32_t startup_method_samples)
189 : methods_(methods),
190 startup_method_samples_(startup_method_samples) {}
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700191
Mathieu Chartier28357fa2016-10-18 16:27:40 -0700192 virtual bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700193 if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
194 return true;
195 }
Andreas Gampe542451c2016-07-26 09:02:02 -0700196 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700197 if (!method.IsNative()) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100198 if (method.GetCounter() >= startup_method_samples_ ||
Andreas Gampe542451c2016-07-26 09:02:02 -0700199 method.GetProfilingInfo(kRuntimePointerSize) != nullptr) {
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700200 // Have samples, add to profile.
Andreas Gampe542451c2016-07-26 09:02:02 -0700201 const DexFile* dex_file =
202 method.GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetDexFile();
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700203 methods_->push_back(MethodReference(dex_file, method.GetDexMethodIndex()));
204 }
205 }
206 }
207 return true;
208 }
209
210 private:
211 std::vector<MethodReference>* const methods_;
Calin Juravle138dbff2016-06-28 19:36:58 +0100212 uint32_t startup_method_samples_;
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700213};
214
215void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
Calin Juravle85f7bf32016-03-18 16:23:40 +0000216 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle85f7bf32016-03-18 16:23:40 +0000217 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
218 std::set<DexCacheResolvedClasses> resolved_classes =
219 class_linker->GetResolvedClasses(/*ignore boot classes*/ true);
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700220
221 std::vector<MethodReference> methods;
222 {
223 ScopedTrace trace2("Get hot methods");
Calin Juravle138dbff2016-06-28 19:36:58 +0100224 GetMethodsVisitor visitor(&methods, options_.GetStartupMethodSamples());
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700225 ScopedObjectAccess soa(Thread::Current());
226 class_linker->VisitClasses(&visitor);
227 VLOG(profiler) << "Methods with samples greater than "
Calin Juravle138dbff2016-06-28 19:36:58 +0100228 << options_.GetStartupMethodSamples() << " = " << methods.size();
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700229 }
Calin Juravle85f7bf32016-03-18 16:23:40 +0000230 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
231 uint64_t total_number_of_profile_entries_cached = 0;
Mathieu Chartier9275af62016-04-29 12:03:56 -0700232
Calin Juravle85f7bf32016-03-18 16:23:40 +0000233 for (const auto& it : tracked_dex_base_locations_) {
Mathieu Chartier9275af62016-04-29 12:03:56 -0700234 std::set<DexCacheResolvedClasses> resolved_classes_for_location;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000235 const std::string& filename = it.first;
236 const std::set<std::string>& locations = it.second;
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700237 std::vector<MethodReference> methods_for_location;
238 for (const MethodReference& ref : methods) {
239 if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) {
240 methods_for_location.push_back(ref);
241 }
242 }
Calin Juravle85f7bf32016-03-18 16:23:40 +0000243 for (const DexCacheResolvedClasses& classes : resolved_classes) {
Mathieu Chartier9275af62016-04-29 12:03:56 -0700244 if (locations.find(classes.GetBaseLocation()) != locations.end()) {
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700245 VLOG(profiler) << "Added " << classes.GetClasses().size() << " classes for location "
246 << classes.GetBaseLocation() << " (" << classes.GetDexLocation() << ")";
Calin Juravle85f7bf32016-03-18 16:23:40 +0000247 resolved_classes_for_location.insert(classes);
Mathieu Chartier9275af62016-04-29 12:03:56 -0700248 } else {
249 VLOG(profiler) << "Location not found " << classes.GetBaseLocation()
250 << " (" << classes.GetDexLocation() << ")";
Calin Juravle85f7bf32016-03-18 16:23:40 +0000251 }
252 }
253 ProfileCompilationInfo* info = GetCachedProfiledInfo(filename);
Mathieu Chartierc600eaa2016-05-18 08:51:52 -0700254 info->AddMethodsAndClasses(methods_for_location, resolved_classes_for_location);
Calin Juravle85f7bf32016-03-18 16:23:40 +0000255 total_number_of_profile_entries_cached += resolved_classes_for_location.size();
256 }
257 max_number_of_profile_entries_cached_ = std::max(
258 max_number_of_profile_entries_cached_,
259 total_number_of_profile_entries_cached);
260}
261
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100262bool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) {
Calin Juravle85f7bf32016-03-18 16:23:40 +0000263 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravleb4eddd22016-01-13 15:52:33 -0800264 SafeMap<std::string, std::set<std::string>> tracked_locations;
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000265 {
Calin Juravleb4eddd22016-01-13 15:52:33 -0800266 // Make a copy so that we don't hold the lock while doing I/O.
267 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
268 tracked_locations = tracked_dex_base_locations_;
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000269 }
Calin Juravlec15e5662016-03-17 17:07:52 +0000270
Calin Juravle85f7bf32016-03-18 16:23:40 +0000271 bool profile_file_saved = false;
272 uint64_t total_number_of_profile_entries_cached = 0;
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100273 *new_methods = 0;
274
Calin Juravleb4eddd22016-01-13 15:52:33 -0800275 for (const auto& it : tracked_locations) {
276 if (ShuttingDown(Thread::Current())) {
277 return true;
278 }
279 const std::string& filename = it.first;
280 const std::set<std::string>& locations = it.second;
Calin Juravlee2d066d2016-04-19 16:33:46 +0100281 std::vector<MethodReference> methods;
Calin Juravleb4eddd22016-01-13 15:52:33 -0800282 {
283 ScopedObjectAccess soa(Thread::Current());
Calin Juravlee2d066d2016-04-19 16:33:46 +0100284 jit_code_cache_->GetProfiledMethods(locations, methods);
Calin Juravlec19c1c22016-03-09 15:37:48 +0000285 total_number_of_code_cache_queries_++;
Calin Juravleb4eddd22016-01-13 15:52:33 -0800286 }
Calin Juravlec15e5662016-03-17 17:07:52 +0000287
Calin Juravle85f7bf32016-03-18 16:23:40 +0000288 ProfileCompilationInfo* cached_info = GetCachedProfiledInfo(filename);
289 cached_info->AddMethodsAndClasses(methods, std::set<DexCacheResolvedClasses>());
Calin Juravle0cdaa6c2016-03-30 18:18:58 +0100290 int64_t delta_number_of_methods =
291 cached_info->GetNumberOfMethods() -
292 static_cast<int64_t>(last_save_number_of_methods_);
293 int64_t delta_number_of_classes =
294 cached_info->GetNumberOfResolvedClasses() -
295 static_cast<int64_t>(last_save_number_of_classes_);
Calin Juravle85f7bf32016-03-18 16:23:40 +0000296
Calin Juravle138dbff2016-06-28 19:36:58 +0100297 if (delta_number_of_methods < options_.GetMinMethodsToSave() &&
298 delta_number_of_classes < options_.GetMinClassesToSave()) {
Calin Juravle0cdaa6c2016-03-30 18:18:58 +0100299 VLOG(profiler) << "Not enough information to save to: " << filename
Calin Juravle138dbff2016-06-28 19:36:58 +0100300 << " Number of methods: " << delta_number_of_methods
301 << " Number of classes: " << delta_number_of_classes;
Calin Juravlec19c1c22016-03-09 15:37:48 +0000302 total_number_of_skipped_writes_++;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000303 continue;
Calin Juravleb4eddd22016-01-13 15:52:33 -0800304 }
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100305 *new_methods = std::max(static_cast<uint16_t>(delta_number_of_methods), *new_methods);
Calin Juravlec19c1c22016-03-09 15:37:48 +0000306 uint64_t bytes_written;
Calin Juravlefe297a92016-03-24 20:33:22 +0000307 // Force the save. In case the profile data is corrupted or the the profile
308 // has the wrong version this will "fix" the file to the correct format.
309 if (cached_info->MergeAndSave(filename, &bytes_written, /*force*/ true)) {
Calin Juravle85f7bf32016-03-18 16:23:40 +0000310 last_save_number_of_methods_ = cached_info->GetNumberOfMethods();
Calin Juravle0cdaa6c2016-03-30 18:18:58 +0100311 last_save_number_of_classes_ = cached_info->GetNumberOfResolvedClasses();
Calin Juravle85f7bf32016-03-18 16:23:40 +0000312 // Clear resolved classes. No need to store them around as
313 // they don't change after the first write.
314 cached_info->ClearResolvedClasses();
Calin Juravlec19c1c22016-03-09 15:37:48 +0000315 if (bytes_written > 0) {
316 total_number_of_writes_++;
317 total_bytes_written_ += bytes_written;
Calin Juravle0cdaa6c2016-03-30 18:18:58 +0100318 profile_file_saved = true;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000319 } else {
320 // At this point we could still have avoided the write.
321 // We load and merge the data from the file lazily at its first ever
322 // save attempt. So, whatever we are trying to save could already be
323 // in the file.
324 total_number_of_skipped_writes_++;
Calin Juravlec19c1c22016-03-09 15:37:48 +0000325 }
Calin Juravle85f7bf32016-03-18 16:23:40 +0000326 } else {
327 LOG(WARNING) << "Could not save profiling info to " << filename;
328 total_number_of_failed_writes_++;
Calin Juravleb4eddd22016-01-13 15:52:33 -0800329 }
Calin Juravle85f7bf32016-03-18 16:23:40 +0000330 total_number_of_profile_entries_cached +=
331 cached_info->GetNumberOfMethods() +
332 cached_info->GetNumberOfResolvedClasses();
Calin Juravleb4eddd22016-01-13 15:52:33 -0800333 }
Calin Juravle85f7bf32016-03-18 16:23:40 +0000334 max_number_of_profile_entries_cached_ = std::max(
335 max_number_of_profile_entries_cached_,
336 total_number_of_profile_entries_cached);
337 return profile_file_saved;
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000338}
339
340void* ProfileSaver::RunProfileSaverThread(void* arg) {
341 Runtime* runtime = Runtime::Current();
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000342
Calin Juravlee55fda12016-04-28 12:59:33 +0100343 bool attached = runtime->AttachCurrentThread("Profile Saver",
344 /*as_daemon*/true,
345 runtime->GetSystemThreadGroup(),
346 /*create_peer*/true);
347 if (!attached) {
348 CHECK(runtime->IsShuttingDown(Thread::Current()));
349 return nullptr;
350 }
351
352 ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg);
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000353 profile_saver->Run();
354
355 runtime->DetachCurrentThread();
356 VLOG(profiler) << "Profile saver shutdown";
357 return nullptr;
358}
359
Calin Juravle6044fa72016-03-25 17:17:09 +0000360static bool ShouldProfileLocation(const std::string& location) {
Calin Juravle75064232016-04-18 16:38:27 +0100361 OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager();
362 const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location);
Calin Juravle6044fa72016-03-25 17:17:09 +0000363 if (oat_file == nullptr) {
364 // This can happen if we fallback to run code directly from the APK.
365 // Profile it with the hope that the background dexopt will get us back into
366 // a good state.
Calin Juravle75064232016-04-18 16:38:27 +0100367 VLOG(profiler) << "Asked to profile a location without an oat file:" << location;
Calin Juravle6044fa72016-03-25 17:17:09 +0000368 return true;
369 }
370 CompilerFilter::Filter filter = oat_file->GetCompilerFilter();
Calin Juravled19dc462016-04-19 18:17:41 +0100371 if ((filter == CompilerFilter::kSpeed) || (filter == CompilerFilter::kEverything)) {
Calin Juravle75064232016-04-18 16:38:27 +0100372 VLOG(profiler)
Calin Juravled19dc462016-04-19 18:17:41 +0100373 << "Skip profiling oat file because it's already speed|everything compiled: "
374 << location << " oat location: " << oat_file->GetLocation();
Calin Juravle6044fa72016-03-25 17:17:09 +0000375 return false;
376 }
377 return true;
378}
379
Calin Juravle138dbff2016-06-28 19:36:58 +0100380void ProfileSaver::Start(const ProfileSaverOptions& options,
381 const std::string& output_filename,
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000382 jit::JitCodeCache* jit_code_cache,
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000383 const std::vector<std::string>& code_paths,
384 const std::string& foreign_dex_profile_path,
385 const std::string& app_data_dir) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100386 DCHECK(options.IsEnabled());
387 DCHECK(Runtime::Current()->GetJit() != nullptr);
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000388 DCHECK(!output_filename.empty());
389 DCHECK(jit_code_cache != nullptr);
390
Calin Juravle6044fa72016-03-25 17:17:09 +0000391 std::vector<std::string> code_paths_to_profile;
392
393 for (const std::string& location : code_paths) {
394 if (ShouldProfileLocation(location)) {
395 code_paths_to_profile.push_back(location);
Calin Juravle6044fa72016-03-25 17:17:09 +0000396 }
397 }
398 if (code_paths_to_profile.empty()) {
Calin Juravle75064232016-04-18 16:38:27 +0100399 VLOG(profiler) << "No code paths should be profiled.";
Calin Juravle6044fa72016-03-25 17:17:09 +0000400 return;
401 }
402
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000403 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000404 if (instance_ != nullptr) {
Calin Juravleb4eddd22016-01-13 15:52:33 -0800405 // If we already have an instance, make sure it uses the same jit_code_cache.
406 // This may be called multiple times via Runtime::registerAppInfo (e.g. for
407 // apps which share the same runtime).
408 DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache);
409 // Add the code_paths to the tracked locations.
Calin Juravle20ae7932016-04-18 18:59:22 +0100410 instance_->AddTrackedLocations(output_filename, app_data_dir, code_paths_to_profile);
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000411 return;
412 }
413
414 VLOG(profiler) << "Starting profile saver using output file: " << output_filename
Calin Juravle75064232016-04-18 16:38:27 +0100415 << ". Tracking: " << Join(code_paths_to_profile, ':');
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000416
Calin Juravle138dbff2016-06-28 19:36:58 +0100417 instance_ = new ProfileSaver(options,
418 output_filename,
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000419 jit_code_cache,
Calin Juravle75064232016-04-18 16:38:27 +0100420 code_paths_to_profile,
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000421 foreign_dex_profile_path,
422 app_data_dir);
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000423
424 // Create a new thread which does the saving.
425 CHECK_PTHREAD_CALL(
426 pthread_create,
427 (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
428 "Profile saver thread");
429}
430
Calin Juravlec19c1c22016-03-09 15:37:48 +0000431void ProfileSaver::Stop(bool dump_info) {
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000432 ProfileSaver* profile_saver = nullptr;
433 pthread_t profiler_pthread = 0U;
434
435 {
436 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
Calin Juravleb4eddd22016-01-13 15:52:33 -0800437 VLOG(profiler) << "Stopping profile saver thread";
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000438 profile_saver = instance_;
439 profiler_pthread = profiler_pthread_;
440 if (instance_ == nullptr) {
441 DCHECK(false) << "Tried to stop a profile saver which was not started";
442 return;
443 }
444 if (instance_->shutting_down_) {
445 DCHECK(false) << "Tried to stop the profile saver twice";
446 return;
447 }
448 instance_->shutting_down_ = true;
Calin Juravlec19c1c22016-03-09 15:37:48 +0000449 if (dump_info) {
Andreas Gampe3fec9ac2016-09-13 10:47:28 -0700450 instance_->DumpInfo(LOG_STREAM(INFO));
Calin Juravlec19c1c22016-03-09 15:37:48 +0000451 }
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000452 }
453
454 {
455 // Wake up the saver thread if it is sleeping to allow for a clean exit.
456 MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_);
457 profile_saver->period_condition_.Signal(Thread::Current());
458 }
459
460 // Wait for the saver thread to stop.
461 CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
462
463 {
464 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
465 instance_ = nullptr;
466 profiler_pthread_ = 0U;
467 }
468 delete profile_saver;
469}
470
471bool ProfileSaver::ShuttingDown(Thread* self) {
472 MutexLock mu(self, *Locks::profiler_lock_);
473 return shutting_down_;
474}
475
476bool ProfileSaver::IsStarted() {
477 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
478 return instance_ != nullptr;
479}
480
Calin Juravleb4eddd22016-01-13 15:52:33 -0800481void ProfileSaver::AddTrackedLocations(const std::string& output_filename,
Calin Juravle20ae7932016-04-18 18:59:22 +0100482 const std::string& app_data_dir,
Calin Juravleb4eddd22016-01-13 15:52:33 -0800483 const std::vector<std::string>& code_paths) {
484 auto it = tracked_dex_base_locations_.find(output_filename);
485 if (it == tracked_dex_base_locations_.end()) {
486 tracked_dex_base_locations_.Put(output_filename,
487 std::set<std::string>(code_paths.begin(), code_paths.end()));
Calin Juravle655c3c32016-05-25 16:45:16 +0100488 if (!app_data_dir.empty()) {
489 app_data_dirs_.insert(app_data_dir);
490 }
Calin Juravleb4eddd22016-01-13 15:52:33 -0800491 } else {
492 it->second.insert(code_paths.begin(), code_paths.end());
493 }
494}
495
Calin Juravle655c3c32016-05-25 16:45:16 +0100496// TODO(calin): This may lead to several calls to realpath.
497// Consider moving the logic to the saver thread (i.e. when notified,
498// only cache the location, and then wake up the saver thread to do the
499// comparisons with the real file paths and to create the markers).
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000500void ProfileSaver::NotifyDexUse(const std::string& dex_location) {
Calin Juravle6044fa72016-03-25 17:17:09 +0000501 if (!ShouldProfileLocation(dex_location)) {
502 return;
503 }
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000504 std::set<std::string> app_code_paths;
505 std::string foreign_dex_profile_path;
Calin Juravle20ae7932016-04-18 18:59:22 +0100506 std::set<std::string> app_data_dirs;
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000507 {
508 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
Calin Juravlec19c1c22016-03-09 15:37:48 +0000509 if (instance_ == nullptr) {
510 return;
511 }
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000512 // Make a copy so that we don't hold the lock while doing I/O.
513 for (const auto& it : instance_->tracked_dex_base_locations_) {
514 app_code_paths.insert(it.second.begin(), it.second.end());
515 }
516 foreign_dex_profile_path = instance_->foreign_dex_profile_path_;
Calin Juravle20ae7932016-04-18 18:59:22 +0100517 app_data_dirs.insert(instance_->app_data_dirs_.begin(), instance_->app_data_dirs_.end());
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000518 }
519
Calin Juravlec19c1c22016-03-09 15:37:48 +0000520 bool mark_created = MaybeRecordDexUseInternal(dex_location,
521 app_code_paths,
522 foreign_dex_profile_path,
Calin Juravle20ae7932016-04-18 18:59:22 +0100523 app_data_dirs);
Calin Juravlec19c1c22016-03-09 15:37:48 +0000524 if (mark_created) {
525 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
526 if (instance_ != nullptr) {
527 instance_->total_number_of_foreign_dex_marks_++;
528 }
529 }
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000530}
531
Calin Juravle655c3c32016-05-25 16:45:16 +0100532static bool CheckContainsWithRealPath(const std::set<std::string>& paths_set,
533 const std::string& path_to_check) {
534 for (const auto& path : paths_set) {
535 UniqueCPtr<const char[]> real_path(realpath(path.c_str(), nullptr));
536 if (real_path == nullptr) {
537 PLOG(WARNING) << "Could not get realpath for " << path;
538 continue;
Calin Juravle1fae45f2016-03-08 12:52:52 +0000539 }
Calin Juravle655c3c32016-05-25 16:45:16 +0100540 std::string real_path_str(real_path.get());
541 if (real_path_str == path_to_check) {
542 return true;
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000543 }
544 }
Calin Juravle655c3c32016-05-25 16:45:16 +0100545 return false;
546}
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000547
Calin Juravle655c3c32016-05-25 16:45:16 +0100548// After the call, dex_location_real_path will contain the marker's name.
549static bool CreateForeignDexMarker(const std::string& foreign_dex_profile_path,
550 /*in-out*/ std::string* dex_location_real_path) {
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000551 // For foreign dex files we record a flag on disk. PackageManager will (potentially) take this
552 // into account when deciding how to optimize the loaded dex file.
553 // The expected flag name is the canonical path of the apk where '/' is substituted to '@'.
554 // (it needs to be kept in sync with
555 // frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java)
Calin Juravle655c3c32016-05-25 16:45:16 +0100556 std::replace(dex_location_real_path->begin(), dex_location_real_path->end(), '/', '@');
557 std::string flag_path = foreign_dex_profile_path + "/" + *dex_location_real_path;
Richard Uhler12e41572016-05-10 14:01:18 -0700558 // We use O_RDONLY as the access mode because we must supply some access
559 // mode, and there is no access mode that means 'create but do not read' the
560 // file. We will not not actually read from the file.
561 int fd = TEMP_FAILURE_RETRY(open(flag_path.c_str(),
562 O_CREAT | O_RDONLY | O_EXCL | O_CLOEXEC | O_NOFOLLOW, 0));
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000563 if (fd != -1) {
564 if (close(fd) != 0) {
565 PLOG(WARNING) << "Could not close file after flagging foreign dex use " << flag_path;
566 }
Calin Juravlec19c1c22016-03-09 15:37:48 +0000567 return true;
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000568 } else {
Richard Uhler12e41572016-05-10 14:01:18 -0700569 if (errno != EEXIST && errno != EACCES) {
570 // Another app could have already created the file, and selinux may not
571 // allow the read access to the file implied by the call to open.
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000572 PLOG(WARNING) << "Could not create foreign dex use mark " << flag_path;
Calin Juravlec19c1c22016-03-09 15:37:48 +0000573 return false;
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000574 }
Calin Juravlec19c1c22016-03-09 15:37:48 +0000575 return true;
Calin Juravle86a9ebe2016-02-24 10:13:09 +0000576 }
577}
578
Calin Juravle655c3c32016-05-25 16:45:16 +0100579bool ProfileSaver::MaybeRecordDexUseInternal(
580 const std::string& dex_location,
581 const std::set<std::string>& app_code_paths,
582 const std::string& foreign_dex_profile_path,
583 const std::set<std::string>& app_data_dirs) {
584 if (dex_location.empty()) {
585 LOG(WARNING) << "Asked to record foreign dex use with an empty dex location.";
586 return false;
587 }
588 if (foreign_dex_profile_path.empty()) {
589 LOG(WARNING) << "Asked to record foreign dex use without a valid profile path ";
590 return false;
591 }
592
593 if (app_code_paths.find(dex_location) != app_code_paths.end()) {
594 // The dex location belongs to the application code paths. Nothing to record.
595 return false;
596 }
597
598 if (app_data_dirs.find(dex_location) != app_data_dirs.end()) {
599 // The dex location is under the application folder. Nothing to record.
600 return false;
601 }
602
603 // Do another round of checks with the real paths.
604 // Application directory could be a symlink (e.g. /data/data instead of /data/user/0), and we
605 // don't have control over how the dex files are actually loaded (symlink or canonical path),
606
607 // Note that we could cache all the real locations in the saver (since it's an expensive
608 // operation). However we expect that app_code_paths is small (usually 1 element), and
609 // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise
610 // to save some bytes of memory usage.
611
612 UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr));
613 if (dex_location_real_path == nullptr) {
614 PLOG(WARNING) << "Could not get realpath for " << dex_location;
615 return false;
616 }
617 std::string dex_location_real_path_str(dex_location_real_path.get());
618
619 if (CheckContainsWithRealPath(app_code_paths, dex_location_real_path_str)) {
620 return false;
621 }
622
623 if (CheckContainsWithRealPath(app_data_dirs, dex_location_real_path_str)) {
624 return false;
625 }
626
627 return CreateForeignDexMarker(foreign_dex_profile_path, &dex_location_real_path_str);
628}
629
Calin Juravlec19c1c22016-03-09 15:37:48 +0000630void ProfileSaver::DumpInstanceInfo(std::ostream& os) {
631 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
632 if (instance_ != nullptr) {
633 instance_->DumpInfo(os);
634 }
635}
636
637void ProfileSaver::DumpInfo(std::ostream& os) {
638 os << "ProfileSaver total_bytes_written=" << total_bytes_written_ << '\n'
639 << "ProfileSaver total_number_of_writes=" << total_number_of_writes_ << '\n'
Calin Juravle85f7bf32016-03-18 16:23:40 +0000640 << "ProfileSaver total_number_of_code_cache_queries="
641 << total_number_of_code_cache_queries_ << '\n'
Calin Juravlec19c1c22016-03-09 15:37:48 +0000642 << "ProfileSaver total_number_of_skipped_writes=" << total_number_of_skipped_writes_ << '\n'
643 << "ProfileSaver total_number_of_failed_writes=" << total_number_of_failed_writes_ << '\n'
Calin Juravle85f7bf32016-03-18 16:23:40 +0000644 << "ProfileSaver total_ms_of_sleep=" << total_ms_of_sleep_ << '\n'
Calin Juravle6044fa72016-03-25 17:17:09 +0000645 << "ProfileSaver total_ms_of_work=" << NsToMs(total_ns_of_work_) << '\n'
Calin Juravle85f7bf32016-03-18 16:23:40 +0000646 << "ProfileSaver total_number_of_foreign_dex_marks="
647 << total_number_of_foreign_dex_marks_ << '\n'
648 << "ProfileSaver max_number_profile_entries_cached="
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100649 << max_number_of_profile_entries_cached_ << '\n'
650 << "ProfileSaver total_number_of_hot_spikes=" << total_number_of_hot_spikes_ << '\n'
651 << "ProfileSaver total_number_of_wake_ups=" << total_number_of_wake_ups_ << '\n';
Calin Juravlec19c1c22016-03-09 15:37:48 +0000652}
653
Calin Juravlee5de54c2016-04-20 14:22:09 +0100654
655void ProfileSaver::ForceProcessProfiles() {
656 ProfileSaver* saver = nullptr;
657 {
658 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
659 saver = instance_;
660 }
661 // TODO(calin): this is not actually thread safe as the instance_ may have been deleted,
662 // but we only use this in testing when we now this won't happen.
663 // Refactor the way we handle the instance so that we don't end up in this situation.
664 if (saver != nullptr) {
Calin Juravle5fbb0fe2016-04-29 16:44:11 +0100665 uint16_t new_methods;
666 saver->ProcessProfilingInfo(&new_methods);
Calin Juravlee5de54c2016-04-20 14:22:09 +0100667 }
668}
669
670bool ProfileSaver::HasSeenMethod(const std::string& profile,
671 const DexFile* dex_file,
672 uint16_t method_idx) {
673 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
674 if (instance_ != nullptr) {
675 ProfileCompilationInfo* info = instance_->GetCachedProfiledInfo(profile);
676 if (info != nullptr) {
677 return info->ContainsMethod(MethodReference(dex_file, method_idx));
678 }
679 }
680 return false;
681}
682
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000683} // namespace art