1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "profile_saver.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
20*795d594fSAndroid Build Coastguard Worker #include <sys/resource.h>
21*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
22*795d594fSAndroid Build Coastguard Worker #include <sys/types.h>
23*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker #include <algorithm>
26*795d594fSAndroid Build Coastguard Worker #include <string>
27*795d594fSAndroid Build Coastguard Worker #include <utility>
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
30*795d594fSAndroid Build Coastguard Worker #include "android-base/strings.h"
31*795d594fSAndroid Build Coastguard Worker #include "app_info.h"
32*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "base/compiler_filter.h"
34*795d594fSAndroid Build Coastguard Worker #include "base/logging.h" // For VLOG.
35*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
36*795d594fSAndroid Build Coastguard Worker #include "base/safe_map.h"
37*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
38*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
39*795d594fSAndroid Build Coastguard Worker #include "base/systrace.h"
40*795d594fSAndroid Build Coastguard Worker #include "base/time_utils.h"
41*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
42*795d594fSAndroid Build Coastguard Worker #include "class_table-inl.h"
43*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_loader.h"
44*795d594fSAndroid Build Coastguard Worker #include "dex_reference_collection.h"
45*795d594fSAndroid Build Coastguard Worker #include "gc/collector_type.h"
46*795d594fSAndroid Build Coastguard Worker #include "gc/gc_cause.h"
47*795d594fSAndroid Build Coastguard Worker #include "jit/jit.h"
48*795d594fSAndroid Build Coastguard Worker #include "jit/profiling_info.h"
49*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file_manager.h"
50*795d594fSAndroid Build Coastguard Worker #include "profile/profile_compilation_info.h"
51*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
52*795d594fSAndroid Build Coastguard Worker
53*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
54*795d594fSAndroid Build Coastguard Worker
55*795d594fSAndroid Build Coastguard Worker using Hotness = ProfileCompilationInfo::MethodHotness;
56*795d594fSAndroid Build Coastguard Worker
57*795d594fSAndroid Build Coastguard Worker ProfileSaver* ProfileSaver::instance_ = nullptr;
58*795d594fSAndroid Build Coastguard Worker pthread_t ProfileSaver::profiler_pthread_ = 0U;
59*795d594fSAndroid Build Coastguard Worker
60*795d594fSAndroid Build Coastguard Worker static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize ==
61*795d594fSAndroid Build Coastguard Worker InlineCache::kIndividualCacheSize,
62*795d594fSAndroid Build Coastguard Worker "InlineCache and ProfileCompilationInfo do not agree on kIndividualCacheSize");
63*795d594fSAndroid Build Coastguard Worker
64*795d594fSAndroid Build Coastguard Worker // At what priority to schedule the saver threads. 9 is the lowest foreground priority on device.
65*795d594fSAndroid Build Coastguard Worker static constexpr int kProfileSaverPthreadPriority = 9;
66*795d594fSAndroid Build Coastguard Worker
SetProfileSaverThreadPriority(pthread_t thread,int priority)67*795d594fSAndroid Build Coastguard Worker static void SetProfileSaverThreadPriority(pthread_t thread, int priority) {
68*795d594fSAndroid Build Coastguard Worker #if defined(ART_TARGET_ANDROID)
69*795d594fSAndroid Build Coastguard Worker int result = setpriority(PRIO_PROCESS, pthread_gettid_np(thread), priority);
70*795d594fSAndroid Build Coastguard Worker if (result != 0) {
71*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to setpriority to :" << priority;
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker #else
74*795d594fSAndroid Build Coastguard Worker UNUSED(thread);
75*795d594fSAndroid Build Coastguard Worker UNUSED(priority);
76*795d594fSAndroid Build Coastguard Worker #endif
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker
GetDefaultThreadPriority()79*795d594fSAndroid Build Coastguard Worker static int GetDefaultThreadPriority() {
80*795d594fSAndroid Build Coastguard Worker #if defined(ART_TARGET_ANDROID)
81*795d594fSAndroid Build Coastguard Worker pthread_attr_t attr;
82*795d594fSAndroid Build Coastguard Worker sched_param param;
83*795d594fSAndroid Build Coastguard Worker pthread_attr_init(&attr);
84*795d594fSAndroid Build Coastguard Worker pthread_attr_getschedparam(&attr, ¶m);
85*795d594fSAndroid Build Coastguard Worker return param.sched_priority;
86*795d594fSAndroid Build Coastguard Worker #else
87*795d594fSAndroid Build Coastguard Worker return 0;
88*795d594fSAndroid Build Coastguard Worker #endif
89*795d594fSAndroid Build Coastguard Worker }
90*795d594fSAndroid Build Coastguard Worker
ProfileSaver(const ProfileSaverOptions & options,jit::JitCodeCache * jit_code_cache)91*795d594fSAndroid Build Coastguard Worker ProfileSaver::ProfileSaver(const ProfileSaverOptions& options, jit::JitCodeCache* jit_code_cache)
92*795d594fSAndroid Build Coastguard Worker : jit_code_cache_(jit_code_cache),
93*795d594fSAndroid Build Coastguard Worker shutting_down_(false),
94*795d594fSAndroid Build Coastguard Worker last_time_ns_saver_woke_up_(0),
95*795d594fSAndroid Build Coastguard Worker jit_activity_notifications_(0),
96*795d594fSAndroid Build Coastguard Worker wait_lock_("ProfileSaver wait lock"),
97*795d594fSAndroid Build Coastguard Worker period_condition_("ProfileSaver period condition", wait_lock_),
98*795d594fSAndroid Build Coastguard Worker total_bytes_written_(0),
99*795d594fSAndroid Build Coastguard Worker total_number_of_writes_(0),
100*795d594fSAndroid Build Coastguard Worker total_number_of_code_cache_queries_(0),
101*795d594fSAndroid Build Coastguard Worker total_number_of_skipped_writes_(0),
102*795d594fSAndroid Build Coastguard Worker total_number_of_failed_writes_(0),
103*795d594fSAndroid Build Coastguard Worker total_ms_of_sleep_(0),
104*795d594fSAndroid Build Coastguard Worker total_ns_of_work_(0),
105*795d594fSAndroid Build Coastguard Worker total_number_of_hot_spikes_(0),
106*795d594fSAndroid Build Coastguard Worker total_number_of_wake_ups_(0),
107*795d594fSAndroid Build Coastguard Worker options_(options) {
108*795d594fSAndroid Build Coastguard Worker DCHECK(options_.IsEnabled());
109*795d594fSAndroid Build Coastguard Worker }
110*795d594fSAndroid Build Coastguard Worker
~ProfileSaver()111*795d594fSAndroid Build Coastguard Worker ProfileSaver::~ProfileSaver() {
112*795d594fSAndroid Build Coastguard Worker for (auto& it : profile_cache_) {
113*795d594fSAndroid Build Coastguard Worker delete it.second;
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker }
116*795d594fSAndroid Build Coastguard Worker
NotifyStartupCompleted()117*795d594fSAndroid Build Coastguard Worker void ProfileSaver::NotifyStartupCompleted() {
118*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
119*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *Locks::profiler_lock_);
120*795d594fSAndroid Build Coastguard Worker if (instance_ == nullptr || instance_->shutting_down_) {
121*795d594fSAndroid Build Coastguard Worker return;
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker MutexLock mu2(self, instance_->wait_lock_);
124*795d594fSAndroid Build Coastguard Worker instance_->period_condition_.Signal(self);
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker
Run()127*795d594fSAndroid Build Coastguard Worker void ProfileSaver::Run() {
128*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
129*795d594fSAndroid Build Coastguard Worker
130*795d594fSAndroid Build Coastguard Worker // For thread annotalysis, the setup is more complicated than it should be. Run needs to start
131*795d594fSAndroid Build Coastguard Worker // under mutex, but should drop it.
132*795d594fSAndroid Build Coastguard Worker Locks::profiler_lock_->ExclusiveUnlock(self);
133*795d594fSAndroid Build Coastguard Worker
134*795d594fSAndroid Build Coastguard Worker // Fetch the resolved classes for the app images after waiting for Startup
135*795d594fSAndroid Build Coastguard Worker // completion notification.
136*795d594fSAndroid Build Coastguard Worker const uint64_t thread_start_time = NanoTime();
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker // Wait for startup to complete with a timeout at StartupCompletedTask.
139*795d594fSAndroid Build Coastguard Worker // Note that we may be woken up by JIT notifications.
140*795d594fSAndroid Build Coastguard Worker // We need to wait for startup to complete to make sure we have
141*795d594fSAndroid Build Coastguard Worker // the resolved classes and methods.
142*795d594fSAndroid Build Coastguard Worker while (!Runtime::Current()->GetStartupCompleted() && !ShuttingDown(self)) {
143*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, wait_lock_);
144*795d594fSAndroid Build Coastguard Worker // Make sure to sleep again until startup is completed.
145*795d594fSAndroid Build Coastguard Worker period_condition_.Wait(self);
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker
148*795d594fSAndroid Build Coastguard Worker // Mark collected classes/methods as startup.
149*795d594fSAndroid Build Coastguard Worker FetchAndCacheResolvedClassesAndMethods(/*startup=*/ true);
150*795d594fSAndroid Build Coastguard Worker
151*795d594fSAndroid Build Coastguard Worker bool is_min_first_save_set =
152*795d594fSAndroid Build Coastguard Worker options_.GetMinFirstSaveMs() != ProfileSaverOptions::kMinFirstSaveMsNotSet;
153*795d594fSAndroid Build Coastguard Worker bool force_first_save = is_min_first_save_set && IsFirstSave();
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker // When we save without waiting for JIT notifications we use a simple
156*795d594fSAndroid Build Coastguard Worker // exponential back off policy bounded by max_wait_without_jit.
157*795d594fSAndroid Build Coastguard Worker uint32_t max_wait_without_jit = options_.GetMinSavePeriodMs() * 16;
158*795d594fSAndroid Build Coastguard Worker uint64_t cur_wait_without_jit = options_.GetMinSavePeriodMs();
159*795d594fSAndroid Build Coastguard Worker
160*795d594fSAndroid Build Coastguard Worker // Loop for the profiled methods.
161*795d594fSAndroid Build Coastguard Worker while (!ShuttingDown(self)) {
162*795d594fSAndroid Build Coastguard Worker // In case of force_first_save we need to count from the start of the thread.
163*795d594fSAndroid Build Coastguard Worker uint64_t sleep_start = force_first_save ? thread_start_time : NanoTime();
164*795d594fSAndroid Build Coastguard Worker uint64_t sleep_time = 0;
165*795d594fSAndroid Build Coastguard Worker {
166*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, wait_lock_);
167*795d594fSAndroid Build Coastguard Worker if (options_.GetWaitForJitNotificationsToSave()) {
168*795d594fSAndroid Build Coastguard Worker period_condition_.Wait(self);
169*795d594fSAndroid Build Coastguard Worker } else {
170*795d594fSAndroid Build Coastguard Worker period_condition_.TimedWait(self, cur_wait_without_jit, 0);
171*795d594fSAndroid Build Coastguard Worker if (cur_wait_without_jit < max_wait_without_jit) {
172*795d594fSAndroid Build Coastguard Worker cur_wait_without_jit *= 2;
173*795d594fSAndroid Build Coastguard Worker }
174*795d594fSAndroid Build Coastguard Worker }
175*795d594fSAndroid Build Coastguard Worker sleep_time = NanoTime() - sleep_start;
176*795d594fSAndroid Build Coastguard Worker }
177*795d594fSAndroid Build Coastguard Worker // Check if the thread was woken up for shutdown.
178*795d594fSAndroid Build Coastguard Worker if (ShuttingDown(self)) {
179*795d594fSAndroid Build Coastguard Worker break;
180*795d594fSAndroid Build Coastguard Worker }
181*795d594fSAndroid Build Coastguard Worker total_number_of_wake_ups_++;
182*795d594fSAndroid Build Coastguard Worker // We might have been woken up by a huge number of notifications to guarantee saving.
183*795d594fSAndroid Build Coastguard Worker // If we didn't meet the minimum saving period go back to sleep (only if missed by
184*795d594fSAndroid Build Coastguard Worker // a reasonable margin).
185*795d594fSAndroid Build Coastguard Worker uint64_t min_save_period_ns = MsToNs(force_first_save ? options_.GetMinFirstSaveMs() :
186*795d594fSAndroid Build Coastguard Worker options_.GetMinSavePeriodMs());
187*795d594fSAndroid Build Coastguard Worker while (min_save_period_ns * 0.9 > sleep_time) {
188*795d594fSAndroid Build Coastguard Worker {
189*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, wait_lock_);
190*795d594fSAndroid Build Coastguard Worker period_condition_.TimedWait(self, NsToMs(min_save_period_ns - sleep_time), 0);
191*795d594fSAndroid Build Coastguard Worker sleep_time = NanoTime() - sleep_start;
192*795d594fSAndroid Build Coastguard Worker }
193*795d594fSAndroid Build Coastguard Worker // Check if the thread was woken up for shutdown.
194*795d594fSAndroid Build Coastguard Worker if (ShuttingDown(self)) {
195*795d594fSAndroid Build Coastguard Worker break;
196*795d594fSAndroid Build Coastguard Worker }
197*795d594fSAndroid Build Coastguard Worker total_number_of_wake_ups_++;
198*795d594fSAndroid Build Coastguard Worker }
199*795d594fSAndroid Build Coastguard Worker total_ms_of_sleep_ += NsToMs(NanoTime() - sleep_start);
200*795d594fSAndroid Build Coastguard Worker
201*795d594fSAndroid Build Coastguard Worker if (ShuttingDown(self)) {
202*795d594fSAndroid Build Coastguard Worker break;
203*795d594fSAndroid Build Coastguard Worker }
204*795d594fSAndroid Build Coastguard Worker
205*795d594fSAndroid Build Coastguard Worker uint16_t number_of_new_methods = 0;
206*795d594fSAndroid Build Coastguard Worker uint64_t start_work = NanoTime();
207*795d594fSAndroid Build Coastguard Worker bool profile_saved_to_disk = ProcessProfilingInfo(
208*795d594fSAndroid Build Coastguard Worker /*force_save=*/ false,
209*795d594fSAndroid Build Coastguard Worker &number_of_new_methods);
210*795d594fSAndroid Build Coastguard Worker
211*795d594fSAndroid Build Coastguard Worker // Reset the flag, so we can continue on the normal schedule.
212*795d594fSAndroid Build Coastguard Worker force_first_save = false;
213*795d594fSAndroid Build Coastguard Worker
214*795d594fSAndroid Build Coastguard Worker // Update the notification counter based on result. Note that there might be contention on this
215*795d594fSAndroid Build Coastguard Worker // but we don't care about to be 100% precise.
216*795d594fSAndroid Build Coastguard Worker if (!profile_saved_to_disk) {
217*795d594fSAndroid Build Coastguard Worker // If we didn't save to disk it may be because we didn't have enough new methods.
218*795d594fSAndroid Build Coastguard Worker // Set the jit activity notifications to number_of_new_methods so we can wake up earlier
219*795d594fSAndroid Build Coastguard Worker // if needed.
220*795d594fSAndroid Build Coastguard Worker jit_activity_notifications_ = number_of_new_methods;
221*795d594fSAndroid Build Coastguard Worker }
222*795d594fSAndroid Build Coastguard Worker total_ns_of_work_ += NanoTime() - start_work;
223*795d594fSAndroid Build Coastguard Worker }
224*795d594fSAndroid Build Coastguard Worker }
225*795d594fSAndroid Build Coastguard Worker
226*795d594fSAndroid Build Coastguard Worker // Checks if the profile file is empty.
227*795d594fSAndroid Build Coastguard Worker // Return true if the size of the profile file is 0 or if there were errors when
228*795d594fSAndroid Build Coastguard Worker // trying to open the file.
IsProfileEmpty(const std::string & location)229*795d594fSAndroid Build Coastguard Worker static bool IsProfileEmpty(const std::string& location) {
230*795d594fSAndroid Build Coastguard Worker if (location.empty()) {
231*795d594fSAndroid Build Coastguard Worker return true;
232*795d594fSAndroid Build Coastguard Worker }
233*795d594fSAndroid Build Coastguard Worker
234*795d594fSAndroid Build Coastguard Worker struct stat stat_buffer;
235*795d594fSAndroid Build Coastguard Worker if (stat(location.c_str(), &stat_buffer) != 0) {
236*795d594fSAndroid Build Coastguard Worker if (VLOG_IS_ON(profiler)) {
237*795d594fSAndroid Build Coastguard Worker PLOG(WARNING) << "Failed to stat profile location for IsFirstUse: " << location;
238*795d594fSAndroid Build Coastguard Worker }
239*795d594fSAndroid Build Coastguard Worker return true;
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker
242*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Profile " << location << " size=" << stat_buffer.st_size;
243*795d594fSAndroid Build Coastguard Worker return stat_buffer.st_size == 0;
244*795d594fSAndroid Build Coastguard Worker }
245*795d594fSAndroid Build Coastguard Worker
IsFirstSave()246*795d594fSAndroid Build Coastguard Worker bool ProfileSaver::IsFirstSave() {
247*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
248*795d594fSAndroid Build Coastguard Worker SafeMap<std::string, std::pair<std::string, AppInfo::CodeType>> tracked_locations;
249*795d594fSAndroid Build Coastguard Worker {
250*795d594fSAndroid Build Coastguard Worker // Make a copy so that we don't hold the lock while doing I/O.
251*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *Locks::profiler_lock_);
252*795d594fSAndroid Build Coastguard Worker tracked_locations = tracked_profiles_;
253*795d594fSAndroid Build Coastguard Worker }
254*795d594fSAndroid Build Coastguard Worker
255*795d594fSAndroid Build Coastguard Worker for (const auto& it : tracked_locations) {
256*795d594fSAndroid Build Coastguard Worker if (ShuttingDown(self)) {
257*795d594fSAndroid Build Coastguard Worker return false;
258*795d594fSAndroid Build Coastguard Worker }
259*795d594fSAndroid Build Coastguard Worker const std::string& cur_profile = it.first;
260*795d594fSAndroid Build Coastguard Worker const std::string& ref_profile = it.second.first;
261*795d594fSAndroid Build Coastguard Worker
262*795d594fSAndroid Build Coastguard Worker // Check if any profile is non empty. If so, then this is not the first save.
263*795d594fSAndroid Build Coastguard Worker if (!IsProfileEmpty(cur_profile) || !IsProfileEmpty(ref_profile)) {
264*795d594fSAndroid Build Coastguard Worker return false;
265*795d594fSAndroid Build Coastguard Worker }
266*795d594fSAndroid Build Coastguard Worker }
267*795d594fSAndroid Build Coastguard Worker
268*795d594fSAndroid Build Coastguard Worker // All locations are empty. Assume this is the first use.
269*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "All profile locations are empty. This is considered to be first save";
270*795d594fSAndroid Build Coastguard Worker return true;
271*795d594fSAndroid Build Coastguard Worker }
272*795d594fSAndroid Build Coastguard Worker
NotifyJitActivity()273*795d594fSAndroid Build Coastguard Worker void ProfileSaver::NotifyJitActivity() {
274*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
275*795d594fSAndroid Build Coastguard Worker if (instance_ == nullptr || instance_->shutting_down_) {
276*795d594fSAndroid Build Coastguard Worker return;
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker instance_->NotifyJitActivityInternal();
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker
WakeUpSaver()281*795d594fSAndroid Build Coastguard Worker void ProfileSaver::WakeUpSaver() {
282*795d594fSAndroid Build Coastguard Worker jit_activity_notifications_ = 0;
283*795d594fSAndroid Build Coastguard Worker last_time_ns_saver_woke_up_ = NanoTime();
284*795d594fSAndroid Build Coastguard Worker period_condition_.Signal(Thread::Current());
285*795d594fSAndroid Build Coastguard Worker }
286*795d594fSAndroid Build Coastguard Worker
NotifyJitActivityInternal()287*795d594fSAndroid Build Coastguard Worker void ProfileSaver::NotifyJitActivityInternal() {
288*795d594fSAndroid Build Coastguard Worker // Unlikely to overflow but if it happens,
289*795d594fSAndroid Build Coastguard Worker // we would have waken up the saver long before that.
290*795d594fSAndroid Build Coastguard Worker jit_activity_notifications_++;
291*795d594fSAndroid Build Coastguard Worker // Note that we are not as precise as we could be here but we don't want to wake the saver
292*795d594fSAndroid Build Coastguard Worker // every time we see a hot method.
293*795d594fSAndroid Build Coastguard Worker if (jit_activity_notifications_ > options_.GetMinNotificationBeforeWake()) {
294*795d594fSAndroid Build Coastguard Worker MutexLock wait_mutex(Thread::Current(), wait_lock_);
295*795d594fSAndroid Build Coastguard Worker if ((NanoTime() - last_time_ns_saver_woke_up_) > MsToNs(options_.GetMinSavePeriodMs())) {
296*795d594fSAndroid Build Coastguard Worker WakeUpSaver();
297*795d594fSAndroid Build Coastguard Worker } else if (jit_activity_notifications_ > options_.GetMaxNotificationBeforeWake()) {
298*795d594fSAndroid Build Coastguard Worker // Make sure to wake up the saver if we see a spike in the number of notifications.
299*795d594fSAndroid Build Coastguard Worker // This is a precaution to avoid losing a big number of methods in case
300*795d594fSAndroid Build Coastguard Worker // this is a spike with no jit after.
301*795d594fSAndroid Build Coastguard Worker total_number_of_hot_spikes_++;
302*795d594fSAndroid Build Coastguard Worker WakeUpSaver();
303*795d594fSAndroid Build Coastguard Worker }
304*795d594fSAndroid Build Coastguard Worker }
305*795d594fSAndroid Build Coastguard Worker }
306*795d594fSAndroid Build Coastguard Worker
307*795d594fSAndroid Build Coastguard Worker class ProfileSaver::ScopedDefaultPriority {
308*795d594fSAndroid Build Coastguard Worker public:
ScopedDefaultPriority(pthread_t thread)309*795d594fSAndroid Build Coastguard Worker explicit ScopedDefaultPriority(pthread_t thread) : thread_(thread) {
310*795d594fSAndroid Build Coastguard Worker SetProfileSaverThreadPriority(thread_, GetDefaultThreadPriority());
311*795d594fSAndroid Build Coastguard Worker }
312*795d594fSAndroid Build Coastguard Worker
~ScopedDefaultPriority()313*795d594fSAndroid Build Coastguard Worker ~ScopedDefaultPriority() {
314*795d594fSAndroid Build Coastguard Worker SetProfileSaverThreadPriority(thread_, kProfileSaverPthreadPriority);
315*795d594fSAndroid Build Coastguard Worker }
316*795d594fSAndroid Build Coastguard Worker
317*795d594fSAndroid Build Coastguard Worker private:
318*795d594fSAndroid Build Coastguard Worker const pthread_t thread_;
319*795d594fSAndroid Build Coastguard Worker };
320*795d594fSAndroid Build Coastguard Worker
321*795d594fSAndroid Build Coastguard Worker class ProfileSaver::GetClassesAndMethodsHelper {
322*795d594fSAndroid Build Coastguard Worker public:
GetClassesAndMethodsHelper(bool startup,const ProfileSaverOptions & options,const ProfileCompilationInfo::ProfileSampleAnnotation & annotation)323*795d594fSAndroid Build Coastguard Worker GetClassesAndMethodsHelper(bool startup,
324*795d594fSAndroid Build Coastguard Worker const ProfileSaverOptions& options,
325*795d594fSAndroid Build Coastguard Worker const ProfileCompilationInfo::ProfileSampleAnnotation& annotation)
326*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_)
327*795d594fSAndroid Build Coastguard Worker : startup_(startup),
328*795d594fSAndroid Build Coastguard Worker profile_boot_class_path_(options.GetProfileBootClassPath()),
329*795d594fSAndroid Build Coastguard Worker extra_flags_(GetExtraMethodHotnessFlags(options)),
330*795d594fSAndroid Build Coastguard Worker annotation_(annotation),
331*795d594fSAndroid Build Coastguard Worker arena_stack_(Runtime::Current()->GetArenaPool()),
332*795d594fSAndroid Build Coastguard Worker allocator_(&arena_stack_),
333*795d594fSAndroid Build Coastguard Worker class_loaders_(std::nullopt),
334*795d594fSAndroid Build Coastguard Worker dex_file_records_map_(allocator_.Adapter(kArenaAllocProfile)),
335*795d594fSAndroid Build Coastguard Worker number_of_hot_methods_(0u),
336*795d594fSAndroid Build Coastguard Worker number_of_sampled_methods_(0u) {
337*795d594fSAndroid Build Coastguard Worker std::fill_n(max_primitive_array_dimensions_.data(), max_primitive_array_dimensions_.size(), 0u);
338*795d594fSAndroid Build Coastguard Worker }
339*795d594fSAndroid Build Coastguard Worker
REQUIRES_SHARED(Locks::mutator_lock_)340*795d594fSAndroid Build Coastguard Worker ~GetClassesAndMethodsHelper() REQUIRES_SHARED(Locks::mutator_lock_) {
341*795d594fSAndroid Build Coastguard Worker // The `class_loaders_` member destructor needs the mutator lock.
342*795d594fSAndroid Build Coastguard Worker // We need to destroy arena-allocated dex file records.
343*795d594fSAndroid Build Coastguard Worker for (const auto& entry : dex_file_records_map_) {
344*795d594fSAndroid Build Coastguard Worker delete entry.second;
345*795d594fSAndroid Build Coastguard Worker }
346*795d594fSAndroid Build Coastguard Worker }
347*795d594fSAndroid Build Coastguard Worker
348*795d594fSAndroid Build Coastguard Worker void CollectClasses(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
349*795d594fSAndroid Build Coastguard Worker void UpdateProfile(const std::set<std::string>& locations, ProfileCompilationInfo* profile_info);
350*795d594fSAndroid Build Coastguard Worker
GetNumberOfHotMethods() const351*795d594fSAndroid Build Coastguard Worker size_t GetNumberOfHotMethods() const {
352*795d594fSAndroid Build Coastguard Worker return number_of_hot_methods_;
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker
GetNumberOfSampledMethods() const355*795d594fSAndroid Build Coastguard Worker size_t GetNumberOfSampledMethods() const {
356*795d594fSAndroid Build Coastguard Worker return number_of_sampled_methods_;
357*795d594fSAndroid Build Coastguard Worker }
358*795d594fSAndroid Build Coastguard Worker
359*795d594fSAndroid Build Coastguard Worker private:
360*795d594fSAndroid Build Coastguard Worker class CollectInternalVisitor {
361*795d594fSAndroid Build Coastguard Worker public:
CollectInternalVisitor(GetClassesAndMethodsHelper * helper)362*795d594fSAndroid Build Coastguard Worker explicit CollectInternalVisitor(GetClassesAndMethodsHelper* helper)
363*795d594fSAndroid Build Coastguard Worker : helper_(helper) {}
364*795d594fSAndroid Build Coastguard Worker
VisitRootIfNonNull(StackReference<mirror::Object> * ref)365*795d594fSAndroid Build Coastguard Worker void VisitRootIfNonNull(StackReference<mirror::Object>* ref)
366*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
367*795d594fSAndroid Build Coastguard Worker if (!ref->IsNull()) {
368*795d594fSAndroid Build Coastguard Worker helper_->CollectInternal</*kBootClassLoader=*/ false>(ref->AsMirrorPtr()->AsClassLoader());
369*795d594fSAndroid Build Coastguard Worker }
370*795d594fSAndroid Build Coastguard Worker }
371*795d594fSAndroid Build Coastguard Worker
372*795d594fSAndroid Build Coastguard Worker private:
373*795d594fSAndroid Build Coastguard Worker GetClassesAndMethodsHelper* helper_;
374*795d594fSAndroid Build Coastguard Worker };
375*795d594fSAndroid Build Coastguard Worker
376*795d594fSAndroid Build Coastguard Worker struct ClassRecord {
377*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index;
378*795d594fSAndroid Build Coastguard Worker uint16_t array_dimension;
379*795d594fSAndroid Build Coastguard Worker uint32_t copied_methods_start;
380*795d594fSAndroid Build Coastguard Worker LengthPrefixedArray<ArtMethod>* methods;
381*795d594fSAndroid Build Coastguard Worker };
382*795d594fSAndroid Build Coastguard Worker
383*795d594fSAndroid Build Coastguard Worker struct DexFileRecords : public DeletableArenaObject<kArenaAllocProfile> {
DexFileRecordsart::ProfileSaver::GetClassesAndMethodsHelper::DexFileRecords384*795d594fSAndroid Build Coastguard Worker explicit DexFileRecords(ScopedArenaAllocator* allocator)
385*795d594fSAndroid Build Coastguard Worker : class_records(allocator->Adapter(kArenaAllocProfile)),
386*795d594fSAndroid Build Coastguard Worker copied_methods(allocator->Adapter(kArenaAllocProfile)) {
387*795d594fSAndroid Build Coastguard Worker class_records.reserve(kInitialClassRecordsReservation);
388*795d594fSAndroid Build Coastguard Worker }
389*795d594fSAndroid Build Coastguard Worker
390*795d594fSAndroid Build Coastguard Worker static constexpr size_t kInitialClassRecordsReservation = 512;
391*795d594fSAndroid Build Coastguard Worker
392*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<ClassRecord> class_records;
393*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<ArtMethod*> copied_methods;
394*795d594fSAndroid Build Coastguard Worker };
395*795d594fSAndroid Build Coastguard Worker
396*795d594fSAndroid Build Coastguard Worker using DexFileRecordsMap = ScopedArenaHashMap<const DexFile*, DexFileRecords*>;
397*795d594fSAndroid Build Coastguard Worker
ShouldCollectClasses(bool startup)398*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE static bool ShouldCollectClasses(bool startup) {
399*795d594fSAndroid Build Coastguard Worker // We only record classes for the startup case. This may change in the future.
400*795d594fSAndroid Build Coastguard Worker return startup;
401*795d594fSAndroid Build Coastguard Worker }
402*795d594fSAndroid Build Coastguard Worker
403*795d594fSAndroid Build Coastguard Worker // Collect classes and methods from one class loader.
404*795d594fSAndroid Build Coastguard Worker template <bool kBootClassLoader>
405*795d594fSAndroid Build Coastguard Worker void CollectInternal(ObjPtr<mirror::ClassLoader> class_loader) NO_INLINE
406*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_);
407*795d594fSAndroid Build Coastguard Worker
408*795d594fSAndroid Build Coastguard Worker const bool startup_;
409*795d594fSAndroid Build Coastguard Worker const bool profile_boot_class_path_;
410*795d594fSAndroid Build Coastguard Worker const uint32_t extra_flags_;
411*795d594fSAndroid Build Coastguard Worker const ProfileCompilationInfo::ProfileSampleAnnotation annotation_;
412*795d594fSAndroid Build Coastguard Worker ArenaStack arena_stack_;
413*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator_;
414*795d594fSAndroid Build Coastguard Worker std::optional<VariableSizedHandleScope> class_loaders_;
415*795d594fSAndroid Build Coastguard Worker DexFileRecordsMap dex_file_records_map_;
416*795d594fSAndroid Build Coastguard Worker
417*795d594fSAndroid Build Coastguard Worker static_assert(Primitive::kPrimLast == Primitive::kPrimVoid); // There are no arrays of void.
418*795d594fSAndroid Build Coastguard Worker std::array<uint8_t, static_cast<size_t>(Primitive::kPrimLast)> max_primitive_array_dimensions_;
419*795d594fSAndroid Build Coastguard Worker
420*795d594fSAndroid Build Coastguard Worker size_t number_of_hot_methods_;
421*795d594fSAndroid Build Coastguard Worker size_t number_of_sampled_methods_;
422*795d594fSAndroid Build Coastguard Worker };
423*795d594fSAndroid Build Coastguard Worker
424*795d594fSAndroid Build Coastguard Worker template <bool kBootClassLoader>
CollectInternal(ObjPtr<mirror::ClassLoader> class_loader)425*795d594fSAndroid Build Coastguard Worker void ProfileSaver::GetClassesAndMethodsHelper::CollectInternal(
426*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::ClassLoader> class_loader) {
427*795d594fSAndroid Build Coastguard Worker ScopedTrace trace(__PRETTY_FUNCTION__);
428*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kBootClassLoader, class_loader == nullptr);
429*795d594fSAndroid Build Coastguard Worker
430*795d594fSAndroid Build Coastguard Worker // If the class loader has not loaded any classes, it may have a null table.
431*795d594fSAndroid Build Coastguard Worker ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
432*795d594fSAndroid Build Coastguard Worker ClassTable* const table =
433*795d594fSAndroid Build Coastguard Worker class_linker->ClassTableForClassLoader(kBootClassLoader ? nullptr : class_loader);
434*795d594fSAndroid Build Coastguard Worker if (table == nullptr) {
435*795d594fSAndroid Build Coastguard Worker return;
436*795d594fSAndroid Build Coastguard Worker }
437*795d594fSAndroid Build Coastguard Worker
438*795d594fSAndroid Build Coastguard Worker // Move members to local variables to allow the compiler to optimize this properly.
439*795d594fSAndroid Build Coastguard Worker const bool startup = startup_;
440*795d594fSAndroid Build Coastguard Worker table->Visit([&](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
441*795d594fSAndroid Build Coastguard Worker if (kBootClassLoader ? (!klass->IsBootStrapClassLoaded())
442*795d594fSAndroid Build Coastguard Worker : (klass->GetClassLoader() != class_loader)) {
443*795d594fSAndroid Build Coastguard Worker // To avoid processing a class more than once, we process each class only
444*795d594fSAndroid Build Coastguard Worker // when we encounter it in the defining class loader's class table.
445*795d594fSAndroid Build Coastguard Worker // This class has a different defining class loader, skip it.
446*795d594fSAndroid Build Coastguard Worker return true;
447*795d594fSAndroid Build Coastguard Worker }
448*795d594fSAndroid Build Coastguard Worker
449*795d594fSAndroid Build Coastguard Worker uint16_t dim = 0u;
450*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> k = klass;
451*795d594fSAndroid Build Coastguard Worker if (klass->IsArrayClass()) {
452*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(klass->NumMethods(), 0u); // No methods to collect.
453*795d594fSAndroid Build Coastguard Worker if (!ShouldCollectClasses(startup)) {
454*795d594fSAndroid Build Coastguard Worker return true;
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker do {
457*795d594fSAndroid Build Coastguard Worker DCHECK(k->IsResolved()); // Array classes are always resolved.
458*795d594fSAndroid Build Coastguard Worker ++dim;
459*795d594fSAndroid Build Coastguard Worker // At the time of array class creation, the element type is already either
460*795d594fSAndroid Build Coastguard Worker // resolved or erroneous unresoved and either shall remain an invariant.
461*795d594fSAndroid Build Coastguard Worker // Similarly, the access flag indicating a proxy class is an invariant.
462*795d594fSAndroid Build Coastguard Worker // Read barrier is unnecessary for reading a chain of constant references
463*795d594fSAndroid Build Coastguard Worker // in order to read primitive fields to check such invariants, or to read
464*795d594fSAndroid Build Coastguard Worker // other constant primitive fields (dex file, primitive type) below.
465*795d594fSAndroid Build Coastguard Worker k = k->GetComponentType<kDefaultVerifyFlags, kWithoutReadBarrier>();
466*795d594fSAndroid Build Coastguard Worker } while (k->IsArrayClass());
467*795d594fSAndroid Build Coastguard Worker
468*795d594fSAndroid Build Coastguard Worker DCHECK(kBootClassLoader || !k->IsPrimitive());
469*795d594fSAndroid Build Coastguard Worker if (kBootClassLoader && UNLIKELY(k->IsPrimitive())) {
470*795d594fSAndroid Build Coastguard Worker size_t index = enum_cast<size_t>(k->GetPrimitiveType());
471*795d594fSAndroid Build Coastguard Worker DCHECK_LT(index, max_primitive_array_dimensions_.size());
472*795d594fSAndroid Build Coastguard Worker if (dim > max_primitive_array_dimensions_[index]) {
473*795d594fSAndroid Build Coastguard Worker // Enforce an upper limit of 255 for primitive array dimensions.
474*795d594fSAndroid Build Coastguard Worker max_primitive_array_dimensions_[index] =
475*795d594fSAndroid Build Coastguard Worker std::min<size_t>(dim, std::numeric_limits<uint8_t>::max());
476*795d594fSAndroid Build Coastguard Worker }
477*795d594fSAndroid Build Coastguard Worker return true;
478*795d594fSAndroid Build Coastguard Worker }
479*795d594fSAndroid Build Coastguard Worker
480*795d594fSAndroid Build Coastguard Worker // Attribute the array class to the defining dex file of the element class.
481*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(klass->GetCopiedMethodsStartOffset(), 0u);
482*795d594fSAndroid Build Coastguard Worker DCHECK(klass->GetMethodsPtr() == nullptr);
483*795d594fSAndroid Build Coastguard Worker } else {
484*795d594fSAndroid Build Coastguard Worker // Non-array class. There is no need to collect primitive types.
485*795d594fSAndroid Build Coastguard Worker DCHECK(kBootClassLoader || !k->IsPrimitive());
486*795d594fSAndroid Build Coastguard Worker if (kBootClassLoader && UNLIKELY(klass->IsPrimitive())) {
487*795d594fSAndroid Build Coastguard Worker DCHECK(profile_boot_class_path_);
488*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(klass->NumMethods(), 0u); // No methods to collect.
489*795d594fSAndroid Build Coastguard Worker return true;
490*795d594fSAndroid Build Coastguard Worker }
491*795d594fSAndroid Build Coastguard Worker }
492*795d594fSAndroid Build Coastguard Worker
493*795d594fSAndroid Build Coastguard Worker if (!k->IsResolved() || k->IsProxyClass()) {
494*795d594fSAndroid Build Coastguard Worker return true;
495*795d594fSAndroid Build Coastguard Worker }
496*795d594fSAndroid Build Coastguard Worker
497*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = k->GetDexFile();
498*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index = k->GetDexTypeIndex();
499*795d594fSAndroid Build Coastguard Worker uint32_t copied_methods_start = klass->GetCopiedMethodsStartOffset();
500*795d594fSAndroid Build Coastguard Worker LengthPrefixedArray<ArtMethod>* methods = klass->GetMethodsPtr();
501*795d594fSAndroid Build Coastguard Worker if (methods != nullptr) {
502*795d594fSAndroid Build Coastguard Worker CHECK_LE(copied_methods_start, methods->size()) << k->PrettyClass();
503*795d594fSAndroid Build Coastguard Worker }
504*795d594fSAndroid Build Coastguard Worker
505*795d594fSAndroid Build Coastguard Worker DexFileRecords* dex_file_records;
506*795d594fSAndroid Build Coastguard Worker auto it = dex_file_records_map_.find(&dex_file);
507*795d594fSAndroid Build Coastguard Worker if (it != dex_file_records_map_.end()) {
508*795d594fSAndroid Build Coastguard Worker dex_file_records = it->second;
509*795d594fSAndroid Build Coastguard Worker } else {
510*795d594fSAndroid Build Coastguard Worker dex_file_records = new (&allocator_) DexFileRecords(&allocator_);
511*795d594fSAndroid Build Coastguard Worker dex_file_records_map_.insert(std::make_pair(&dex_file, dex_file_records));
512*795d594fSAndroid Build Coastguard Worker }
513*795d594fSAndroid Build Coastguard Worker dex_file_records->class_records.push_back(
514*795d594fSAndroid Build Coastguard Worker ClassRecord{type_index, dim, copied_methods_start, methods});
515*795d594fSAndroid Build Coastguard Worker return true;
516*795d594fSAndroid Build Coastguard Worker });
517*795d594fSAndroid Build Coastguard Worker }
518*795d594fSAndroid Build Coastguard Worker
CollectClasses(Thread * self)519*795d594fSAndroid Build Coastguard Worker void ProfileSaver::GetClassesAndMethodsHelper::CollectClasses(Thread* self) {
520*795d594fSAndroid Build Coastguard Worker ScopedTrace trace(__PRETTY_FUNCTION__);
521*795d594fSAndroid Build Coastguard Worker
522*795d594fSAndroid Build Coastguard Worker // Collect class loaders into a `VariableSizedHandleScope` to prevent contention
523*795d594fSAndroid Build Coastguard Worker // problems on the class_linker_classes_lock. Hold those class loaders in
524*795d594fSAndroid Build Coastguard Worker // a member variable to keep them alive and prevent unloading their classes,
525*795d594fSAndroid Build Coastguard Worker // so that methods referenced in collected `DexFileRecords` remain valid.
526*795d594fSAndroid Build Coastguard Worker class_loaders_.emplace(self);
527*795d594fSAndroid Build Coastguard Worker Runtime::Current()->GetClassLinker()->GetClassLoaders(self, &class_loaders_.value());
528*795d594fSAndroid Build Coastguard Worker
529*795d594fSAndroid Build Coastguard Worker // Collect classes and their method array pointers.
530*795d594fSAndroid Build Coastguard Worker if (profile_boot_class_path_) {
531*795d594fSAndroid Build Coastguard Worker // Collect classes from the boot class loader since visit classloaders doesn't visit it.
532*795d594fSAndroid Build Coastguard Worker CollectInternal</*kBootClassLoader=*/ true>(/*class_loader=*/ nullptr);
533*795d594fSAndroid Build Coastguard Worker }
534*795d594fSAndroid Build Coastguard Worker {
535*795d594fSAndroid Build Coastguard Worker CollectInternalVisitor visitor(this);
536*795d594fSAndroid Build Coastguard Worker class_loaders_->VisitRoots(visitor);
537*795d594fSAndroid Build Coastguard Worker }
538*795d594fSAndroid Build Coastguard Worker
539*795d594fSAndroid Build Coastguard Worker // Attribute copied methods to defining dex files while holding the mutator lock.
540*795d594fSAndroid Build Coastguard Worker for (const auto& entry : dex_file_records_map_) {
541*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = entry.first;
542*795d594fSAndroid Build Coastguard Worker DexFileRecords* dex_file_records = entry.second;
543*795d594fSAndroid Build Coastguard Worker
544*795d594fSAndroid Build Coastguard Worker for (const ClassRecord& class_record : dex_file_records->class_records) {
545*795d594fSAndroid Build Coastguard Worker LengthPrefixedArray<ArtMethod>* methods = class_record.methods;
546*795d594fSAndroid Build Coastguard Worker if (methods == nullptr) {
547*795d594fSAndroid Build Coastguard Worker continue;
548*795d594fSAndroid Build Coastguard Worker }
549*795d594fSAndroid Build Coastguard Worker const size_t methods_size = methods->size();
550*795d594fSAndroid Build Coastguard Worker CHECK_LE(class_record.copied_methods_start, methods_size)
551*795d594fSAndroid Build Coastguard Worker << dex_file->PrettyType(class_record.type_index);
552*795d594fSAndroid Build Coastguard Worker for (size_t index = class_record.copied_methods_start; index != methods_size; ++index) {
553*795d594fSAndroid Build Coastguard Worker // Note: Using `ArtMethod` array with implicit `kRuntimePointerSize`.
554*795d594fSAndroid Build Coastguard Worker ArtMethod& method = methods->At(index);
555*795d594fSAndroid Build Coastguard Worker CHECK(method.IsCopied()) << dex_file->PrettyType(class_record.type_index);
556*795d594fSAndroid Build Coastguard Worker CHECK(!method.IsNative()) << dex_file->PrettyType(class_record.type_index);
557*795d594fSAndroid Build Coastguard Worker if (method.IsInvokable()) {
558*795d594fSAndroid Build Coastguard Worker const DexFile* method_dex_file = method.GetDexFile();
559*795d594fSAndroid Build Coastguard Worker DexFileRecords* method_dex_file_records = dex_file_records;
560*795d594fSAndroid Build Coastguard Worker if (method_dex_file != dex_file) {
561*795d594fSAndroid Build Coastguard Worker auto it = dex_file_records_map_.find(method_dex_file);
562*795d594fSAndroid Build Coastguard Worker if (it == dex_file_records_map_.end()) {
563*795d594fSAndroid Build Coastguard Worker // We have not seen any class in the dex file that defines the interface with this
564*795d594fSAndroid Build Coastguard Worker // copied method. This can happen if the interface is in the boot class path and
565*795d594fSAndroid Build Coastguard Worker // we are not profiling boot class path; or when we first visit classes for the
566*795d594fSAndroid Build Coastguard Worker // interface's defining class loader before it has any resolved classes and then
567*795d594fSAndroid Build Coastguard Worker // the interface is resolved and an implementing class is defined in a child class
568*795d594fSAndroid Build Coastguard Worker // loader before we visit that child class loader's classes.
569*795d594fSAndroid Build Coastguard Worker continue;
570*795d594fSAndroid Build Coastguard Worker }
571*795d594fSAndroid Build Coastguard Worker method_dex_file_records = it->second;
572*795d594fSAndroid Build Coastguard Worker }
573*795d594fSAndroid Build Coastguard Worker method_dex_file_records->copied_methods.push_back(&method);
574*795d594fSAndroid Build Coastguard Worker }
575*795d594fSAndroid Build Coastguard Worker }
576*795d594fSAndroid Build Coastguard Worker }
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker }
579*795d594fSAndroid Build Coastguard Worker
UpdateProfile(const std::set<std::string> & locations,ProfileCompilationInfo * profile_info)580*795d594fSAndroid Build Coastguard Worker void ProfileSaver::GetClassesAndMethodsHelper::UpdateProfile(const std::set<std::string>& locations,
581*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo* profile_info) {
582*795d594fSAndroid Build Coastguard Worker // Move members to local variables to allow the compiler to optimize this properly.
583*795d594fSAndroid Build Coastguard Worker const bool startup = startup_;
584*795d594fSAndroid Build Coastguard Worker const uint32_t base_flags =
585*795d594fSAndroid Build Coastguard Worker (startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup) | extra_flags_;
586*795d594fSAndroid Build Coastguard Worker
587*795d594fSAndroid Build Coastguard Worker // Collect the number of hot and sampled methods.
588*795d594fSAndroid Build Coastguard Worker size_t number_of_hot_methods = 0u;
589*795d594fSAndroid Build Coastguard Worker size_t number_of_sampled_methods = 0u;
590*795d594fSAndroid Build Coastguard Worker
591*795d594fSAndroid Build Coastguard Worker uint16_t initial_value = Runtime::Current()->GetJITOptions()->GetWarmupThreshold();
592*795d594fSAndroid Build Coastguard Worker auto get_method_flags = [&](ArtMethod& method) {
593*795d594fSAndroid Build Coastguard Worker // Mark methods as hot if they are marked as such (warm for the runtime
594*795d594fSAndroid Build Coastguard Worker // means hot for the profile).
595*795d594fSAndroid Build Coastguard Worker if (method.PreviouslyWarm()) {
596*795d594fSAndroid Build Coastguard Worker ++number_of_hot_methods;
597*795d594fSAndroid Build Coastguard Worker return enum_cast<ProfileCompilationInfo::MethodHotness::Flag>(base_flags | Hotness::kFlagHot);
598*795d594fSAndroid Build Coastguard Worker } else if (method.CounterHasChanged(initial_value)) {
599*795d594fSAndroid Build Coastguard Worker ++number_of_sampled_methods;
600*795d594fSAndroid Build Coastguard Worker return enum_cast<ProfileCompilationInfo::MethodHotness::Flag>(base_flags);
601*795d594fSAndroid Build Coastguard Worker } else {
602*795d594fSAndroid Build Coastguard Worker return enum_cast<ProfileCompilationInfo::MethodHotness::Flag>(0u);
603*795d594fSAndroid Build Coastguard Worker }
604*795d594fSAndroid Build Coastguard Worker };
605*795d594fSAndroid Build Coastguard Worker
606*795d594fSAndroid Build Coastguard Worker // Use a single string for array descriptors to avoid too many reallocations.
607*795d594fSAndroid Build Coastguard Worker std::string array_class_descriptor;
608*795d594fSAndroid Build Coastguard Worker
609*795d594fSAndroid Build Coastguard Worker // Process classes and methods.
610*795d594fSAndroid Build Coastguard Worker for (const auto& entry : dex_file_records_map_) {
611*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = entry.first;
612*795d594fSAndroid Build Coastguard Worker const DexFileRecords* dex_file_records = entry.second;
613*795d594fSAndroid Build Coastguard Worker
614*795d594fSAndroid Build Coastguard Worker // Check if this is a profiled dex file.
615*795d594fSAndroid Build Coastguard Worker const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
616*795d594fSAndroid Build Coastguard Worker if (locations.find(base_location) == locations.end()) {
617*795d594fSAndroid Build Coastguard Worker continue;
618*795d594fSAndroid Build Coastguard Worker }
619*795d594fSAndroid Build Coastguard Worker
620*795d594fSAndroid Build Coastguard Worker // Get the profile index.
621*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo::ProfileIndexType profile_index =
622*795d594fSAndroid Build Coastguard Worker profile_info->FindOrAddDexFile(*dex_file, annotation_);
623*795d594fSAndroid Build Coastguard Worker if (profile_index == ProfileCompilationInfo::MaxProfileIndex()) {
624*795d594fSAndroid Build Coastguard Worker // Error adding dex file to the `profile_info`.
625*795d594fSAndroid Build Coastguard Worker continue;
626*795d594fSAndroid Build Coastguard Worker }
627*795d594fSAndroid Build Coastguard Worker
628*795d594fSAndroid Build Coastguard Worker for (const ClassRecord& class_record : dex_file_records->class_records) {
629*795d594fSAndroid Build Coastguard Worker if (class_record.array_dimension != 0u) {
630*795d594fSAndroid Build Coastguard Worker DCHECK(ShouldCollectClasses(startup));
631*795d594fSAndroid Build Coastguard Worker DCHECK(class_record.methods == nullptr); // No methods to process.
632*795d594fSAndroid Build Coastguard Worker array_class_descriptor.assign(class_record.array_dimension, '[');
633*795d594fSAndroid Build Coastguard Worker array_class_descriptor += dex_file->GetTypeDescriptorView(class_record.type_index);
634*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index =
635*795d594fSAndroid Build Coastguard Worker profile_info->FindOrCreateTypeIndex(*dex_file, array_class_descriptor);
636*795d594fSAndroid Build Coastguard Worker if (type_index.IsValid()) {
637*795d594fSAndroid Build Coastguard Worker profile_info->AddClass(profile_index, type_index);
638*795d594fSAndroid Build Coastguard Worker }
639*795d594fSAndroid Build Coastguard Worker } else {
640*795d594fSAndroid Build Coastguard Worker // Non-array class.
641*795d594fSAndroid Build Coastguard Worker if (ShouldCollectClasses(startup)) {
642*795d594fSAndroid Build Coastguard Worker profile_info->AddClass(profile_index, class_record.type_index);
643*795d594fSAndroid Build Coastguard Worker }
644*795d594fSAndroid Build Coastguard Worker const size_t num_declared_methods = class_record.copied_methods_start;
645*795d594fSAndroid Build Coastguard Worker LengthPrefixedArray<ArtMethod>* methods = class_record.methods;
646*795d594fSAndroid Build Coastguard Worker for (size_t index = 0; index != num_declared_methods; ++index) {
647*795d594fSAndroid Build Coastguard Worker // Note: Using `ArtMethod` array with implicit `kRuntimePointerSize`.
648*795d594fSAndroid Build Coastguard Worker ArtMethod& method = methods->At(index);
649*795d594fSAndroid Build Coastguard Worker DCHECK(!method.IsCopied());
650*795d594fSAndroid Build Coastguard Worker // We do not record native methods. Once we AOT-compile the app,
651*795d594fSAndroid Build Coastguard Worker // all native methods shall have their JNI stubs compiled.
652*795d594fSAndroid Build Coastguard Worker if (method.IsInvokable() && !method.IsNative()) {
653*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo::MethodHotness::Flag flags = get_method_flags(method);
654*795d594fSAndroid Build Coastguard Worker if (flags != 0u) {
655*795d594fSAndroid Build Coastguard Worker profile_info->AddMethod(profile_index, method.GetDexMethodIndex(), flags);
656*795d594fSAndroid Build Coastguard Worker }
657*795d594fSAndroid Build Coastguard Worker }
658*795d594fSAndroid Build Coastguard Worker }
659*795d594fSAndroid Build Coastguard Worker }
660*795d594fSAndroid Build Coastguard Worker }
661*795d594fSAndroid Build Coastguard Worker
662*795d594fSAndroid Build Coastguard Worker for (ArtMethod* method : dex_file_records->copied_methods) {
663*795d594fSAndroid Build Coastguard Worker DCHECK(method->IsCopied());
664*795d594fSAndroid Build Coastguard Worker DCHECK(method->IsInvokable());
665*795d594fSAndroid Build Coastguard Worker DCHECK(!method->IsNative());
666*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo::MethodHotness::Flag flags = get_method_flags(*method);
667*795d594fSAndroid Build Coastguard Worker if (flags != 0u) {
668*795d594fSAndroid Build Coastguard Worker profile_info->AddMethod(profile_index, method->GetDexMethodIndex(), flags);
669*795d594fSAndroid Build Coastguard Worker }
670*795d594fSAndroid Build Coastguard Worker }
671*795d594fSAndroid Build Coastguard Worker }
672*795d594fSAndroid Build Coastguard Worker
673*795d594fSAndroid Build Coastguard Worker if (profile_boot_class_path_) {
674*795d594fSAndroid Build Coastguard Worker // Attribute primitive arrays to the first dex file in the boot class path (should
675*795d594fSAndroid Build Coastguard Worker // be core-oj). We collect primitive array types to know the needed dimensions.
676*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
677*795d594fSAndroid Build Coastguard Worker DCHECK(!class_linker->GetBootClassPath().empty());
678*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = class_linker->GetBootClassPath().front();
679*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo::ProfileIndexType profile_index =
680*795d594fSAndroid Build Coastguard Worker profile_info->FindOrAddDexFile(*dex_file, annotation_);
681*795d594fSAndroid Build Coastguard Worker if (profile_index != ProfileCompilationInfo::MaxProfileIndex()) {
682*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != max_primitive_array_dimensions_.size(); ++i) {
683*795d594fSAndroid Build Coastguard Worker size_t max_dim = max_primitive_array_dimensions_[i];
684*795d594fSAndroid Build Coastguard Worker // Insert descriptors for all dimensions up to `max_dim`.
685*795d594fSAndroid Build Coastguard Worker for (size_t dim = 1; dim <= max_dim; ++dim) {
686*795d594fSAndroid Build Coastguard Worker array_class_descriptor.assign(dim, '[');
687*795d594fSAndroid Build Coastguard Worker array_class_descriptor += Primitive::Descriptor(enum_cast<Primitive::Type>(i));
688*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index =
689*795d594fSAndroid Build Coastguard Worker profile_info->FindOrCreateTypeIndex(*dex_file, array_class_descriptor);
690*795d594fSAndroid Build Coastguard Worker if (type_index.IsValid()) {
691*795d594fSAndroid Build Coastguard Worker profile_info->AddClass(profile_index, type_index);
692*795d594fSAndroid Build Coastguard Worker }
693*795d594fSAndroid Build Coastguard Worker }
694*795d594fSAndroid Build Coastguard Worker }
695*795d594fSAndroid Build Coastguard Worker } else {
696*795d594fSAndroid Build Coastguard Worker // Error adding dex file to the `profile_info`.
697*795d594fSAndroid Build Coastguard Worker }
698*795d594fSAndroid Build Coastguard Worker } else {
699*795d594fSAndroid Build Coastguard Worker DCHECK(std::all_of(max_primitive_array_dimensions_.begin(),
700*795d594fSAndroid Build Coastguard Worker max_primitive_array_dimensions_.end(),
701*795d594fSAndroid Build Coastguard Worker [](uint8_t dim) { return dim == 0u; }));
702*795d594fSAndroid Build Coastguard Worker }
703*795d594fSAndroid Build Coastguard Worker
704*795d594fSAndroid Build Coastguard Worker // Store the number of hot and sampled methods.
705*795d594fSAndroid Build Coastguard Worker number_of_hot_methods_ = number_of_hot_methods;
706*795d594fSAndroid Build Coastguard Worker number_of_sampled_methods_ = number_of_sampled_methods;
707*795d594fSAndroid Build Coastguard Worker }
708*795d594fSAndroid Build Coastguard Worker
FetchAndCacheResolvedClassesAndMethods(bool startup)709*795d594fSAndroid Build Coastguard Worker void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) {
710*795d594fSAndroid Build Coastguard Worker ScopedTrace trace(__PRETTY_FUNCTION__);
711*795d594fSAndroid Build Coastguard Worker const uint64_t start_time = NanoTime();
712*795d594fSAndroid Build Coastguard Worker
713*795d594fSAndroid Build Coastguard Worker // Resolve any new registered locations.
714*795d594fSAndroid Build Coastguard Worker ResolveTrackedLocations();
715*795d594fSAndroid Build Coastguard Worker
716*795d594fSAndroid Build Coastguard Worker Thread* const self = Thread::Current();
717*795d594fSAndroid Build Coastguard Worker pthread_t profiler_pthread;
718*795d594fSAndroid Build Coastguard Worker {
719*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *Locks::profiler_lock_);
720*795d594fSAndroid Build Coastguard Worker profiler_pthread = profiler_pthread_;
721*795d594fSAndroid Build Coastguard Worker }
722*795d594fSAndroid Build Coastguard Worker
723*795d594fSAndroid Build Coastguard Worker size_t number_of_hot_methods = 0u;
724*795d594fSAndroid Build Coastguard Worker size_t number_of_sampled_methods = 0u;
725*795d594fSAndroid Build Coastguard Worker {
726*795d594fSAndroid Build Coastguard Worker // Restore profile saver thread priority while holding the mutator lock. This helps
727*795d594fSAndroid Build Coastguard Worker // prevent priority inversions blocking the GC for long periods of time.
728*795d594fSAndroid Build Coastguard Worker // Only restore default priority if we are the profile saver thread. Other threads
729*795d594fSAndroid Build Coastguard Worker // that call this are threads calling Stop and the signal catcher (for SIGUSR1).
730*795d594fSAndroid Build Coastguard Worker std::optional<ScopedDefaultPriority> sdp = std::nullopt;
731*795d594fSAndroid Build Coastguard Worker if (pthread_self() == profiler_pthread) {
732*795d594fSAndroid Build Coastguard Worker sdp.emplace(profiler_pthread);
733*795d594fSAndroid Build Coastguard Worker }
734*795d594fSAndroid Build Coastguard Worker
735*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
736*795d594fSAndroid Build Coastguard Worker GetClassesAndMethodsHelper helper(startup, options_, GetProfileSampleAnnotation());
737*795d594fSAndroid Build Coastguard Worker helper.CollectClasses(self);
738*795d594fSAndroid Build Coastguard Worker
739*795d594fSAndroid Build Coastguard Worker // Release the mutator lock. We shall need to re-acquire the lock for a moment to
740*795d594fSAndroid Build Coastguard Worker // destroy the `VariableSizedHandleScope` inside the `helper` which shall be
741*795d594fSAndroid Build Coastguard Worker // conveniently handled by destroying `sts`, then `helper` and then `soa`.
742*795d594fSAndroid Build Coastguard Worker ScopedThreadSuspension sts(self, ThreadState::kNative);
743*795d594fSAndroid Build Coastguard Worker // Get back to the previous thread priority. We shall not increase the priority
744*795d594fSAndroid Build Coastguard Worker // for the short time we need to re-acquire mutator lock for `helper` destructor.
745*795d594fSAndroid Build Coastguard Worker sdp.reset();
746*795d594fSAndroid Build Coastguard Worker
747*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *Locks::profiler_lock_);
748*795d594fSAndroid Build Coastguard Worker for (const auto& it : tracked_dex_base_locations_) {
749*795d594fSAndroid Build Coastguard Worker const std::string& filename = it.first;
750*795d594fSAndroid Build Coastguard Worker auto info_it = profile_cache_.find(filename);
751*795d594fSAndroid Build Coastguard Worker if (info_it == profile_cache_.end()) {
752*795d594fSAndroid Build Coastguard Worker info_it = profile_cache_.Put(
753*795d594fSAndroid Build Coastguard Worker filename,
754*795d594fSAndroid Build Coastguard Worker new ProfileCompilationInfo(
755*795d594fSAndroid Build Coastguard Worker Runtime::Current()->GetArenaPool(), options_.GetProfileBootClassPath()));
756*795d594fSAndroid Build Coastguard Worker }
757*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo* cached_info = info_it->second;
758*795d594fSAndroid Build Coastguard Worker
759*795d594fSAndroid Build Coastguard Worker const std::set<std::string>& locations = it.second;
760*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Locations for " << it.first << " " << android::base::Join(locations, ':');
761*795d594fSAndroid Build Coastguard Worker helper.UpdateProfile(locations, cached_info);
762*795d594fSAndroid Build Coastguard Worker
763*795d594fSAndroid Build Coastguard Worker // Update statistics. Note that a method shall be counted for each
764*795d594fSAndroid Build Coastguard Worker // tracked location that covers the dex file where it is defined.
765*795d594fSAndroid Build Coastguard Worker number_of_hot_methods += helper.GetNumberOfHotMethods();
766*795d594fSAndroid Build Coastguard Worker number_of_sampled_methods += helper.GetNumberOfSampledMethods();
767*795d594fSAndroid Build Coastguard Worker }
768*795d594fSAndroid Build Coastguard Worker }
769*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Profile saver recorded " << number_of_hot_methods
770*795d594fSAndroid Build Coastguard Worker << " hot methods and " << number_of_sampled_methods
771*795d594fSAndroid Build Coastguard Worker << " sampled methods in " << PrettyDuration(NanoTime() - start_time);
772*795d594fSAndroid Build Coastguard Worker }
773*795d594fSAndroid Build Coastguard Worker
ProcessProfilingInfo(bool force_save,uint16_t * number_of_new_methods)774*795d594fSAndroid Build Coastguard Worker bool ProfileSaver::ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number_of_new_methods) {
775*795d594fSAndroid Build Coastguard Worker ScopedTrace trace(__PRETTY_FUNCTION__);
776*795d594fSAndroid Build Coastguard Worker
777*795d594fSAndroid Build Coastguard Worker // Resolve any new registered locations.
778*795d594fSAndroid Build Coastguard Worker ResolveTrackedLocations();
779*795d594fSAndroid Build Coastguard Worker
780*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, std::set<std::string>>> tracked_locations;
781*795d594fSAndroid Build Coastguard Worker SafeMap<std::string, AppInfo::CodeType> profile_to_code_type;
782*795d594fSAndroid Build Coastguard Worker {
783*795d594fSAndroid Build Coastguard Worker // Make a copy so that we don't hold the lock while doing I/O.
784*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
785*795d594fSAndroid Build Coastguard Worker tracked_locations.assign(tracked_dex_base_locations_.begin(),
786*795d594fSAndroid Build Coastguard Worker tracked_dex_base_locations_.end());
787*795d594fSAndroid Build Coastguard Worker for (const auto& [key, value] : tracked_profiles_) {
788*795d594fSAndroid Build Coastguard Worker profile_to_code_type.Put(key, value.second);
789*795d594fSAndroid Build Coastguard Worker }
790*795d594fSAndroid Build Coastguard Worker }
791*795d594fSAndroid Build Coastguard Worker
792*795d594fSAndroid Build Coastguard Worker // Put "primary.prof" at the end. `artd` relies on the fact that "primary.prof" is the last one to
793*795d594fSAndroid Build Coastguard Worker // write when it waits for a profile save to be done.
794*795d594fSAndroid Build Coastguard Worker std::sort(tracked_locations.begin(),
795*795d594fSAndroid Build Coastguard Worker tracked_locations.end(),
796*795d594fSAndroid Build Coastguard Worker [&](const auto& pair1, const auto& pair2) {
797*795d594fSAndroid Build Coastguard Worker return profile_to_code_type.Get(pair1.first) != AppInfo::CodeType::kPrimaryApk &&
798*795d594fSAndroid Build Coastguard Worker profile_to_code_type.Get(pair2.first) == AppInfo::CodeType::kPrimaryApk;
799*795d594fSAndroid Build Coastguard Worker });
800*795d594fSAndroid Build Coastguard Worker
801*795d594fSAndroid Build Coastguard Worker bool profile_file_saved = false;
802*795d594fSAndroid Build Coastguard Worker if (number_of_new_methods != nullptr) {
803*795d594fSAndroid Build Coastguard Worker *number_of_new_methods = 0;
804*795d594fSAndroid Build Coastguard Worker }
805*795d594fSAndroid Build Coastguard Worker
806*795d594fSAndroid Build Coastguard Worker FetchAndCacheResolvedClassesAndMethods(/*startup=*/ false);
807*795d594fSAndroid Build Coastguard Worker
808*795d594fSAndroid Build Coastguard Worker for (const auto& it : tracked_locations) {
809*795d594fSAndroid Build Coastguard Worker if (!force_save && ShuttingDown(Thread::Current())) {
810*795d594fSAndroid Build Coastguard Worker // The ProfileSaver is in shutdown mode, meaning a stop request was made and
811*795d594fSAndroid Build Coastguard Worker // we need to exit cleanly (by waiting for the saver thread to finish). Unless
812*795d594fSAndroid Build Coastguard Worker // we have a request for a forced save, do not do any processing so that we
813*795d594fSAndroid Build Coastguard Worker // speed up the exit.
814*795d594fSAndroid Build Coastguard Worker return true;
815*795d594fSAndroid Build Coastguard Worker }
816*795d594fSAndroid Build Coastguard Worker const std::string& filename = it.first;
817*795d594fSAndroid Build Coastguard Worker const std::set<std::string>& locations = it.second;
818*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Tracked filename " << filename << " locations "
819*795d594fSAndroid Build Coastguard Worker << android::base::Join(locations, ":");
820*795d594fSAndroid Build Coastguard Worker
821*795d594fSAndroid Build Coastguard Worker std::vector<ProfileMethodInfo> profile_methods;
822*795d594fSAndroid Build Coastguard Worker {
823*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
824*795d594fSAndroid Build Coastguard Worker jit_code_cache_->GetProfiledMethods(
825*795d594fSAndroid Build Coastguard Worker locations, profile_methods, options_.GetInlineCacheThreshold());
826*795d594fSAndroid Build Coastguard Worker total_number_of_code_cache_queries_++;
827*795d594fSAndroid Build Coastguard Worker }
828*795d594fSAndroid Build Coastguard Worker {
829*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo info(Runtime::Current()->GetArenaPool(),
830*795d594fSAndroid Build Coastguard Worker /*for_boot_image=*/options_.GetProfileBootClassPath());
831*795d594fSAndroid Build Coastguard Worker // Load the existing profile before saving.
832*795d594fSAndroid Build Coastguard Worker // If the file is updated between `Load` and `Save`, the update will be lost. This is
833*795d594fSAndroid Build Coastguard Worker // acceptable. The main reason is that the lost entries will eventually come back if the user
834*795d594fSAndroid Build Coastguard Worker // keeps using the same methods, or they won't be needed if the user doesn't use the same
835*795d594fSAndroid Build Coastguard Worker // methods again.
836*795d594fSAndroid Build Coastguard Worker if (!info.Load(filename, /*clear_if_invalid=*/true)) {
837*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Could not forcefully load profile " << filename;
838*795d594fSAndroid Build Coastguard Worker continue;
839*795d594fSAndroid Build Coastguard Worker }
840*795d594fSAndroid Build Coastguard Worker
841*795d594fSAndroid Build Coastguard Worker uint64_t last_save_number_of_methods = info.GetNumberOfMethods();
842*795d594fSAndroid Build Coastguard Worker uint64_t last_save_number_of_classes = info.GetNumberOfResolvedClasses();
843*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "last_save_number_of_methods=" << last_save_number_of_methods
844*795d594fSAndroid Build Coastguard Worker << " last_save_number_of_classes=" << last_save_number_of_classes
845*795d594fSAndroid Build Coastguard Worker << " number of profiled methods=" << profile_methods.size();
846*795d594fSAndroid Build Coastguard Worker
847*795d594fSAndroid Build Coastguard Worker // Try to add the method data. Note this may fail is the profile loaded from disk contains
848*795d594fSAndroid Build Coastguard Worker // outdated data (e.g. the previous profiled dex files might have been updated).
849*795d594fSAndroid Build Coastguard Worker // If this happens we clear the profile data and for the save to ensure the file is cleared.
850*795d594fSAndroid Build Coastguard Worker if (!info.AddMethods(
851*795d594fSAndroid Build Coastguard Worker profile_methods,
852*795d594fSAndroid Build Coastguard Worker AnnotateSampleFlags(Hotness::kFlagHot | Hotness::kFlagPostStartup),
853*795d594fSAndroid Build Coastguard Worker GetProfileSampleAnnotation())) {
854*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Could not add methods to the existing profiler. "
855*795d594fSAndroid Build Coastguard Worker << "Clearing the profile data.";
856*795d594fSAndroid Build Coastguard Worker info.ClearData();
857*795d594fSAndroid Build Coastguard Worker force_save = true;
858*795d594fSAndroid Build Coastguard Worker }
859*795d594fSAndroid Build Coastguard Worker
860*795d594fSAndroid Build Coastguard Worker {
861*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
862*795d594fSAndroid Build Coastguard Worker auto profile_cache_it = profile_cache_.find(filename);
863*795d594fSAndroid Build Coastguard Worker if (profile_cache_it != profile_cache_.end()) {
864*795d594fSAndroid Build Coastguard Worker if (!info.MergeWith(*(profile_cache_it->second))) {
865*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Could not merge the profile. Clearing the profile data.";
866*795d594fSAndroid Build Coastguard Worker info.ClearData();
867*795d594fSAndroid Build Coastguard Worker force_save = true;
868*795d594fSAndroid Build Coastguard Worker }
869*795d594fSAndroid Build Coastguard Worker } else if (VLOG_IS_ON(profiler)) {
870*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Failed to find cached profile for " << filename;
871*795d594fSAndroid Build Coastguard Worker for (auto&& pair : profile_cache_) {
872*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Cached profile " << pair.first;
873*795d594fSAndroid Build Coastguard Worker }
874*795d594fSAndroid Build Coastguard Worker }
875*795d594fSAndroid Build Coastguard Worker
876*795d594fSAndroid Build Coastguard Worker int64_t delta_number_of_methods =
877*795d594fSAndroid Build Coastguard Worker info.GetNumberOfMethods() - last_save_number_of_methods;
878*795d594fSAndroid Build Coastguard Worker int64_t delta_number_of_classes =
879*795d594fSAndroid Build Coastguard Worker info.GetNumberOfResolvedClasses() - last_save_number_of_classes;
880*795d594fSAndroid Build Coastguard Worker
881*795d594fSAndroid Build Coastguard Worker // Always write on a forced save. `artd` relies on the fact that profiles are always
882*795d594fSAndroid Build Coastguard Worker // written when it waits for a forced profile save to be done.
883*795d594fSAndroid Build Coastguard Worker if (!force_save &&
884*795d594fSAndroid Build Coastguard Worker delta_number_of_methods < options_.GetMinMethodsToSave() &&
885*795d594fSAndroid Build Coastguard Worker delta_number_of_classes < options_.GetMinClassesToSave()) {
886*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Not enough information to save to: " << filename
887*795d594fSAndroid Build Coastguard Worker << " Number of methods: " << delta_number_of_methods
888*795d594fSAndroid Build Coastguard Worker << " Number of classes: " << delta_number_of_classes;
889*795d594fSAndroid Build Coastguard Worker total_number_of_skipped_writes_++;
890*795d594fSAndroid Build Coastguard Worker continue;
891*795d594fSAndroid Build Coastguard Worker }
892*795d594fSAndroid Build Coastguard Worker
893*795d594fSAndroid Build Coastguard Worker if (number_of_new_methods != nullptr) {
894*795d594fSAndroid Build Coastguard Worker *number_of_new_methods =
895*795d594fSAndroid Build Coastguard Worker std::max(static_cast<uint16_t>(delta_number_of_methods),
896*795d594fSAndroid Build Coastguard Worker *number_of_new_methods);
897*795d594fSAndroid Build Coastguard Worker }
898*795d594fSAndroid Build Coastguard Worker uint64_t bytes_written;
899*795d594fSAndroid Build Coastguard Worker // Force the save. In case the profile data is corrupted or the profile
900*795d594fSAndroid Build Coastguard Worker // has the wrong version this will "fix" the file to the correct format.
901*795d594fSAndroid Build Coastguard Worker if (info.Save(filename, &bytes_written, force_save)) {
902*795d594fSAndroid Build Coastguard Worker // We managed to save the profile. Clear the cache stored during startup.
903*795d594fSAndroid Build Coastguard Worker if (profile_cache_it != profile_cache_.end()) {
904*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo *cached_info = profile_cache_it->second;
905*795d594fSAndroid Build Coastguard Worker profile_cache_.erase(profile_cache_it);
906*795d594fSAndroid Build Coastguard Worker delete cached_info;
907*795d594fSAndroid Build Coastguard Worker }
908*795d594fSAndroid Build Coastguard Worker if (bytes_written > 0) {
909*795d594fSAndroid Build Coastguard Worker total_number_of_writes_++;
910*795d594fSAndroid Build Coastguard Worker total_bytes_written_ += bytes_written;
911*795d594fSAndroid Build Coastguard Worker profile_file_saved = true;
912*795d594fSAndroid Build Coastguard Worker } else {
913*795d594fSAndroid Build Coastguard Worker // At this point we could still have avoided the write.
914*795d594fSAndroid Build Coastguard Worker // We load and merge the data from the file lazily at its first ever
915*795d594fSAndroid Build Coastguard Worker // save attempt. So, whatever we are trying to save could already be
916*795d594fSAndroid Build Coastguard Worker // in the file.
917*795d594fSAndroid Build Coastguard Worker total_number_of_skipped_writes_++;
918*795d594fSAndroid Build Coastguard Worker }
919*795d594fSAndroid Build Coastguard Worker } else {
920*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Could not save profiling info to " << filename;
921*795d594fSAndroid Build Coastguard Worker total_number_of_failed_writes_++;
922*795d594fSAndroid Build Coastguard Worker }
923*795d594fSAndroid Build Coastguard Worker }
924*795d594fSAndroid Build Coastguard Worker }
925*795d594fSAndroid Build Coastguard Worker }
926*795d594fSAndroid Build Coastguard Worker
927*795d594fSAndroid Build Coastguard Worker // Trim the maps to madvise the pages used for profile info.
928*795d594fSAndroid Build Coastguard Worker // It is unlikely we will need them again in the near feature.
929*795d594fSAndroid Build Coastguard Worker Runtime::Current()->GetArenaPool()->TrimMaps();
930*795d594fSAndroid Build Coastguard Worker
931*795d594fSAndroid Build Coastguard Worker return profile_file_saved;
932*795d594fSAndroid Build Coastguard Worker }
933*795d594fSAndroid Build Coastguard Worker
RunProfileSaverThread(void * arg)934*795d594fSAndroid Build Coastguard Worker void* ProfileSaver::RunProfileSaverThread(void* arg) {
935*795d594fSAndroid Build Coastguard Worker Runtime* runtime = Runtime::Current();
936*795d594fSAndroid Build Coastguard Worker
937*795d594fSAndroid Build Coastguard Worker bool attached = runtime->AttachCurrentThread("Profile Saver",
938*795d594fSAndroid Build Coastguard Worker /*as_daemon=*/true,
939*795d594fSAndroid Build Coastguard Worker runtime->GetSystemThreadGroup(),
940*795d594fSAndroid Build Coastguard Worker /*create_peer=*/true);
941*795d594fSAndroid Build Coastguard Worker if (!attached) {
942*795d594fSAndroid Build Coastguard Worker CHECK(runtime->IsShuttingDown(Thread::Current()));
943*795d594fSAndroid Build Coastguard Worker return nullptr;
944*795d594fSAndroid Build Coastguard Worker }
945*795d594fSAndroid Build Coastguard Worker
946*795d594fSAndroid Build Coastguard Worker {
947*795d594fSAndroid Build Coastguard Worker Locks::profiler_lock_->ExclusiveLock(Thread::Current());
948*795d594fSAndroid Build Coastguard Worker CHECK_EQ(reinterpret_cast<ProfileSaver*>(arg), instance_);
949*795d594fSAndroid Build Coastguard Worker instance_->Run();
950*795d594fSAndroid Build Coastguard Worker }
951*795d594fSAndroid Build Coastguard Worker
952*795d594fSAndroid Build Coastguard Worker runtime->DetachCurrentThread();
953*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Profile saver shutdown";
954*795d594fSAndroid Build Coastguard Worker return nullptr;
955*795d594fSAndroid Build Coastguard Worker }
956*795d594fSAndroid Build Coastguard Worker
ShouldProfileLocation(const std::string & location,bool profile_aot_code)957*795d594fSAndroid Build Coastguard Worker static bool ShouldProfileLocation(const std::string& location, bool profile_aot_code) {
958*795d594fSAndroid Build Coastguard Worker if (profile_aot_code) {
959*795d594fSAndroid Build Coastguard Worker // If we have to profile all the code, irrespective of its compilation state, return true
960*795d594fSAndroid Build Coastguard Worker // right away.
961*795d594fSAndroid Build Coastguard Worker return true;
962*795d594fSAndroid Build Coastguard Worker }
963*795d594fSAndroid Build Coastguard Worker
964*795d594fSAndroid Build Coastguard Worker OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager();
965*795d594fSAndroid Build Coastguard Worker const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location);
966*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
967*795d594fSAndroid Build Coastguard Worker // This can happen if we fallback to run code directly from the APK.
968*795d594fSAndroid Build Coastguard Worker // Profile it with the hope that the background dexopt will get us back into
969*795d594fSAndroid Build Coastguard Worker // a good state.
970*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Asked to profile a location without an oat file:" << location;
971*795d594fSAndroid Build Coastguard Worker return true;
972*795d594fSAndroid Build Coastguard Worker }
973*795d594fSAndroid Build Coastguard Worker CompilerFilter::Filter filter = oat_file->GetCompilerFilter();
974*795d594fSAndroid Build Coastguard Worker if ((filter == CompilerFilter::kSpeed) || (filter == CompilerFilter::kEverything)) {
975*795d594fSAndroid Build Coastguard Worker VLOG(profiler)
976*795d594fSAndroid Build Coastguard Worker << "Skip profiling oat file because it's already speed|everything compiled: "
977*795d594fSAndroid Build Coastguard Worker << location << " oat location: " << oat_file->GetLocation();
978*795d594fSAndroid Build Coastguard Worker return false;
979*795d594fSAndroid Build Coastguard Worker }
980*795d594fSAndroid Build Coastguard Worker return true;
981*795d594fSAndroid Build Coastguard Worker }
982*795d594fSAndroid Build Coastguard Worker
Start(const ProfileSaverOptions & options,const std::string & output_filename,jit::JitCodeCache * jit_code_cache,const std::vector<std::string> & code_paths,const std::string & ref_profile_filename,AppInfo::CodeType code_type)983*795d594fSAndroid Build Coastguard Worker void ProfileSaver::Start(const ProfileSaverOptions& options,
984*795d594fSAndroid Build Coastguard Worker const std::string& output_filename,
985*795d594fSAndroid Build Coastguard Worker jit::JitCodeCache* jit_code_cache,
986*795d594fSAndroid Build Coastguard Worker const std::vector<std::string>& code_paths,
987*795d594fSAndroid Build Coastguard Worker const std::string& ref_profile_filename,
988*795d594fSAndroid Build Coastguard Worker AppInfo::CodeType code_type) {
989*795d594fSAndroid Build Coastguard Worker Runtime* const runtime = Runtime::Current();
990*795d594fSAndroid Build Coastguard Worker DCHECK(options.IsEnabled());
991*795d594fSAndroid Build Coastguard Worker DCHECK(runtime->GetJit() != nullptr);
992*795d594fSAndroid Build Coastguard Worker DCHECK(!output_filename.empty());
993*795d594fSAndroid Build Coastguard Worker DCHECK(jit_code_cache != nullptr);
994*795d594fSAndroid Build Coastguard Worker
995*795d594fSAndroid Build Coastguard Worker std::vector<std::string> code_paths_to_profile;
996*795d594fSAndroid Build Coastguard Worker for (const std::string& location : code_paths) {
997*795d594fSAndroid Build Coastguard Worker if (ShouldProfileLocation(location, options.GetProfileAOTCode())) {
998*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Code path to profile " << location;
999*795d594fSAndroid Build Coastguard Worker code_paths_to_profile.push_back(location);
1000*795d594fSAndroid Build Coastguard Worker }
1001*795d594fSAndroid Build Coastguard Worker }
1002*795d594fSAndroid Build Coastguard Worker
1003*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
1004*795d594fSAndroid Build Coastguard Worker // Support getting profile samples for the boot class path. This will be used to generate the boot
1005*795d594fSAndroid Build Coastguard Worker // image profile. The intention is to use this code to generate to boot image but not use it in
1006*795d594fSAndroid Build Coastguard Worker // production. b/37966211
1007*795d594fSAndroid Build Coastguard Worker if (options.GetProfileBootClassPath()) {
1008*795d594fSAndroid Build Coastguard Worker std::set<std::string> code_paths_keys;
1009*795d594fSAndroid Build Coastguard Worker for (const std::string& location : code_paths) {
1010*795d594fSAndroid Build Coastguard Worker // Use the profile base key for checking file uniqueness (as it is constructed solely based
1011*795d594fSAndroid Build Coastguard Worker // on the location and ignores other metadata like origin package).
1012*795d594fSAndroid Build Coastguard Worker code_paths_keys.insert(ProfileCompilationInfo::GetProfileDexFileBaseKey(location));
1013*795d594fSAndroid Build Coastguard Worker }
1014*795d594fSAndroid Build Coastguard Worker for (const DexFile* dex_file : runtime->GetClassLinker()->GetBootClassPath()) {
1015*795d594fSAndroid Build Coastguard Worker // Don't check ShouldProfileLocation since the boot class path may be speed compiled.
1016*795d594fSAndroid Build Coastguard Worker const std::string& location = dex_file->GetLocation();
1017*795d594fSAndroid Build Coastguard Worker const std::string key = ProfileCompilationInfo::GetProfileDexFileBaseKey(location);
1018*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Registering boot dex file " << location;
1019*795d594fSAndroid Build Coastguard Worker if (code_paths_keys.find(key) != code_paths_keys.end()) {
1020*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Boot class path location key conflicts with code path " << location;
1021*795d594fSAndroid Build Coastguard Worker } else if (instance_ == nullptr) {
1022*795d594fSAndroid Build Coastguard Worker // Only add the boot class path once since Start may be called multiple times for secondary
1023*795d594fSAndroid Build Coastguard Worker // dexes.
1024*795d594fSAndroid Build Coastguard Worker // We still do the collision check above. This handles any secondary dexes that conflict
1025*795d594fSAndroid Build Coastguard Worker // with the boot class path dex files.
1026*795d594fSAndroid Build Coastguard Worker code_paths_to_profile.push_back(location);
1027*795d594fSAndroid Build Coastguard Worker }
1028*795d594fSAndroid Build Coastguard Worker }
1029*795d594fSAndroid Build Coastguard Worker }
1030*795d594fSAndroid Build Coastguard Worker if (code_paths_to_profile.empty()) {
1031*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "No code paths should be profiled.";
1032*795d594fSAndroid Build Coastguard Worker return;
1033*795d594fSAndroid Build Coastguard Worker }
1034*795d594fSAndroid Build Coastguard Worker
1035*795d594fSAndroid Build Coastguard Worker if (instance_ != nullptr) {
1036*795d594fSAndroid Build Coastguard Worker // If we already have an instance, make sure it uses the same jit_code_cache.
1037*795d594fSAndroid Build Coastguard Worker // This may be called multiple times via Runtime::registerAppInfo (e.g. for
1038*795d594fSAndroid Build Coastguard Worker // apps which share the same runtime).
1039*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache);
1040*795d594fSAndroid Build Coastguard Worker // Add the code_paths to the tracked locations.
1041*795d594fSAndroid Build Coastguard Worker instance_->AddTrackedLocations(
1042*795d594fSAndroid Build Coastguard Worker output_filename, code_paths_to_profile, ref_profile_filename, code_type);
1043*795d594fSAndroid Build Coastguard Worker return;
1044*795d594fSAndroid Build Coastguard Worker }
1045*795d594fSAndroid Build Coastguard Worker
1046*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Starting profile saver using output file: " << output_filename
1047*795d594fSAndroid Build Coastguard Worker << ". Tracking: " << android::base::Join(code_paths_to_profile, ':')
1048*795d594fSAndroid Build Coastguard Worker << ". With reference profile: " << ref_profile_filename;
1049*795d594fSAndroid Build Coastguard Worker
1050*795d594fSAndroid Build Coastguard Worker instance_ = new ProfileSaver(options, jit_code_cache);
1051*795d594fSAndroid Build Coastguard Worker instance_->AddTrackedLocations(
1052*795d594fSAndroid Build Coastguard Worker output_filename, code_paths_to_profile, ref_profile_filename, code_type);
1053*795d594fSAndroid Build Coastguard Worker
1054*795d594fSAndroid Build Coastguard Worker // Create a new thread which does the saving.
1055*795d594fSAndroid Build Coastguard Worker CHECK_PTHREAD_CALL(
1056*795d594fSAndroid Build Coastguard Worker pthread_create,
1057*795d594fSAndroid Build Coastguard Worker (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
1058*795d594fSAndroid Build Coastguard Worker "Profile saver thread");
1059*795d594fSAndroid Build Coastguard Worker
1060*795d594fSAndroid Build Coastguard Worker SetProfileSaverThreadPriority(profiler_pthread_, kProfileSaverPthreadPriority);
1061*795d594fSAndroid Build Coastguard Worker }
1062*795d594fSAndroid Build Coastguard Worker
Stop(bool dump_info)1063*795d594fSAndroid Build Coastguard Worker void ProfileSaver::Stop(bool dump_info) {
1064*795d594fSAndroid Build Coastguard Worker ProfileSaver* profile_saver = nullptr;
1065*795d594fSAndroid Build Coastguard Worker pthread_t profiler_pthread = 0U;
1066*795d594fSAndroid Build Coastguard Worker
1067*795d594fSAndroid Build Coastguard Worker {
1068*795d594fSAndroid Build Coastguard Worker MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
1069*795d594fSAndroid Build Coastguard Worker VLOG(profiler) << "Stopping profile saver thread";
1070*795d594fSAndroid Build Coastguard Worker profile_saver = instance_;
1071*795d594fSAndroid Build Coastguard Worker profiler_pthread = profiler_pthread_;
1072*795d594fSAndroid Build Coastguard Worker if (instance_ == nullptr) {
1073*795d594fSAndroid Build Coastguard Worker DCHECK(false) << "Tried to stop a profile saver which was not started";
1074*795d594fSAndroid Build Coastguard Worker return;
1075*795d594fSAndroid Build Coastguard Worker }
1076*795d594fSAndroid Build Coastguard Worker if (instance_->shutting_down_) {
1077*795d594fSAndroid Build Coastguard Worker DCHECK(false) << "Tried to stop the profile saver twice";
1078*795d594fSAndroid Build Coastguard Worker return;
1079*795d594fSAndroid Build Coastguard Worker }
1080*795d594fSAndroid Build Coastguard Worker instance_->shutting_down_ = true;
1081*795d594fSAndroid Build Coastguard Worker }
1082*795d594fSAndroid Build Coastguard Worker
1083*795d594fSAndroid Build Coastguard Worker {
1084*795d594fSAndroid Build Coastguard Worker // Wake up the saver thread if it is sleeping to allow for a clean exit.
1085*795d594fSAndroid Build Coastguard Worker MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_);
1086*795d594fSAndroid Build Coastguard Worker profile_saver->period_condition_.Signal(Thread::Current());
1087*795d594fSAndroid Build Coastguard Worker }
1088*795d594fSAndroid Build Coastguard Worker
1089*795d594fSAndroid Build Coastguard Worker // Force save everything before destroying the thread since we want profiler_pthread_ to remain
1090*795d594fSAndroid Build Coastguard Worker // valid.
1091*795d594fSAndroid Build Coastguard Worker profile_saver->ProcessProfilingInfo(/*force_ save=*/ true, /*number_of_new_methods=*/ nullptr);
1092*795d594fSAndroid Build Coastguard Worker
1093*795d594fSAndroid Build Coastguard Worker // Wait for the saver thread to stop.
1094*795d594fSAndroid Build Coastguard Worker CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
1095*795d594fSAndroid Build Coastguard Worker
1096*795d594fSAndroid Build Coastguard Worker {
1097*795d594fSAndroid Build Coastguard Worker MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
1098*795d594fSAndroid Build Coastguard Worker if (dump_info) {
1099*795d594fSAndroid Build Coastguard Worker instance_->DumpInfo(LOG_STREAM(INFO));
1100*795d594fSAndroid Build Coastguard Worker }
1101*795d594fSAndroid Build Coastguard Worker instance_ = nullptr;
1102*795d594fSAndroid Build Coastguard Worker profiler_pthread_ = 0U;
1103*795d594fSAndroid Build Coastguard Worker }
1104*795d594fSAndroid Build Coastguard Worker delete profile_saver;
1105*795d594fSAndroid Build Coastguard Worker }
1106*795d594fSAndroid Build Coastguard Worker
ShuttingDown(Thread * self)1107*795d594fSAndroid Build Coastguard Worker bool ProfileSaver::ShuttingDown(Thread* self) {
1108*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *Locks::profiler_lock_);
1109*795d594fSAndroid Build Coastguard Worker return shutting_down_;
1110*795d594fSAndroid Build Coastguard Worker }
1111*795d594fSAndroid Build Coastguard Worker
IsStarted()1112*795d594fSAndroid Build Coastguard Worker bool ProfileSaver::IsStarted() {
1113*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
1114*795d594fSAndroid Build Coastguard Worker return instance_ != nullptr;
1115*795d594fSAndroid Build Coastguard Worker }
1116*795d594fSAndroid Build Coastguard Worker
AddTrackedLocationsToMap(const std::string & output_filename,const std::vector<std::string> & code_paths,SafeMap<std::string,std::set<std::string>> * map)1117*795d594fSAndroid Build Coastguard Worker static void AddTrackedLocationsToMap(const std::string& output_filename,
1118*795d594fSAndroid Build Coastguard Worker const std::vector<std::string>& code_paths,
1119*795d594fSAndroid Build Coastguard Worker SafeMap<std::string, std::set<std::string>>* map) {
1120*795d594fSAndroid Build Coastguard Worker std::vector<std::string> code_paths_and_filenames;
1121*795d594fSAndroid Build Coastguard Worker // The dex locations are sometimes set to the filename instead of the full path.
1122*795d594fSAndroid Build Coastguard Worker // So make sure we have both "locations" when tracking what needs to be profiled.
1123*795d594fSAndroid Build Coastguard Worker // - apps + system server have filenames
1124*795d594fSAndroid Build Coastguard Worker // - boot classpath elements have full paths
1125*795d594fSAndroid Build Coastguard Worker
1126*795d594fSAndroid Build Coastguard Worker // TODO(calin, ngeoffray, vmarko) This is an workaround for using filanames as
1127*795d594fSAndroid Build Coastguard Worker // dex locations - needed to prebuilt with a partial boot image
1128*795d594fSAndroid Build Coastguard Worker // (commit: c4a924d8c74241057d957d360bf31cd5cd0e4f9c).
1129*795d594fSAndroid Build Coastguard Worker // We should find a better way which allows us to do the tracking based on full paths.
1130*795d594fSAndroid Build Coastguard Worker for (const std::string& path : code_paths) {
1131*795d594fSAndroid Build Coastguard Worker size_t last_sep_index = path.find_last_of('/');
1132*795d594fSAndroid Build Coastguard Worker if (path.empty() || last_sep_index == path.size() - 1) {
1133*795d594fSAndroid Build Coastguard Worker // Should not happen, but anyone can register code paths so better be prepared and ignore
1134*795d594fSAndroid Build Coastguard Worker // such locations.
1135*795d594fSAndroid Build Coastguard Worker continue;
1136*795d594fSAndroid Build Coastguard Worker }
1137*795d594fSAndroid Build Coastguard Worker std::string filename = last_sep_index == std::string::npos
1138*795d594fSAndroid Build Coastguard Worker ? path
1139*795d594fSAndroid Build Coastguard Worker : path.substr(last_sep_index + 1);
1140*795d594fSAndroid Build Coastguard Worker
1141*795d594fSAndroid Build Coastguard Worker code_paths_and_filenames.push_back(path);
1142*795d594fSAndroid Build Coastguard Worker code_paths_and_filenames.push_back(filename);
1143*795d594fSAndroid Build Coastguard Worker }
1144*795d594fSAndroid Build Coastguard Worker
1145*795d594fSAndroid Build Coastguard Worker auto it = map->FindOrAdd(output_filename);
1146*795d594fSAndroid Build Coastguard Worker it->second.insert(code_paths_and_filenames.begin(), code_paths_and_filenames.end());
1147*795d594fSAndroid Build Coastguard Worker }
1148*795d594fSAndroid Build Coastguard Worker
AddTrackedLocations(const std::string & output_filename,const std::vector<std::string> & code_paths,const std::string & ref_profile_filename,AppInfo::CodeType code_type)1149*795d594fSAndroid Build Coastguard Worker void ProfileSaver::AddTrackedLocations(const std::string& output_filename,
1150*795d594fSAndroid Build Coastguard Worker const std::vector<std::string>& code_paths,
1151*795d594fSAndroid Build Coastguard Worker const std::string& ref_profile_filename,
1152*795d594fSAndroid Build Coastguard Worker AppInfo::CodeType code_type) {
1153*795d594fSAndroid Build Coastguard Worker // Register the output profile and its reference profile.
1154*795d594fSAndroid Build Coastguard Worker auto it = tracked_profiles_.find(output_filename);
1155*795d594fSAndroid Build Coastguard Worker if (it == tracked_profiles_.end()) {
1156*795d594fSAndroid Build Coastguard Worker tracked_profiles_.Put(output_filename, std::make_pair(ref_profile_filename, code_type));
1157*795d594fSAndroid Build Coastguard Worker }
1158*795d594fSAndroid Build Coastguard Worker
1159*795d594fSAndroid Build Coastguard Worker // Add the code paths to the list of tracked location.
1160*795d594fSAndroid Build Coastguard Worker AddTrackedLocationsToMap(output_filename, code_paths, &tracked_dex_base_locations_);
1161*795d594fSAndroid Build Coastguard Worker // The code paths may contain symlinks which could fool the profiler.
1162*795d594fSAndroid Build Coastguard Worker // If the dex file is compiled with an absolute location but loaded with symlink
1163*795d594fSAndroid Build Coastguard Worker // the profiler could skip the dex due to location mismatch.
1164*795d594fSAndroid Build Coastguard Worker // To avoid this, we add the code paths to the temporary cache of 'to_be_resolved'
1165*795d594fSAndroid Build Coastguard Worker // locations. When the profiler thread executes we will resolve the paths to their
1166*795d594fSAndroid Build Coastguard Worker // real paths.
1167*795d594fSAndroid Build Coastguard Worker // Note that we delay taking the realpath to avoid spending more time than needed
1168*795d594fSAndroid Build Coastguard Worker // when registering location (as it is done during app launch).
1169*795d594fSAndroid Build Coastguard Worker AddTrackedLocationsToMap(output_filename,
1170*795d594fSAndroid Build Coastguard Worker code_paths,
1171*795d594fSAndroid Build Coastguard Worker &tracked_dex_base_locations_to_be_resolved_);
1172*795d594fSAndroid Build Coastguard Worker }
1173*795d594fSAndroid Build Coastguard Worker
DumpInstanceInfo(std::ostream & os)1174*795d594fSAndroid Build Coastguard Worker void ProfileSaver::DumpInstanceInfo(std::ostream& os) {
1175*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
1176*795d594fSAndroid Build Coastguard Worker if (instance_ != nullptr) {
1177*795d594fSAndroid Build Coastguard Worker instance_->DumpInfo(os);
1178*795d594fSAndroid Build Coastguard Worker }
1179*795d594fSAndroid Build Coastguard Worker }
1180*795d594fSAndroid Build Coastguard Worker
DumpInfo(std::ostream & os)1181*795d594fSAndroid Build Coastguard Worker void ProfileSaver::DumpInfo(std::ostream& os) {
1182*795d594fSAndroid Build Coastguard Worker os << "ProfileSaver total_bytes_written=" << total_bytes_written_ << '\n'
1183*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_number_of_writes=" << total_number_of_writes_ << '\n'
1184*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_number_of_code_cache_queries="
1185*795d594fSAndroid Build Coastguard Worker << total_number_of_code_cache_queries_ << '\n'
1186*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_number_of_skipped_writes=" << total_number_of_skipped_writes_ << '\n'
1187*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_number_of_failed_writes=" << total_number_of_failed_writes_ << '\n'
1188*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_ms_of_sleep=" << total_ms_of_sleep_ << '\n'
1189*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_ms_of_work=" << NsToMs(total_ns_of_work_) << '\n'
1190*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_number_of_hot_spikes=" << total_number_of_hot_spikes_ << '\n'
1191*795d594fSAndroid Build Coastguard Worker << "ProfileSaver total_number_of_wake_ups=" << total_number_of_wake_ups_ << '\n';
1192*795d594fSAndroid Build Coastguard Worker }
1193*795d594fSAndroid Build Coastguard Worker
1194*795d594fSAndroid Build Coastguard Worker
ForceProcessProfiles()1195*795d594fSAndroid Build Coastguard Worker void ProfileSaver::ForceProcessProfiles() {
1196*795d594fSAndroid Build Coastguard Worker ProfileSaver* saver = nullptr;
1197*795d594fSAndroid Build Coastguard Worker {
1198*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
1199*795d594fSAndroid Build Coastguard Worker saver = instance_;
1200*795d594fSAndroid Build Coastguard Worker }
1201*795d594fSAndroid Build Coastguard Worker // TODO(calin): this is not actually thread safe as the instance_ may have been deleted,
1202*795d594fSAndroid Build Coastguard Worker // but we only use this in testing when we now this won't happen.
1203*795d594fSAndroid Build Coastguard Worker // Refactor the way we handle the instance so that we don't end up in this situation.
1204*795d594fSAndroid Build Coastguard Worker if (saver != nullptr) {
1205*795d594fSAndroid Build Coastguard Worker saver->ProcessProfilingInfo(/*force_save=*/ true, /*number_of_new_methods=*/ nullptr);
1206*795d594fSAndroid Build Coastguard Worker }
1207*795d594fSAndroid Build Coastguard Worker }
1208*795d594fSAndroid Build Coastguard Worker
ResolveTrackedLocations()1209*795d594fSAndroid Build Coastguard Worker void ProfileSaver::ResolveTrackedLocations() {
1210*795d594fSAndroid Build Coastguard Worker SafeMap<std::string, std::set<std::string>> locations_to_be_resolved;
1211*795d594fSAndroid Build Coastguard Worker {
1212*795d594fSAndroid Build Coastguard Worker // Make a copy so that we don't hold the lock while doing I/O.
1213*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
1214*795d594fSAndroid Build Coastguard Worker locations_to_be_resolved = tracked_dex_base_locations_to_be_resolved_;
1215*795d594fSAndroid Build Coastguard Worker tracked_dex_base_locations_to_be_resolved_.clear();
1216*795d594fSAndroid Build Coastguard Worker }
1217*795d594fSAndroid Build Coastguard Worker
1218*795d594fSAndroid Build Coastguard Worker // Resolve the locations.
1219*795d594fSAndroid Build Coastguard Worker SafeMap<std::string, std::vector<std::string>> resolved_locations_map;
1220*795d594fSAndroid Build Coastguard Worker for (const auto& it : locations_to_be_resolved) {
1221*795d594fSAndroid Build Coastguard Worker const std::string& filename = it.first;
1222*795d594fSAndroid Build Coastguard Worker const std::set<std::string>& locations = it.second;
1223*795d594fSAndroid Build Coastguard Worker auto resolved_locations_it = resolved_locations_map.Put(filename, std::vector<std::string>());
1224*795d594fSAndroid Build Coastguard Worker resolved_locations_it->second.reserve(locations.size());
1225*795d594fSAndroid Build Coastguard Worker
1226*795d594fSAndroid Build Coastguard Worker for (const auto& location : locations) {
1227*795d594fSAndroid Build Coastguard Worker UniqueCPtr<const char[]> location_real(realpath(location.c_str(), nullptr));
1228*795d594fSAndroid Build Coastguard Worker // Note that it's ok if we cannot get the real path.
1229*795d594fSAndroid Build Coastguard Worker if (location_real != nullptr) {
1230*795d594fSAndroid Build Coastguard Worker resolved_locations_it->second.emplace_back(location_real.get());
1231*795d594fSAndroid Build Coastguard Worker }
1232*795d594fSAndroid Build Coastguard Worker }
1233*795d594fSAndroid Build Coastguard Worker }
1234*795d594fSAndroid Build Coastguard Worker
1235*795d594fSAndroid Build Coastguard Worker // Add the resolved locations to the tracked collection.
1236*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
1237*795d594fSAndroid Build Coastguard Worker for (const auto& it : resolved_locations_map) {
1238*795d594fSAndroid Build Coastguard Worker AddTrackedLocationsToMap(it.first, it.second, &tracked_dex_base_locations_);
1239*795d594fSAndroid Build Coastguard Worker }
1240*795d594fSAndroid Build Coastguard Worker }
1241*795d594fSAndroid Build Coastguard Worker
GetProfileSampleAnnotation()1242*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo::ProfileSampleAnnotation ProfileSaver::GetProfileSampleAnnotation() {
1243*795d594fSAndroid Build Coastguard Worker // Ideally, this would be cached in the ProfileSaver class, when we start the thread.
1244*795d594fSAndroid Build Coastguard Worker // However the profile is initialized before the process package name is set and fixing this
1245*795d594fSAndroid Build Coastguard Worker // would require unnecessary complex synchronizations.
1246*795d594fSAndroid Build Coastguard Worker std::string package_name = Runtime::Current()->GetProcessPackageName();
1247*795d594fSAndroid Build Coastguard Worker if (package_name.empty()) {
1248*795d594fSAndroid Build Coastguard Worker package_name = "unknown";
1249*795d594fSAndroid Build Coastguard Worker }
1250*795d594fSAndroid Build Coastguard Worker // We only use annotation for the boot image profiles. Regular apps do not use the extra
1251*795d594fSAndroid Build Coastguard Worker // metadata and as such there is no need to pay the cost (storage and computational)
1252*795d594fSAndroid Build Coastguard Worker // that comes with the annotations.
1253*795d594fSAndroid Build Coastguard Worker return options_.GetProfileBootClassPath()
1254*795d594fSAndroid Build Coastguard Worker ? ProfileCompilationInfo::ProfileSampleAnnotation(package_name)
1255*795d594fSAndroid Build Coastguard Worker : ProfileCompilationInfo::ProfileSampleAnnotation::kNone;
1256*795d594fSAndroid Build Coastguard Worker }
1257*795d594fSAndroid Build Coastguard Worker
GetExtraMethodHotnessFlags(const ProfileSaverOptions & options)1258*795d594fSAndroid Build Coastguard Worker uint32_t ProfileSaver::GetExtraMethodHotnessFlags(const ProfileSaverOptions& options) {
1259*795d594fSAndroid Build Coastguard Worker // We only add the extra flags for the boot image profile because individual apps do not use
1260*795d594fSAndroid Build Coastguard Worker // this information.
1261*795d594fSAndroid Build Coastguard Worker if (options.GetProfileBootClassPath()) {
1262*795d594fSAndroid Build Coastguard Worker return Is64BitInstructionSet(Runtime::Current()->GetInstructionSet())
1263*795d594fSAndroid Build Coastguard Worker ? Hotness::kFlag64bit
1264*795d594fSAndroid Build Coastguard Worker : Hotness::kFlag32bit;
1265*795d594fSAndroid Build Coastguard Worker } else {
1266*795d594fSAndroid Build Coastguard Worker return 0u;
1267*795d594fSAndroid Build Coastguard Worker }
1268*795d594fSAndroid Build Coastguard Worker }
1269*795d594fSAndroid Build Coastguard Worker
AnnotateSampleFlags(uint32_t flags)1270*795d594fSAndroid Build Coastguard Worker Hotness::Flag ProfileSaver::AnnotateSampleFlags(uint32_t flags) {
1271*795d594fSAndroid Build Coastguard Worker uint32_t extra_flags = GetExtraMethodHotnessFlags(options_);
1272*795d594fSAndroid Build Coastguard Worker return static_cast<Hotness::Flag>(flags | extra_flags);
1273*795d594fSAndroid Build Coastguard Worker }
1274*795d594fSAndroid Build Coastguard Worker
1275*795d594fSAndroid Build Coastguard Worker } // namespace art
1276