xref: /aosp_15_r20/art/runtime/jit/profile_saver.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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, &param);
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