From b9c1b9bdd7689c0e80c64c371581f99e53749e05 Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Thu, 17 Mar 2016 17:07:52 +0000 Subject: [PATCH] Improve resolved classes saving strategy If we already have a non empty profile file it means that we already saved once the resolved classes. So there's no need to hurry up and start the profile saver eagerly after 2s. Bug: 27600652 (cherry picked from commit c15e566b36170237f01ccefc12129c1578a02140) Change-Id: Iecc730c25eab779efccbbde66432dbbc61192e8a --- runtime/jit/profile_saver.cc | 60 ++++++++++++++++++++++++++++---------------- runtime/jit/profile_saver.h | 4 +-- runtime/utils.cc | 8 ++++++ runtime/utils.h | 1 + 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index fd3324887..3d3f3dd0b 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -37,7 +37,7 @@ static constexpr const uint64_t kMinimumTimeBetweenCodeCacheUpdatesNs = 2000 * k static constexpr const uint64_t kRandomDelayMaxMs = 40 * 1000; // 40 seconds static constexpr const uint64_t kMaxBackoffMs = 5 * 60 * 1000; // 5 minutes static constexpr const uint64_t kSavePeriodMs = 40 * 1000; // 40 seconds -static constexpr const uint64_t kInitialDelayMs = 2 * 1000; // 2 seconds +static constexpr const uint64_t kSaveResolvedClassesDelayMs = 2 * 1000; // 2 seconds static constexpr const double kBackoffCoef = 1.5; static constexpr const uint32_t kMinimumNrOrMethodsToSave = 10; @@ -54,7 +54,6 @@ ProfileSaver::ProfileSaver(const std::string& output_filename, foreign_dex_profile_path_(foreign_dex_profile_path), code_cache_last_update_time_ns_(0), shutting_down_(false), - first_profile_(true), wait_lock_("ProfileSaver wait lock"), period_condition_("ProfileSaver period condition", wait_lock_), total_bytes_written_(0), @@ -66,6 +65,13 @@ ProfileSaver::ProfileSaver(const std::string& output_filename, total_ns_of_work_(0), total_number_of_foreign_dex_marks_(0) { AddTrackedLocations(output_filename, code_paths); + // We only need to save the resolved classes if the profile file is empty. + // Otherwise we must have already save them (we always do it during the first + // ever profile save). + // TODO(calin) This only considers the case of the primary profile file. + // Anything that gets loaded in the same VM will not have their resolved + // classes save (unless they started before the initial saving was done). + save_resolved_classes_ = !FileExistsAndNotEmpty(output_filename); app_data_dir_ = ""; if (!app_data_dir.empty()) { // The application directory is used to determine which dex files are owned by app. @@ -88,14 +94,12 @@ void ProfileSaver::Run() { uint64_t save_period_ms = kSavePeriodMs; VLOG(profiler) << "Save profiling information every " << save_period_ms << " ms"; - - bool first_iteration = true; while (!ShuttingDown(self)) { uint64_t sleep_time_ms; - if (first_iteration) { + if (save_resolved_classes_) { // Sleep less long for the first iteration since we want to record loaded classes shortly // after app launch. - sleep_time_ms = kInitialDelayMs; + sleep_time_ms = kSaveResolvedClassesDelayMs; } else { const uint64_t random_sleep_delay_ms = rand() % kRandomDelayMaxMs; sleep_time_ms = save_period_ms + random_sleep_delay_ms; @@ -111,7 +115,7 @@ void ProfileSaver::Run() { uint64_t start = NanoTime(); - if (!ProcessProfilingInfo() && save_period_ms < kMaxBackoffMs) { + if (!ProcessProfilingInfo(save_resolved_classes_) && save_period_ms < kMaxBackoffMs) { // If we don't need to save now it is less likely that we will need to do // so in the future. Increase the time between saves according to the // kBackoffCoef, but make it no larger than kMaxBackoffMs. @@ -120,16 +124,16 @@ void ProfileSaver::Run() { // Reset the period to the initial value as it's highly likely to JIT again. save_period_ms = kSavePeriodMs; } - first_iteration = false; + save_resolved_classes_ = false; total_ns_of_work_ += (NanoTime() - start); } } -bool ProfileSaver::ProcessProfilingInfo() { +bool ProfileSaver::ProcessProfilingInfo(bool save_resolved_classes) { ScopedTrace trace(__PRETTY_FUNCTION__); uint64_t last_update_time_ns = jit_code_cache_->GetLastUpdateTimeNs(); - if (!first_profile_ && last_update_time_ns - code_cache_last_update_time_ns_ + if (!save_resolved_classes && last_update_time_ns - code_cache_last_update_time_ns_ < kMinimumTimeBetweenCodeCacheUpdatesNs) { VLOG(profiler) << "Not enough time has passed since the last code cache update." << "Last update: " << last_update_time_ns @@ -145,6 +149,12 @@ bool ProfileSaver::ProcessProfilingInfo() { MutexLock mu(Thread::Current(), *Locks::profiler_lock_); tracked_locations = tracked_dex_base_locations_; } + + std::set resolved_classes; + if (save_resolved_classes) { + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + resolved_classes = class_linker->GetResolvedClasses(/*ignore boot classes*/true); + } for (const auto& it : tracked_locations) { if (ShuttingDown(Thread::Current())) { return true; @@ -157,24 +167,31 @@ bool ProfileSaver::ProcessProfilingInfo() { jit_code_cache_->GetCompiledArtMethods(locations, methods); total_number_of_code_cache_queries_++; } + + std::set resolved_classes_for_location; + if (save_resolved_classes) { + bool resolved_classes_already_in_file = FileExistsAndNotEmpty(filename); + if (!resolved_classes_already_in_file) { + for (const DexCacheResolvedClasses& classes : resolved_classes) { + if (locations.find(classes.GetDexLocation()) != locations.end()) { + resolved_classes_for_location.insert(classes); + } + } + } + } // Always save for the first one for loaded classes profile. - if (methods.size() < kMinimumNrOrMethodsToSave && !first_profile_) { + if (methods.size() < kMinimumNrOrMethodsToSave && !save_resolved_classes) { VLOG(profiler) << "Not enough information to save to: " << filename <<" Nr of methods: " << methods.size(); total_number_of_skipped_writes_++; return false; } - - std::set resolved_classes; - if (first_profile_) { - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - resolved_classes = class_linker->GetResolvedClasses(/*ignore boot classes*/true); - } - uint64_t bytes_written; - if (!ProfileCompilationInfo::SaveProfilingInfo(filename, methods, - resolved_classes, - &bytes_written)) { + if (!ProfileCompilationInfo::SaveProfilingInfo( + filename, + methods, + resolved_classes_for_location, + &bytes_written)) { LOG(WARNING) << "Could not save profiling info to " << filename; total_number_of_failed_writes_++; return false; @@ -185,7 +202,6 @@ bool ProfileSaver::ProcessProfilingInfo() { } } } - first_profile_ = false; return true; } diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h index 48ab1ad44..d810c8123 100644 --- a/runtime/jit/profile_saver.h +++ b/runtime/jit/profile_saver.h @@ -65,7 +65,7 @@ class ProfileSaver { void Run() REQUIRES(!Locks::profiler_lock_, !wait_lock_); // Processes the existing profiling info from the jit code cache and returns // true if it needed to be saved to disk. - bool ProcessProfilingInfo(); + bool ProcessProfilingInfo(bool save_resolved_classes); // Returns true if the saver is shutting down (ProfileSaver::Stop() has been called). bool ShuttingDown(Thread* self) REQUIRES(!Locks::profiler_lock_); @@ -93,7 +93,7 @@ class ProfileSaver { std::string app_data_dir_; uint64_t code_cache_last_update_time_ns_; bool shutting_down_ GUARDED_BY(Locks::profiler_lock_); - bool first_profile_ = true; + bool save_resolved_classes_; // Save period condition support. Mutex wait_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; diff --git a/runtime/utils.cc b/runtime/utils.cc index 472a85c04..6a50b8eee 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -1459,6 +1459,14 @@ bool FileExists(const std::string& filename) { return stat(filename.c_str(), &buffer) == 0; } +bool FileExistsAndNotEmpty(const std::string& filename) { + struct stat buffer; + if (stat(filename.c_str(), &buffer) != 0) { + return false; + } + return buffer.st_size > 0; +} + std::string PrettyDescriptor(Primitive::Type type) { return PrettyDescriptor(Primitive::Descriptor(type)); } diff --git a/runtime/utils.h b/runtime/utils.h index 83ac0b870..c1e88a4fe 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -296,6 +296,7 @@ int ExecAndReturnCode(std::vector& arg_vector, std::string* error_m // Returns true if the file exists. bool FileExists(const std::string& filename); +bool FileExistsAndNotEmpty(const std::string& filename); class VoidFunctor { public: -- 2.11.0