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