diff options
-rw-r--r-- | cmdline/cmdline_parser_test.cc | 15 | ||||
-rw-r--r-- | cmdline/cmdline_types.h | 6 | ||||
-rw-r--r-- | runtime/jit/profile_saver.cc | 49 | ||||
-rw-r--r-- | runtime/jit/profile_saver.h | 6 | ||||
-rw-r--r-- | runtime/jit/profile_saver_options.h | 11 | ||||
-rw-r--r-- | runtime/parsed_options.cc | 1 |
6 files changed, 80 insertions, 8 deletions
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc index 779e3e0fb6..10c651b8e5 100644 --- a/cmdline/cmdline_parser_test.cc +++ b/cmdline/cmdline_parser_test.cc @@ -487,17 +487,18 @@ TEST_F(CmdlineParserTest, TestJitOptions) { * -Xps-* */ TEST_F(CmdlineParserTest, ProfileSaverOptions) { - ProfileSaverOptions opt = ProfileSaverOptions(true, 1, 2, 3, 4, 5, 6, 7, "abc", true); + ProfileSaverOptions opt = ProfileSaverOptions(true, 1, 2, 3, 4, 5, 6, 7, 8, "abc", true); EXPECT_SINGLE_PARSE_VALUE(opt, "-Xjitsaveprofilinginfo " "-Xps-min-save-period-ms:1 " - "-Xps-save-resolved-classes-delay-ms:2 " - "-Xps-hot-startup-method-samples:3 " - "-Xps-min-methods-to-save:4 " - "-Xps-min-classes-to-save:5 " - "-Xps-min-notification-before-wake:6 " - "-Xps-max-notification-before-wake:7 " + "-Xps-min-first-save-ms:2 " + "-Xps-save-resolved-classes-delay-ms:3 " + "-Xps-hot-startup-method-samples:4 " + "-Xps-min-methods-to-save:5 " + "-Xps-min-classes-to-save:6 " + "-Xps-min-notification-before-wake:7 " + "-Xps-max-notification-before-wake:8 " "-Xps-profile-path:abc " "-Xps-profile-boot-class-path", M::ProfileSaverOpts); diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index 7b38b8ebe0..c506e03e27 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -788,6 +788,12 @@ struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> &ProfileSaverOptions::min_save_period_ms_, type_parser.Parse(suffix)); } + if (android::base::StartsWith(option, "min-first-save-ms:")) { + CmdlineType<unsigned int> type_parser; + return ParseInto(existing, + &ProfileSaverOptions::min_first_save_ms_, + type_parser.Parse(suffix)); + } if (android::base::StartsWith(option, "save-resolved-classes-delay-ms:")) { CmdlineType<unsigned int> type_parser; return ParseInto(existing, diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index ff711fa8db..263a9ad731 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -20,6 +20,7 @@ #include <sys/resource.h> #include <sys/stat.h> #include <sys/types.h> +#include <unistd.h> #include "android-base/strings.h" @@ -180,7 +181,11 @@ void ProfileSaver::Run() { // We might have been woken up by a huge number of notifications to guarantee saving. // If we didn't meet the minimum saving period go back to sleep (only if missed by // a reasonable margin). - uint64_t min_save_period_ns = MsToNs(options_.GetMinSavePeriodMs()); + bool check_for_first_save = options_.GetMinFirstSaveMs() != + ProfileSaverOptions::kMinFirstSaveMsNotSet; + uint64_t min_save_period_ns = MsToNs(check_for_first_save && IsFirstSave() + ? options_.GetMinFirstSaveMs() + : options_.GetMinSavePeriodMs()); while (min_save_period_ns * 0.9 > sleep_time) { { MutexLock mu(self, wait_lock_); @@ -215,6 +220,48 @@ void ProfileSaver::Run() { } } +// TODO(b/185979271): include reference profiles in the test. +// The current profiles are cleared after bg-dexopt so this test will currently +// return True after every bg-dexopt call. +bool ProfileSaver::IsFirstSave() { + // Resolve any new registered locations. + ResolveTrackedLocations(); + Thread* self = Thread::Current(); + SafeMap<std::string, std::set<std::string>> tracked_locations; + { + // Make a copy so that we don't hold the lock while doing I/O. + MutexLock mu(self, *Locks::profiler_lock_); + tracked_locations = tracked_dex_base_locations_; + } + + for (const auto& it : tracked_locations) { + if (ShuttingDown(self)) { + return false; + } + const std::set<std::string>& locations = it.second; + + // Check if any profile is non empty. If so, then this is not the first save. + for (const auto& location : locations) { + struct stat stat_buffer; + if (stat(location.c_str(), &stat_buffer) != 0) { + if (VLOG_IS_ON(profiler)) { + PLOG(WARNING) << "Failed to stat profile location for IsFirstUse: " << location; + } + continue; + } + if (stat_buffer.st_size > 0) { + return false; + } else { + VLOG(profiler) << "Profile location is empty: " << location; + } + } + } + + // All locations are empty. Assume this is the first use. + VLOG(profiler) << "All profile locations are empty. This is considered to be first save"; + return true; +} + void ProfileSaver::NotifyJitActivity() { MutexLock mu(Thread::Current(), *Locks::profiler_lock_); if (instance_ == nullptr || instance_->shutting_down_) { diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h index 036e717781..dc44f2425e 100644 --- a/runtime/jit/profile_saver.h +++ b/runtime/jit/profile_saver.h @@ -134,6 +134,12 @@ class ProfileSaver { // to just a few hundreds entries in the ProfileCompilationInfo objects. SafeMap<std::string, ProfileCompilationInfo*> profile_cache_ GUARDED_BY(Locks::profiler_lock_); + // Whether or not this is the first ever profile save. + // Note this is an approximation and is not 100% precise. It relies on checking + // whether or not the profiles are empty which is not a precise indication + // of being the first save (they could have been cleared in the meantime). + bool IsFirstSave() REQUIRES(!Locks::profiler_lock_); + // Save period condition support. Mutex wait_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; ConditionVariable period_condition_ GUARDED_BY(wait_lock_); diff --git a/runtime/jit/profile_saver_options.h b/runtime/jit/profile_saver_options.h index 1cff713415..749205452a 100644 --- a/runtime/jit/profile_saver_options.h +++ b/runtime/jit/profile_saver_options.h @@ -21,6 +21,9 @@ namespace art { struct ProfileSaverOptions { public: static constexpr uint32_t kMinSavePeriodMs = 40 * 1000; // 40 seconds + // Default value for the min save period on first use, indicating that the + // period is not configured. + static constexpr uint32_t kMinFirstSaveMsNotSet = 0; static constexpr uint32_t kSaveResolvedClassesDelayMs = 5 * 1000; // 5 seconds // Minimum number of JIT samples during launch to mark a method as hot in the profile. static constexpr uint32_t kHotStartupMethodSamples = 1; @@ -34,6 +37,7 @@ struct ProfileSaverOptions { ProfileSaverOptions() : enabled_(false), min_save_period_ms_(kMinSavePeriodMs), + min_first_save_ms_(kMinFirstSaveMsNotSet), save_resolved_classes_delay_ms_(kSaveResolvedClassesDelayMs), hot_startup_method_samples_(kHotStartupMethodSamplesNotSet), min_methods_to_save_(kMinMethodsToSave), @@ -48,6 +52,7 @@ struct ProfileSaverOptions { ProfileSaverOptions( bool enabled, uint32_t min_save_period_ms, + uint32_t min_first_save_ms, uint32_t save_resolved_classes_delay_ms, uint32_t hot_startup_method_samples, uint32_t min_methods_to_save, @@ -60,6 +65,7 @@ struct ProfileSaverOptions { bool wait_for_jit_notifications_to_save = true) : enabled_(enabled), min_save_period_ms_(min_save_period_ms), + min_first_save_ms_(min_first_save_ms), save_resolved_classes_delay_ms_(save_resolved_classes_delay_ms), hot_startup_method_samples_(hot_startup_method_samples), min_methods_to_save_(min_methods_to_save), @@ -81,6 +87,9 @@ struct ProfileSaverOptions { uint32_t GetMinSavePeriodMs() const { return min_save_period_ms_; } + uint32_t GetMinFirstSaveMs() const { + return min_first_save_ms_; + } uint32_t GetSaveResolvedClassesDelayMs() const { return save_resolved_classes_delay_ms_; } @@ -122,6 +131,7 @@ struct ProfileSaverOptions { friend std::ostream & operator<<(std::ostream &os, const ProfileSaverOptions& pso) { os << "enabled_" << pso.enabled_ << ", min_save_period_ms_" << pso.min_save_period_ms_ + << ", min_first_save_ms_" << pso.min_first_save_ms_ << ", save_resolved_classes_delay_ms_" << pso.save_resolved_classes_delay_ms_ << ", hot_startup_method_samples_" << pso.hot_startup_method_samples_ << ", min_methods_to_save_" << pso.min_methods_to_save_ @@ -136,6 +146,7 @@ struct ProfileSaverOptions { bool enabled_; uint32_t min_save_period_ms_; + uint32_t min_first_save_ms_; uint32_t save_resolved_classes_delay_ms_; // Do not access hot_startup_method_samples_ directly for reading since it may be set to the // placeholder default. diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index fec2587f3c..471a3fafd6 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -288,6 +288,7 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize // TODO This should be redone. .Define({"-Xps-_", "-Xps-min-save-period-ms:_", + "-Xps-min-first-save-ms:_", "-Xps-save-resolved-classes-delayed-ms:_", "-Xps-hot-startup-method-samples:_", "-Xps-min-methods-to-save:_", |