diff options
-rw-r--r-- | cmdline/cmdline_parser_test.cc | 14 | ||||
-rw-r--r-- | cmdline/cmdline_types.h | 6 | ||||
-rw-r--r-- | compiler/jit/jit_compiler.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 6 | ||||
-rw-r--r-- | runtime/art_method-inl.h | 7 | ||||
-rw-r--r-- | runtime/art_method.h | 1 | ||||
-rw-r--r-- | runtime/interpreter/mterp/nterp.cc | 3 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 33 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.h | 1 | ||||
-rw-r--r-- | runtime/jit/profile_saver.cc | 32 | ||||
-rw-r--r-- | runtime/jit/profile_saver_options.h | 18 | ||||
-rw-r--r-- | runtime/jit/profiling_info.h | 8 | ||||
-rw-r--r-- | test/2230-profile-save-hotness/run.py | 5 | ||||
-rw-r--r-- | test/2230-profile-save-hotness/src-art/Main.java | 4 |
15 files changed, 111 insertions, 32 deletions
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc index e586dd4292..5d6ba4446e 100644 --- a/cmdline/cmdline_parser_test.cc +++ b/cmdline/cmdline_parser_test.cc @@ -38,6 +38,7 @@ namespace art { return lhs.enabled_ == rhs.enabled_ && lhs.min_save_period_ms_ == rhs.min_save_period_ms_ && lhs.save_resolved_classes_delay_ms_ == rhs.save_resolved_classes_delay_ms_ && + lhs.hot_startup_method_samples_ == rhs.hot_startup_method_samples_ && lhs.min_methods_to_save_ == rhs.min_methods_to_save_ && lhs.min_classes_to_save_ == rhs.min_classes_to_save_ && lhs.min_notification_before_wake_ == rhs.min_notification_before_wake_ && @@ -489,18 +490,19 @@ TEST_F(CmdlineParserTest, TestJitOptions) { * -Xps-* */ TEST_F(CmdlineParserTest, ProfileSaverOptions) { - ProfileSaverOptions opt = ProfileSaverOptions(true, 1, 2, 3, 4, 5, 6, 7, 8, "abc", true); + ProfileSaverOptions opt = ProfileSaverOptions(true, 1, 2, 3, 4, 5, 6, 7, 8, 9, "abc", true); EXPECT_SINGLE_PARSE_VALUE(opt, "-Xjitsaveprofilinginfo " "-Xps-min-save-period-ms:1 " "-Xps-min-first-save-ms:2 " "-Xps-save-resolved-classes-delay-ms: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-inline-cache-threshold:8 " + "-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-inline-cache-threshold:9 " "-Xps-profile-path:abc " "-Xps-profile-boot-class-path", M::ProfileSaverOpts); diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index 34c1b0fc97..7cacfde12a 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -832,8 +832,10 @@ struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> type_parser.Parse(suffix)); } if (android::base::StartsWith(option, "hot-startup-method-samples:")) { - LOG(WARNING) << "-Xps-hot-startup-method-samples option is deprecated"; - return Result::SuccessNoValue(); + CmdlineType<unsigned int> type_parser; + return ParseInto(existing, + &ProfileSaverOptions::hot_startup_method_samples_, + type_parser.Parse(suffix)); } if (android::base::StartsWith(option, "min-methods-to-save:")) { CmdlineType<unsigned int> type_parser; diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 4b2f8d2e14..051368cc8a 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -178,8 +178,7 @@ bool JitCompiler::CompileMethod( Thread* self, JitMemoryRegion* region, ArtMethod* method, CompilationKind compilation_kind) { SCOPED_TRACE << "JIT compiling " << method->PrettyMethod() - << " (kind=" << compilation_kind << ")" - << " from " << method->GetDexFile()->GetLocation(); + << " (kind=" << compilation_kind << ")"; DCHECK(!method->IsProxyMethod()); DCHECK(method->GetDeclaringClass()->IsResolved()); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 89369f59f1..33ffc07ba8 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -143,8 +143,6 @@ enum GraphAnalysisResult { kAnalysisSuccess, }; -std::ostream& operator<<(std::ostream& os, GraphAnalysisResult ga); - template <typename T> static inline typename std::make_unsigned<T>::type MakeUnsigned(T x) { return static_cast<typename std::make_unsigned<T>::type>(x); diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 3f73459a00..45d534a9ec 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -30,7 +30,6 @@ #include "base/macros.h" #include "base/mutex.h" #include "base/scoped_arena_allocator.h" -#include "base/systrace.h" #include "base/timing_logger.h" #include "builder.h" #include "code_generator.h" @@ -782,7 +781,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, } if (Compiler::IsPathologicalCase(*code_item, method_idx, dex_file)) { - SCOPED_TRACE << "Not compiling because of pathological case"; MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledPathological); return nullptr; } @@ -793,7 +791,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace) && (CodeItemInstructionAccessor(dex_file, code_item).InsnsSizeInCodeUnits() > kSpaceFilterOptimizingThreshold)) { - SCOPED_TRACE << "Not compiling because of space filter"; MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledSpaceFilter); return nullptr; } @@ -868,7 +865,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, compilation_stats_.get()); GraphAnalysisResult result = builder.BuildGraph(); if (result != kAnalysisSuccess) { - SCOPED_TRACE << "Not compiling because of " << result; switch (result) { case kAnalysisSkipped: { MaybeRecordStat(compilation_stats_.get(), @@ -931,7 +927,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, // However, we may have run out of memory trying to create it, so in this // case just abort the compilation. if (graph->GetProfilingInfo() == nullptr) { - SCOPED_TRACE << "Not compiling because of out of memory"; MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kJitOutOfMemoryForCommit); return nullptr; } @@ -943,7 +938,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, compilation_stats_.get()); if (UNLIKELY(codegen->GetFrameSize() > codegen->GetMaximumFrameSize())) { - SCOPED_TRACE << "Not compiling because of stack frame too large"; LOG(WARNING) << "Stack frame size is " << codegen->GetFrameSize() << " which is larger than the maximum of " << codegen->GetMaximumFrameSize() << " bytes. Method: " << graph->PrettyMethod(); diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index d87040ab49..b2711d968a 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -777,6 +777,13 @@ inline bool ArtMethod::CounterIsHot() { return hotness_count_ == 0; } +inline bool ArtMethod::CounterHasReached(uint16_t samples, uint16_t threshold) { + DCHECK(!IsAbstract()); + DCHECK_EQ(threshold, Runtime::Current()->GetJITOptions()->GetWarmupThreshold()); + DCHECK_LE(samples, threshold); + return hotness_count_ <= (threshold - samples); +} + inline uint16_t ArtMethod::GetCounter() { DCHECK(!IsAbstract()); return hotness_count_; diff --git a/runtime/art_method.h b/runtime/art_method.h index 0a6cda65fd..a23969aa73 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -1011,6 +1011,7 @@ class EXPORT ArtMethod final { ALWAYS_INLINE void UpdateCounter(int32_t new_samples); ALWAYS_INLINE void SetHotCounter(); ALWAYS_INLINE bool CounterIsHot(); + ALWAYS_INLINE bool CounterHasReached(uint16_t samples, uint16_t threshold); ALWAYS_INLINE uint16_t GetCounter(); ALWAYS_INLINE bool CounterHasChanged(uint16_t threshold); diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc index 64f04d6fde..d8ce2bcaed 100644 --- a/runtime/interpreter/mterp/nterp.cc +++ b/runtime/interpreter/mterp/nterp.cc @@ -693,10 +693,7 @@ extern "C" jit::OsrData* NterpHotMethod(ArtMethod* method, uint16_t* dex_pc_ptr, DCHECK_EQ(Thread::Current()->GetSharedMethodHotness(), 0u); Thread::Current()->ResetSharedMethodHotness(); } else { - // Move the counter to the initial threshold in case we have to re-JIT it. method->ResetCounter(runtime->GetJITOptions()->GetWarmupThreshold()); - // Mark the method as warm for the profile saver. - method->SetPreviouslyWarm(); } jit::Jit* jit = runtime->GetJit(); if (jit != nullptr && jit->UseJitCompilation()) { diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 4b69dc5c01..89be345875 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -649,6 +649,17 @@ void JitCodeCache::CopyInlineCacheInto( } } +static void ClearMethodCounter(ArtMethod* method, bool was_warm) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (was_warm) { + method->SetPreviouslyWarm(); + } + method->ResetCounter(Runtime::Current()->GetJITOptions()->GetWarmupThreshold()); + // We add one sample so that the profile knows that the method was executed at least once. + // This is required for layout purposes. + method->UpdateCounter(/* new_samples= */ 1); +} + bool JitCodeCache::Commit(Thread* self, JitMemoryRegion* region, ArtMethod* method, @@ -716,9 +727,10 @@ bool JitCodeCache::Commit(Thread* self, bool single_impl_still_valid = true; for (ArtMethod* single_impl : cha_single_implementation_list) { if (!single_impl->HasSingleImplementation()) { - // Simply discard the compiled code. + // Simply discard the compiled code. Clear the counter so that it may be recompiled later. // Hopefully the class hierarchy will be more stable when compilation is retried. single_impl_still_valid = false; + ClearMethodCounter(method, /*was_warm=*/ false); break; } } @@ -813,6 +825,7 @@ bool JitCodeCache::RemoveMethod(ArtMethod* method, bool release_memory) { return false; } + ClearMethodCounter(method, /* was_warm= */ false); Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr); VLOG(jit) << "JIT removed (osr=" << std::boolalpha << osr << std::noboolalpha << ") " @@ -1234,6 +1247,15 @@ void JitCodeCache::MaybeUpdateInlineCache(ArtMethod* method, info->AddInvokeInfo(dex_pc, cls.Ptr()); } +void JitCodeCache::ResetHotnessCounter(ArtMethod* method, Thread* self) { + ScopedDebugDisallowReadBarriers sddrb(self); + MutexLock mu(self, *Locks::jit_lock_); + auto it = profiling_infos_.find(method); + DCHECK(it != profiling_infos_.end()); + it->second->ResetCounter(); +} + + void JitCodeCache::DoCollection(Thread* self) { ScopedTrace trace(__FUNCTION__); @@ -1584,6 +1606,8 @@ bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, VLOG(jit) << "Not compiling " << method->PrettyMethod() << " because it has the resolution stub"; + // Give it a new chance to be hot. + ClearMethodCounter(method, /*was_warm=*/ false); return false; } } @@ -1684,12 +1708,15 @@ void JitCodeCache::InvalidateAllCompiledCode() { OatQuickMethodHeader::FromCodePointer(data.GetCode()); for (ArtMethod* method : data.GetMethods()) { if (method->GetEntryPointFromQuickCompiledCode() == method_header->GetEntryPoint()) { + ClearMethodCounter(method, /*was_warm=*/true); instr->InitializeMethodsCode(method, /*aot_code=*/ nullptr); } } } for (const auto& entry : method_code_map_) { ArtMethod* meth = entry.second; + // We were compiled, so we must be warm. + ClearMethodCounter(meth, /*was_warm=*/true); if (UNLIKELY(meth->IsObsolete())) { linker->SetEntryPointsForObsoleteMethod(meth); } else { @@ -1719,8 +1746,10 @@ void JitCodeCache::InvalidateCompiledCodeFor(ArtMethod* method, // Clear the method counter if we are running jitted code since we might want to jit this again in // the future. if (method_entrypoint == header->GetEntryPoint()) { - // The entrypoint is the one to invalidate, so we just update it to the interpreter entry point. + // The entrypoint is the one to invalidate, so we just update it to the interpreter entry point + // and clear the counter to get the method Jitted again. Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr); + ClearMethodCounter(method, /*was_warm=*/ true); } else { Thread* self = Thread::Current(); ScopedDebugDisallowReadBarriers sddrb(self); diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h index 3dd57121ca..7de29d4024 100644 --- a/runtime/jit/jit_code_cache.h +++ b/runtime/jit/jit_code_cache.h @@ -414,6 +414,7 @@ class JitCodeCache { } ProfilingInfo* GetProfilingInfo(ArtMethod* method, Thread* self); + void ResetHotnessCounter(ArtMethod* method, Thread* self); void MaybeUpdateInlineCache(ArtMethod* method, uint32_t dex_pc, ObjPtr<mirror::Class> cls, diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index 3506faaa7f..abf01f5498 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -335,6 +335,7 @@ class ProfileSaver::GetClassesAndMethodsHelper { REQUIRES_SHARED(Locks::mutator_lock_) : startup_(startup), profile_boot_class_path_(options.GetProfileBootClassPath()), + hot_method_sample_threshold_(CalculateHotMethodSampleThreshold(startup, options)), extra_flags_(GetExtraMethodHotnessFlags(options)), annotation_(annotation), arena_stack_(Runtime::Current()->GetArenaPool()), @@ -357,6 +358,10 @@ class ProfileSaver::GetClassesAndMethodsHelper { void CollectClasses(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); void UpdateProfile(const std::set<std::string>& locations, ProfileCompilationInfo* profile_info); + uint32_t GetHotMethodSampleThreshold() const { + return hot_method_sample_threshold_; + } + size_t GetNumberOfHotMethods() const { return number_of_hot_methods_; } @@ -404,6 +409,19 @@ class ProfileSaver::GetClassesAndMethodsHelper { using DexFileRecordsMap = ScopedArenaHashMap<const DexFile*, DexFileRecords*>; + static uint32_t CalculateHotMethodSampleThreshold(bool startup, + const ProfileSaverOptions& options) { + Runtime* runtime = Runtime::Current(); + if (startup) { + const bool is_low_ram = runtime->GetHeap()->IsLowMemoryMode(); + return options.GetHotStartupMethodSamples(is_low_ram); + } else if (runtime->GetJit() != nullptr) { + return runtime->GetJit()->WarmMethodThreshold(); + } else { + return std::numeric_limits<uint32_t>::max(); + } + } + ALWAYS_INLINE static bool ShouldCollectClasses(bool startup) { // We only record classes for the startup case. This may change in the future. return startup; @@ -416,6 +434,7 @@ class ProfileSaver::GetClassesAndMethodsHelper { const bool startup_; const bool profile_boot_class_path_; + const uint32_t hot_method_sample_threshold_; const uint32_t extra_flags_; const ProfileCompilationInfo::ProfileSampleAnnotation annotation_; ArenaStack arena_stack_; @@ -590,6 +609,7 @@ void ProfileSaver::GetClassesAndMethodsHelper::UpdateProfile(const std::set<std: ProfileCompilationInfo* profile_info) { // Move members to local variables to allow the compiler to optimize this properly. const bool startup = startup_; + const uint32_t hot_method_sample_threshold = hot_method_sample_threshold_; const uint32_t base_flags = (startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup) | extra_flags_; @@ -599,9 +619,10 @@ void ProfileSaver::GetClassesAndMethodsHelper::UpdateProfile(const std::set<std: uint16_t initial_value = Runtime::Current()->GetJITOptions()->GetWarmupThreshold(); auto get_method_flags = [&](ArtMethod& method) { - // Mark methods as hot if they are marked as such (warm for the runtime - // means hot for the profile). - if (method.PreviouslyWarm()) { + // Mark methods as hot if they have more than hot_method_sample_threshold + // samples. This means they will get compiled by the compiler driver. + if (method.PreviouslyWarm() || + method.CounterHasReached(hot_method_sample_threshold, initial_value)) { ++number_of_hot_methods; return enum_cast<ProfileCompilationInfo::MethodHotness::Flag>(base_flags | Hotness::kFlagHot); } else if (method.CounterHasChanged(initial_value)) { @@ -729,6 +750,7 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) { profiler_pthread = profiler_pthread_; } + uint32_t hot_method_sample_threshold = 0u; size_t number_of_hot_methods = 0u; size_t number_of_sampled_methods = 0u; { @@ -743,6 +765,7 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) { ScopedObjectAccess soa(self); GetClassesAndMethodsHelper helper(startup, options_, GetProfileSampleAnnotation()); + hot_method_sample_threshold = helper.GetHotMethodSampleThreshold(); helper.CollectClasses(self); // Release the mutator lock. We shall need to re-acquire the lock for a moment to @@ -777,7 +800,8 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) { } VLOG(profiler) << "Profile saver recorded " << number_of_hot_methods << " hot methods and " << number_of_sampled_methods - << " sampled methods in " << PrettyDuration(NanoTime() - start_time); + << " sampled methods with threshold " << hot_method_sample_threshold + << " in " << PrettyDuration(NanoTime() - start_time); } bool ProfileSaver::ProcessProfilingInfo( diff --git a/runtime/jit/profile_saver_options.h b/runtime/jit/profile_saver_options.h index ed2f00f48f..f6d928ff6b 100644 --- a/runtime/jit/profile_saver_options.h +++ b/runtime/jit/profile_saver_options.h @@ -26,10 +26,14 @@ struct ProfileSaverOptions { // 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; + static constexpr uint32_t kHotStartupMethodSamplesLowRam = 256; static constexpr uint32_t kMinMethodsToSave = 10; static constexpr uint32_t kMinClassesToSave = 10; static constexpr uint32_t kMinNotificationBeforeWake = 10; static constexpr uint32_t kMaxNotificationBeforeWake = 50; + static constexpr uint32_t kHotStartupMethodSamplesNotSet = std::numeric_limits<uint32_t>::max(); static constexpr uint16_t kInlineCacheThreshold = 4000; ProfileSaverOptions() : @@ -37,6 +41,7 @@ struct ProfileSaverOptions { 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), min_classes_to_save_(kMinClassesToSave), min_notification_before_wake_(kMinNotificationBeforeWake), @@ -52,6 +57,7 @@ struct ProfileSaverOptions { 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, uint32_t min_classes_to_save, uint32_t min_notification_before_wake, @@ -65,6 +71,7 @@ struct ProfileSaverOptions { 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), min_classes_to_save_(min_classes_to_save), min_notification_before_wake_(min_notification_before_wake), @@ -91,6 +98,13 @@ struct ProfileSaverOptions { uint32_t GetSaveResolvedClassesDelayMs() const { return save_resolved_classes_delay_ms_; } + uint32_t GetHotStartupMethodSamples(bool is_low_ram) const { + uint32_t ret = hot_startup_method_samples_; + if (ret == kHotStartupMethodSamplesNotSet) { + ret = is_low_ram ? kHotStartupMethodSamplesLowRam : kHotStartupMethodSamples; + } + return ret; + } uint32_t GetMinMethodsToSave() const { return min_methods_to_save_; } @@ -127,6 +141,7 @@ struct ProfileSaverOptions { << ", 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_ << ", min_classes_to_save_" << pso.min_classes_to_save_ << ", min_notification_before_wake_" << pso.min_notification_before_wake_ @@ -142,6 +157,9 @@ struct ProfileSaverOptions { 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. + uint32_t hot_startup_method_samples_; uint32_t min_methods_to_save_; uint32_t min_classes_to_save_; uint32_t min_notification_before_wake_; diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h index a32b712b0c..ae59d0ade1 100644 --- a/runtime/jit/profiling_info.h +++ b/runtime/jit/profiling_info.h @@ -171,6 +171,14 @@ class ProfilingInfo { return MemberOffset(OFFSETOF_MEMBER(ProfilingInfo, baseline_hotness_count_)); } + void ResetCounter() { + baseline_hotness_count_ = GetOptimizeThreshold(); + } + + bool CounterHasChanged() const { + return baseline_hotness_count_ != GetOptimizeThreshold(); + } + uint16_t GetBaselineHotnessCount() const { return baseline_hotness_count_; } diff --git a/test/2230-profile-save-hotness/run.py b/test/2230-profile-save-hotness/run.py index e2f4473b86..526b841b87 100644 --- a/test/2230-profile-save-hotness/run.py +++ b/test/2230-profile-save-hotness/run.py @@ -16,11 +16,10 @@ def run(ctx, args): ctx.default_run( args, - # Profiling is only done on interpreted and JITted code. Xcompiler_option=[ - "--compiler-filter=verify" + "--count-hotness-in-compiled-code", "--compiler-filter=speed" ], runtime_option=[ - "-Xjitsaveprofilinginfo", "-Xusejit:true" + "-Xps-profile-aot-code", "-Xjitsaveprofilinginfo", "-Xusejit:true" ], ) diff --git a/test/2230-profile-save-hotness/src-art/Main.java b/test/2230-profile-save-hotness/src-art/Main.java index 06e89b2ade..c9132e6e7d 100644 --- a/test/2230-profile-save-hotness/src-art/Main.java +++ b/test/2230-profile-save-hotness/src-art/Main.java @@ -47,7 +47,7 @@ public class Main { new String[] {codePath}, VMRuntime.CODE_PATH_TYPE_PRIMARY_APK); - // Test that the profile saves an app method that gets JITted. + // Test that the profile saves an app method with a profiling info. $noinline$hotnessCountWithLoop(100000); ensureProfileProcessing(); Method appMethod = Main.class.getDeclaredMethod(methodName); @@ -72,7 +72,7 @@ public class Main { } } - // Checks if the profile saver has the method as hot/warm. + // Checks if the profiles saver has the method as hot/warm. public static native boolean presentInProfile(String profile, Method method); // Ensures the profile saver does its usual processing. public static native void ensureProfileProcessing(); |