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 <sys/types.h> 20 #include <sys/stat.h> 21 #include <fcntl.h> 22 23 #include "art_method-inl.h" 24 #include "base/systrace.h" 25 #include "base/time_utils.h" 26 #include "compiler_filter.h" 27 #include "oat_file_manager.h" 28 #include "scoped_thread_state_change.h" 29 30 31 namespace art { 32 33 // TODO: read the constants from ProfileOptions, 34 // Add a random delay each time we go to sleep so that we don't hammer the CPU 35 // with all profile savers running at the same time. 36 static constexpr const uint64_t kMinSavePeriodNs = MsToNs(20 * 1000); // 20 seconds 37 static constexpr const uint64_t kSaveResolvedClassesDelayMs = 2 * 1000; // 2 seconds 38 // Minimum number of JIT samples during launch to include a method into the profile. 39 static constexpr const size_t kStartupMethodSamples = 1; 40 41 static constexpr const uint32_t kMinimumNumberOfMethodsToSave = 10; 42 static constexpr const uint32_t kMinimumNumberOfClassesToSave = 10; 43 static constexpr const uint32_t kMinimumNumberOfNotificationBeforeWake = 44 kMinimumNumberOfMethodsToSave; 45 static constexpr const uint32_t kMaximumNumberOfNotificationBeforeWake = 50; 46 47 48 ProfileSaver* ProfileSaver::instance_ = nullptr; 49 pthread_t ProfileSaver::profiler_pthread_ = 0U; 50 51 ProfileSaver::ProfileSaver(const std::string& output_filename, 52 jit::JitCodeCache* jit_code_cache, 53 const std::vector<std::string>& code_paths, 54 const std::string& foreign_dex_profile_path, 55 const std::string& app_data_dir) 56 : jit_code_cache_(jit_code_cache), 57 foreign_dex_profile_path_(foreign_dex_profile_path), 58 shutting_down_(false), 59 last_save_number_of_methods_(0), 60 last_save_number_of_classes_(0), 61 last_time_ns_saver_woke_up_(0), 62 jit_activity_notifications_(0), 63 wait_lock_("ProfileSaver wait lock"), 64 period_condition_("ProfileSaver period condition", wait_lock_), 65 total_bytes_written_(0), 66 total_number_of_writes_(0), 67 total_number_of_code_cache_queries_(0), 68 total_number_of_skipped_writes_(0), 69 total_number_of_failed_writes_(0), 70 total_ms_of_sleep_(0), 71 total_ns_of_work_(0), 72 total_number_of_foreign_dex_marks_(0), 73 max_number_of_profile_entries_cached_(0), 74 total_number_of_hot_spikes_(0), 75 total_number_of_wake_ups_(0) { 76 AddTrackedLocations(output_filename, app_data_dir, code_paths); 77 } 78 79 void ProfileSaver::Run() { 80 Thread* self = Thread::Current(); 81 82 // Fetch the resolved classes for the app images after sleeping for 83 // kSaveResolvedClassesDelayMs. 84 // TODO(calin) This only considers the case of the primary profile file. 85 // Anything that gets loaded in the same VM will not have their resolved 86 // classes save (unless they started before the initial saving was done). 87 { 88 MutexLock mu(self, wait_lock_); 89 constexpr uint64_t kSleepTime = kSaveResolvedClassesDelayMs; 90 const uint64_t end_time = NanoTime() + MsToNs(kSleepTime); 91 while (true) { 92 const uint64_t current_time = NanoTime(); 93 if (current_time >= end_time) { 94 break; 95 } 96 period_condition_.TimedWait(self, NsToMs(end_time - current_time), 0); 97 } 98 total_ms_of_sleep_ += kSaveResolvedClassesDelayMs; 99 } 100 FetchAndCacheResolvedClassesAndMethods(); 101 102 // Loop for the profiled methods. 103 while (!ShuttingDown(self)) { 104 uint64_t sleep_start = NanoTime(); 105 { 106 uint64_t sleep_time = 0; 107 { 108 MutexLock mu(self, wait_lock_); 109 period_condition_.Wait(self); 110 sleep_time = NanoTime() - sleep_start; 111 } 112 // Check if the thread was woken up for shutdown. 113 if (ShuttingDown(self)) { 114 break; 115 } 116 total_number_of_wake_ups_++; 117 // We might have been woken up by a huge number of notifications to guarantee saving. 118 // If we didn't meet the minimum saving period go back to sleep (only if missed by 119 // a reasonable margin). 120 while (kMinSavePeriodNs * 0.9 > sleep_time) { 121 { 122 MutexLock mu(self, wait_lock_); 123 period_condition_.TimedWait(self, NsToMs(kMinSavePeriodNs - sleep_time), 0); 124 sleep_time = NanoTime() - sleep_start; 125 } 126 // Check if the thread was woken up for shutdown. 127 if (ShuttingDown(self)) { 128 break; 129 } 130 total_number_of_wake_ups_++; 131 } 132 } 133 total_ms_of_sleep_ += NsToMs(NanoTime() - sleep_start); 134 135 if (ShuttingDown(self)) { 136 break; 137 } 138 139 uint16_t new_methods = 0; 140 uint64_t start_work = NanoTime(); 141 bool profile_saved_to_disk = ProcessProfilingInfo(&new_methods); 142 // Update the notification counter based on result. Note that there might be contention on this 143 // but we don't care about to be 100% precise. 144 if (!profile_saved_to_disk) { 145 // If we didn't save to disk it may be because we didn't have enough new methods. 146 // Set the jit activity notifications to new_methods so we can wake up earlier if needed. 147 jit_activity_notifications_ = new_methods; 148 } 149 total_ns_of_work_ += NanoTime() - start_work; 150 } 151 } 152 153 void ProfileSaver::NotifyJitActivity() { 154 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 155 if (instance_ == nullptr || instance_->shutting_down_) { 156 return; 157 } 158 instance_->NotifyJitActivityInternal(); 159 } 160 161 void ProfileSaver::WakeUpSaver() { 162 jit_activity_notifications_ = 0; 163 last_time_ns_saver_woke_up_ = NanoTime(); 164 period_condition_.Signal(Thread::Current()); 165 } 166 167 void ProfileSaver::NotifyJitActivityInternal() { 168 // Unlikely to overflow but if it happens, 169 // we would have waken up the saver long before that. 170 jit_activity_notifications_++; 171 // Note that we are not as precise as we could be here but we don't want to wake the saver 172 // every time we see a hot method. 173 if (jit_activity_notifications_ > kMinimumNumberOfNotificationBeforeWake) { 174 MutexLock wait_mutex(Thread::Current(), wait_lock_); 175 if ((NanoTime() - last_time_ns_saver_woke_up_) > kMinSavePeriodNs) { 176 WakeUpSaver(); 177 } 178 } else if (jit_activity_notifications_ > kMaximumNumberOfNotificationBeforeWake) { 179 // Make sure to wake up the saver if we see a spike in the number of notifications. 180 // This is a precaution to avoid "loosing" a big number of methods in case 181 // this is a spike with no jit after. 182 total_number_of_hot_spikes_++; 183 MutexLock wait_mutex(Thread::Current(), wait_lock_); 184 WakeUpSaver(); 185 } 186 } 187 188 ProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) { 189 auto info_it = profile_cache_.find(filename); 190 if (info_it == profile_cache_.end()) { 191 info_it = profile_cache_.Put(filename, ProfileCompilationInfo()); 192 } 193 return &info_it->second; 194 } 195 196 // Get resolved methods that have a profile info or more than kStartupMethodSamples samples. 197 // Excludes native methods and classes in the boot image. 198 class GetMethodsVisitor : public ClassVisitor { 199 public: 200 explicit GetMethodsVisitor(std::vector<MethodReference>* methods) : methods_(methods) {} 201 202 virtual bool operator()(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_) { 203 if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { 204 return true; 205 } 206 for (ArtMethod& method : klass->GetMethods(sizeof(void*))) { 207 if (!method.IsNative()) { 208 if (method.GetCounter() >= kStartupMethodSamples || 209 method.GetProfilingInfo(sizeof(void*)) != nullptr) { 210 // Have samples, add to profile. 211 const DexFile* dex_file = method.GetInterfaceMethodIfProxy(sizeof(void*))->GetDexFile(); 212 methods_->push_back(MethodReference(dex_file, method.GetDexMethodIndex())); 213 } 214 } 215 } 216 return true; 217 } 218 219 private: 220 std::vector<MethodReference>* const methods_; 221 }; 222 223 void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() { 224 ScopedTrace trace(__PRETTY_FUNCTION__); 225 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); 226 std::set<DexCacheResolvedClasses> resolved_classes = 227 class_linker->GetResolvedClasses(/*ignore boot classes*/ true); 228 229 std::vector<MethodReference> methods; 230 { 231 ScopedTrace trace2("Get hot methods"); 232 GetMethodsVisitor visitor(&methods); 233 ScopedObjectAccess soa(Thread::Current()); 234 class_linker->VisitClasses(&visitor); 235 VLOG(profiler) << "Methods with samples greater than " 236 << kStartupMethodSamples << " = " << methods.size(); 237 } 238 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 239 uint64_t total_number_of_profile_entries_cached = 0; 240 241 for (const auto& it : tracked_dex_base_locations_) { 242 std::set<DexCacheResolvedClasses> resolved_classes_for_location; 243 const std::string& filename = it.first; 244 const std::set<std::string>& locations = it.second; 245 std::vector<MethodReference> methods_for_location; 246 for (const MethodReference& ref : methods) { 247 if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) { 248 methods_for_location.push_back(ref); 249 } 250 } 251 for (const DexCacheResolvedClasses& classes : resolved_classes) { 252 if (locations.find(classes.GetBaseLocation()) != locations.end()) { 253 VLOG(profiler) << "Added " << classes.GetClasses().size() << " classes for location " 254 << classes.GetBaseLocation() << " (" << classes.GetDexLocation() << ")"; 255 resolved_classes_for_location.insert(classes); 256 } else { 257 VLOG(profiler) << "Location not found " << classes.GetBaseLocation() 258 << " (" << classes.GetDexLocation() << ")"; 259 } 260 } 261 ProfileCompilationInfo* info = GetCachedProfiledInfo(filename); 262 info->AddMethodsAndClasses(methods_for_location, resolved_classes_for_location); 263 total_number_of_profile_entries_cached += resolved_classes_for_location.size(); 264 } 265 max_number_of_profile_entries_cached_ = std::max( 266 max_number_of_profile_entries_cached_, 267 total_number_of_profile_entries_cached); 268 } 269 270 bool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) { 271 ScopedTrace trace(__PRETTY_FUNCTION__); 272 SafeMap<std::string, std::set<std::string>> tracked_locations; 273 { 274 // Make a copy so that we don't hold the lock while doing I/O. 275 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 276 tracked_locations = tracked_dex_base_locations_; 277 } 278 279 bool profile_file_saved = false; 280 uint64_t total_number_of_profile_entries_cached = 0; 281 *new_methods = 0; 282 283 for (const auto& it : tracked_locations) { 284 if (ShuttingDown(Thread::Current())) { 285 return true; 286 } 287 const std::string& filename = it.first; 288 const std::set<std::string>& locations = it.second; 289 std::vector<MethodReference> methods; 290 { 291 ScopedObjectAccess soa(Thread::Current()); 292 jit_code_cache_->GetProfiledMethods(locations, methods); 293 total_number_of_code_cache_queries_++; 294 } 295 296 ProfileCompilationInfo* cached_info = GetCachedProfiledInfo(filename); 297 cached_info->AddMethodsAndClasses(methods, std::set<DexCacheResolvedClasses>()); 298 int64_t delta_number_of_methods = 299 cached_info->GetNumberOfMethods() - 300 static_cast<int64_t>(last_save_number_of_methods_); 301 int64_t delta_number_of_classes = 302 cached_info->GetNumberOfResolvedClasses() - 303 static_cast<int64_t>(last_save_number_of_classes_); 304 305 if (delta_number_of_methods < kMinimumNumberOfMethodsToSave && 306 delta_number_of_classes < kMinimumNumberOfClassesToSave) { 307 VLOG(profiler) << "Not enough information to save to: " << filename 308 << " Nr of methods: " << delta_number_of_methods 309 << " Nr of classes: " << delta_number_of_classes; 310 total_number_of_skipped_writes_++; 311 continue; 312 } 313 *new_methods = std::max(static_cast<uint16_t>(delta_number_of_methods), *new_methods); 314 uint64_t bytes_written; 315 // Force the save. In case the profile data is corrupted or the the profile 316 // has the wrong version this will "fix" the file to the correct format. 317 if (cached_info->MergeAndSave(filename, &bytes_written, /*force*/ true)) { 318 last_save_number_of_methods_ = cached_info->GetNumberOfMethods(); 319 last_save_number_of_classes_ = cached_info->GetNumberOfResolvedClasses(); 320 // Clear resolved classes. No need to store them around as 321 // they don't change after the first write. 322 cached_info->ClearResolvedClasses(); 323 if (bytes_written > 0) { 324 total_number_of_writes_++; 325 total_bytes_written_ += bytes_written; 326 profile_file_saved = true; 327 } else { 328 // At this point we could still have avoided the write. 329 // We load and merge the data from the file lazily at its first ever 330 // save attempt. So, whatever we are trying to save could already be 331 // in the file. 332 total_number_of_skipped_writes_++; 333 } 334 } else { 335 LOG(WARNING) << "Could not save profiling info to " << filename; 336 total_number_of_failed_writes_++; 337 } 338 total_number_of_profile_entries_cached += 339 cached_info->GetNumberOfMethods() + 340 cached_info->GetNumberOfResolvedClasses(); 341 } 342 max_number_of_profile_entries_cached_ = std::max( 343 max_number_of_profile_entries_cached_, 344 total_number_of_profile_entries_cached); 345 return profile_file_saved; 346 } 347 348 void* ProfileSaver::RunProfileSaverThread(void* arg) { 349 Runtime* runtime = Runtime::Current(); 350 351 bool attached = runtime->AttachCurrentThread("Profile Saver", 352 /*as_daemon*/true, 353 runtime->GetSystemThreadGroup(), 354 /*create_peer*/true); 355 if (!attached) { 356 CHECK(runtime->IsShuttingDown(Thread::Current())); 357 return nullptr; 358 } 359 360 ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg); 361 profile_saver->Run(); 362 363 runtime->DetachCurrentThread(); 364 VLOG(profiler) << "Profile saver shutdown"; 365 return nullptr; 366 } 367 368 static bool ShouldProfileLocation(const std::string& location) { 369 OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager(); 370 const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location); 371 if (oat_file == nullptr) { 372 // This can happen if we fallback to run code directly from the APK. 373 // Profile it with the hope that the background dexopt will get us back into 374 // a good state. 375 VLOG(profiler) << "Asked to profile a location without an oat file:" << location; 376 return true; 377 } 378 CompilerFilter::Filter filter = oat_file->GetCompilerFilter(); 379 if ((filter == CompilerFilter::kSpeed) || (filter == CompilerFilter::kEverything)) { 380 VLOG(profiler) 381 << "Skip profiling oat file because it's already speed|everything compiled: " 382 << location << " oat location: " << oat_file->GetLocation(); 383 return false; 384 } 385 return true; 386 } 387 388 void ProfileSaver::Start(const std::string& output_filename, 389 jit::JitCodeCache* jit_code_cache, 390 const std::vector<std::string>& code_paths, 391 const std::string& foreign_dex_profile_path, 392 const std::string& app_data_dir) { 393 DCHECK(Runtime::Current()->SaveProfileInfo()); 394 DCHECK(!output_filename.empty()); 395 DCHECK(jit_code_cache != nullptr); 396 397 std::vector<std::string> code_paths_to_profile; 398 399 for (const std::string& location : code_paths) { 400 if (ShouldProfileLocation(location)) { 401 code_paths_to_profile.push_back(location); 402 } 403 } 404 if (code_paths_to_profile.empty()) { 405 VLOG(profiler) << "No code paths should be profiled."; 406 return; 407 } 408 409 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 410 if (instance_ != nullptr) { 411 // If we already have an instance, make sure it uses the same jit_code_cache. 412 // This may be called multiple times via Runtime::registerAppInfo (e.g. for 413 // apps which share the same runtime). 414 DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache); 415 // Add the code_paths to the tracked locations. 416 instance_->AddTrackedLocations(output_filename, app_data_dir, code_paths_to_profile); 417 return; 418 } 419 420 VLOG(profiler) << "Starting profile saver using output file: " << output_filename 421 << ". Tracking: " << Join(code_paths_to_profile, ':'); 422 423 instance_ = new ProfileSaver(output_filename, 424 jit_code_cache, 425 code_paths_to_profile, 426 foreign_dex_profile_path, 427 app_data_dir); 428 429 // Create a new thread which does the saving. 430 CHECK_PTHREAD_CALL( 431 pthread_create, 432 (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)), 433 "Profile saver thread"); 434 } 435 436 void ProfileSaver::Stop(bool dump_info) { 437 ProfileSaver* profile_saver = nullptr; 438 pthread_t profiler_pthread = 0U; 439 440 { 441 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_); 442 VLOG(profiler) << "Stopping profile saver thread"; 443 profile_saver = instance_; 444 profiler_pthread = profiler_pthread_; 445 if (instance_ == nullptr) { 446 DCHECK(false) << "Tried to stop a profile saver which was not started"; 447 return; 448 } 449 if (instance_->shutting_down_) { 450 DCHECK(false) << "Tried to stop the profile saver twice"; 451 return; 452 } 453 instance_->shutting_down_ = true; 454 if (dump_info) { 455 instance_->DumpInfo(LOG(INFO)); 456 } 457 } 458 459 { 460 // Wake up the saver thread if it is sleeping to allow for a clean exit. 461 MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_); 462 profile_saver->period_condition_.Signal(Thread::Current()); 463 } 464 465 // Wait for the saver thread to stop. 466 CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown"); 467 468 { 469 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_); 470 instance_ = nullptr; 471 profiler_pthread_ = 0U; 472 } 473 delete profile_saver; 474 } 475 476 bool ProfileSaver::ShuttingDown(Thread* self) { 477 MutexLock mu(self, *Locks::profiler_lock_); 478 return shutting_down_; 479 } 480 481 bool ProfileSaver::IsStarted() { 482 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 483 return instance_ != nullptr; 484 } 485 486 void ProfileSaver::AddTrackedLocations(const std::string& output_filename, 487 const std::string& app_data_dir, 488 const std::vector<std::string>& code_paths) { 489 auto it = tracked_dex_base_locations_.find(output_filename); 490 if (it == tracked_dex_base_locations_.end()) { 491 tracked_dex_base_locations_.Put(output_filename, 492 std::set<std::string>(code_paths.begin(), code_paths.end())); 493 if (!app_data_dir.empty()) { 494 app_data_dirs_.insert(app_data_dir); 495 } 496 } else { 497 it->second.insert(code_paths.begin(), code_paths.end()); 498 } 499 } 500 501 // TODO(calin): This may lead to several calls to realpath. 502 // Consider moving the logic to the saver thread (i.e. when notified, 503 // only cache the location, and then wake up the saver thread to do the 504 // comparisons with the real file paths and to create the markers). 505 void ProfileSaver::NotifyDexUse(const std::string& dex_location) { 506 if (!ShouldProfileLocation(dex_location)) { 507 return; 508 } 509 std::set<std::string> app_code_paths; 510 std::string foreign_dex_profile_path; 511 std::set<std::string> app_data_dirs; 512 { 513 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 514 if (instance_ == nullptr) { 515 return; 516 } 517 // Make a copy so that we don't hold the lock while doing I/O. 518 for (const auto& it : instance_->tracked_dex_base_locations_) { 519 app_code_paths.insert(it.second.begin(), it.second.end()); 520 } 521 foreign_dex_profile_path = instance_->foreign_dex_profile_path_; 522 app_data_dirs.insert(instance_->app_data_dirs_.begin(), instance_->app_data_dirs_.end()); 523 } 524 525 bool mark_created = MaybeRecordDexUseInternal(dex_location, 526 app_code_paths, 527 foreign_dex_profile_path, 528 app_data_dirs); 529 if (mark_created) { 530 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 531 if (instance_ != nullptr) { 532 instance_->total_number_of_foreign_dex_marks_++; 533 } 534 } 535 } 536 537 static bool CheckContainsWithRealPath(const std::set<std::string>& paths_set, 538 const std::string& path_to_check) { 539 for (const auto& path : paths_set) { 540 UniqueCPtr<const char[]> real_path(realpath(path.c_str(), nullptr)); 541 if (real_path == nullptr) { 542 PLOG(WARNING) << "Could not get realpath for " << path; 543 continue; 544 } 545 std::string real_path_str(real_path.get()); 546 if (real_path_str == path_to_check) { 547 return true; 548 } 549 } 550 return false; 551 } 552 553 // After the call, dex_location_real_path will contain the marker's name. 554 static bool CreateForeignDexMarker(const std::string& foreign_dex_profile_path, 555 /*in-out*/ std::string* dex_location_real_path) { 556 // For foreign dex files we record a flag on disk. PackageManager will (potentially) take this 557 // into account when deciding how to optimize the loaded dex file. 558 // The expected flag name is the canonical path of the apk where '/' is substituted to '@'. 559 // (it needs to be kept in sync with 560 // frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java) 561 std::replace(dex_location_real_path->begin(), dex_location_real_path->end(), '/', '@'); 562 std::string flag_path = foreign_dex_profile_path + "/" + *dex_location_real_path; 563 // We use O_RDONLY as the access mode because we must supply some access 564 // mode, and there is no access mode that means 'create but do not read' the 565 // file. We will not not actually read from the file. 566 int fd = TEMP_FAILURE_RETRY(open(flag_path.c_str(), 567 O_CREAT | O_RDONLY | O_EXCL | O_CLOEXEC | O_NOFOLLOW, 0)); 568 if (fd != -1) { 569 if (close(fd) != 0) { 570 PLOG(WARNING) << "Could not close file after flagging foreign dex use " << flag_path; 571 } 572 return true; 573 } else { 574 if (errno != EEXIST && errno != EACCES) { 575 // Another app could have already created the file, and selinux may not 576 // allow the read access to the file implied by the call to open. 577 PLOG(WARNING) << "Could not create foreign dex use mark " << flag_path; 578 return false; 579 } 580 return true; 581 } 582 } 583 584 bool ProfileSaver::MaybeRecordDexUseInternal( 585 const std::string& dex_location, 586 const std::set<std::string>& app_code_paths, 587 const std::string& foreign_dex_profile_path, 588 const std::set<std::string>& app_data_dirs) { 589 if (dex_location.empty()) { 590 LOG(WARNING) << "Asked to record foreign dex use with an empty dex location."; 591 return false; 592 } 593 if (foreign_dex_profile_path.empty()) { 594 LOG(WARNING) << "Asked to record foreign dex use without a valid profile path "; 595 return false; 596 } 597 598 if (app_code_paths.find(dex_location) != app_code_paths.end()) { 599 // The dex location belongs to the application code paths. Nothing to record. 600 return false; 601 } 602 603 if (app_data_dirs.find(dex_location) != app_data_dirs.end()) { 604 // The dex location is under the application folder. Nothing to record. 605 return false; 606 } 607 608 // Do another round of checks with the real paths. 609 // Application directory could be a symlink (e.g. /data/data instead of /data/user/0), and we 610 // don't have control over how the dex files are actually loaded (symlink or canonical path), 611 612 // Note that we could cache all the real locations in the saver (since it's an expensive 613 // operation). However we expect that app_code_paths is small (usually 1 element), and 614 // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise 615 // to save some bytes of memory usage. 616 617 UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr)); 618 if (dex_location_real_path == nullptr) { 619 PLOG(WARNING) << "Could not get realpath for " << dex_location; 620 return false; 621 } 622 std::string dex_location_real_path_str(dex_location_real_path.get()); 623 624 if (CheckContainsWithRealPath(app_code_paths, dex_location_real_path_str)) { 625 return false; 626 } 627 628 if (CheckContainsWithRealPath(app_data_dirs, dex_location_real_path_str)) { 629 return false; 630 } 631 632 return CreateForeignDexMarker(foreign_dex_profile_path, &dex_location_real_path_str); 633 } 634 635 void ProfileSaver::DumpInstanceInfo(std::ostream& os) { 636 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 637 if (instance_ != nullptr) { 638 instance_->DumpInfo(os); 639 } 640 } 641 642 void ProfileSaver::DumpInfo(std::ostream& os) { 643 os << "ProfileSaver total_bytes_written=" << total_bytes_written_ << '\n' 644 << "ProfileSaver total_number_of_writes=" << total_number_of_writes_ << '\n' 645 << "ProfileSaver total_number_of_code_cache_queries=" 646 << total_number_of_code_cache_queries_ << '\n' 647 << "ProfileSaver total_number_of_skipped_writes=" << total_number_of_skipped_writes_ << '\n' 648 << "ProfileSaver total_number_of_failed_writes=" << total_number_of_failed_writes_ << '\n' 649 << "ProfileSaver total_ms_of_sleep=" << total_ms_of_sleep_ << '\n' 650 << "ProfileSaver total_ms_of_work=" << NsToMs(total_ns_of_work_) << '\n' 651 << "ProfileSaver total_number_of_foreign_dex_marks=" 652 << total_number_of_foreign_dex_marks_ << '\n' 653 << "ProfileSaver max_number_profile_entries_cached=" 654 << max_number_of_profile_entries_cached_ << '\n' 655 << "ProfileSaver total_number_of_hot_spikes=" << total_number_of_hot_spikes_ << '\n' 656 << "ProfileSaver total_number_of_wake_ups=" << total_number_of_wake_ups_ << '\n'; 657 } 658 659 660 void ProfileSaver::ForceProcessProfiles() { 661 ProfileSaver* saver = nullptr; 662 { 663 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 664 saver = instance_; 665 } 666 // TODO(calin): this is not actually thread safe as the instance_ may have been deleted, 667 // but we only use this in testing when we now this won't happen. 668 // Refactor the way we handle the instance so that we don't end up in this situation. 669 if (saver != nullptr) { 670 uint16_t new_methods; 671 saver->ProcessProfilingInfo(&new_methods); 672 } 673 } 674 675 bool ProfileSaver::HasSeenMethod(const std::string& profile, 676 const DexFile* dex_file, 677 uint16_t method_idx) { 678 MutexLock mu(Thread::Current(), *Locks::profiler_lock_); 679 if (instance_ != nullptr) { 680 ProfileCompilationInfo* info = instance_->GetCachedProfiledInfo(profile); 681 if (info != nullptr) { 682 return info->ContainsMethod(MethodReference(dex_file, method_idx)); 683 } 684 } 685 return false; 686 } 687 688 } // namespace art 689