diff options
author | 2016-04-07 17:09:25 +0100 | |
---|---|---|
committer | 2016-04-13 12:42:29 +0100 | |
commit | b2771b41a956b50266d4d83fbb067f99faf7b7dc (patch) | |
tree | 797b73b8b97c496938a9f6bc498d75911b1ff3c9 | |
parent | f9eed16e175f8c7cb37d878acc772d653b07101e (diff) |
Add option to tune sample collection based on thread sensitivity
Bug: 28065407
Bug: 27865109
Change-Id: Icdb89f8f8874a41c07e73185523d18e8956620d3
-rw-r--r-- | runtime/interpreter/mterp/mterp.cc | 4 | ||||
-rw-r--r-- | runtime/jit/jit.cc | 28 | ||||
-rw-r--r-- | runtime/jit/jit.h | 10 | ||||
-rw-r--r-- | runtime/jit/jit_instrumentation.cc | 9 | ||||
-rw-r--r-- | runtime/jit/jit_instrumentation.h | 8 | ||||
-rw-r--r-- | runtime/monitor.cc | 11 | ||||
-rw-r--r-- | runtime/monitor.h | 4 | ||||
-rw-r--r-- | runtime/monitor_android.cc | 2 | ||||
-rw-r--r-- | runtime/parsed_options.cc | 4 | ||||
-rw-r--r-- | runtime/runtime.cc | 7 | ||||
-rw-r--r-- | runtime/runtime_options.def | 1 | ||||
-rw-r--r-- | runtime/thread.cc | 2 | ||||
-rw-r--r-- | runtime/thread.h | 15 |
13 files changed, 83 insertions, 22 deletions
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc index 1da1181503..0af72ce4a0 100644 --- a/runtime/interpreter/mterp/mterp.cc +++ b/runtime/interpreter/mterp/mterp.cc @@ -665,6 +665,10 @@ extern "C" int MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow } else { countdown_value = jit::kJitCheckForOSR; } + if (jit::Jit::ShouldUsePriorityThreadWeight()) { + int32_t priority_thread_weight = cache->PriorityThreadWeight(); + countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight); + } } /* * The actual hotness threshold may exceed the range of our int16_t countdown value. This is diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 4db9f71a90..3344346f06 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -86,9 +86,29 @@ JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& opt } } + if (options.Exists(RuntimeArgumentMap::JITPriorityThreadWeight)) { + jit_options->priority_thread_weight_ = + *options.Get(RuntimeArgumentMap::JITPriorityThreadWeight); + if (jit_options->priority_thread_weight_ > jit_options->warmup_threshold_) { + LOG(FATAL) << "Priority thread weight is above the warmup threshold."; + } else if (jit_options->priority_thread_weight_ == 0) { + LOG(FATAL) << "Priority thread weight cannot be 0."; + } + } else { + jit_options->priority_thread_weight_ = + std::max(jit_options->compile_threshold_ / 2000, static_cast<size_t>(1)); + } + return jit_options; } +bool Jit::ShouldUsePriorityThreadWeight() { + // TODO(calin): verify that IsSensitiveThread covers only the cases we are interested on. + // In particular if apps can set StrictMode policies for any of their threads, case in which + // we need to find another way to track sensitive threads. + return Runtime::Current()->InJankPerceptibleProcessState() && Thread::IsSensitiveThread(); +} + void Jit::DumpInfo(std::ostream& os) { code_cache_->Dump(os); cumulative_timings_.Dump(os); @@ -267,9 +287,13 @@ Jit::~Jit() { void Jit::CreateInstrumentationCache(size_t compile_threshold, size_t warmup_threshold, - size_t osr_threshold) { + size_t osr_threshold, + uint16_t priority_thread_weight) { instrumentation_cache_.reset( - new jit::JitInstrumentationCache(compile_threshold, warmup_threshold, osr_threshold)); + new jit::JitInstrumentationCache(compile_threshold, + warmup_threshold, + osr_threshold, + priority_thread_weight)); } void Jit::NewTypeLoadedIfUsingJit(mirror::Class* type) { diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index 76f540d48a..e2123666f9 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -48,7 +48,8 @@ class Jit { SHARED_REQUIRES(Locks::mutator_lock_); void CreateInstrumentationCache(size_t compile_threshold, size_t warmup_threshold, - size_t osr_threshold); + size_t osr_threshold, + uint16_t priority_thread_weight); void CreateThreadPool(); const JitCodeCache* GetCodeCache() const { return code_cache_.get(); @@ -101,6 +102,9 @@ class Jit { // Return whether we can invoke JIT code for `method`. bool CanInvokeCompiledCode(ArtMethod* method); + // Return whether the runtime should use a priority thread weight when sampling. + static bool ShouldUsePriorityThreadWeight(); + // If an OSR compiled version is available for `method`, // and `dex_pc + dex_pc_offset` is an entry point of that compiled // version, this method will jump to the compiled code, let it run, @@ -154,6 +158,9 @@ class JitOptions { size_t GetOsrThreshold() const { return osr_threshold_; } + uint16_t GetPriorityThreadWeight() const { + return priority_thread_weight_; + } size_t GetCodeCacheInitialCapacity() const { return code_cache_initial_capacity_; } @@ -187,6 +194,7 @@ class JitOptions { size_t compile_threshold_; size_t warmup_threshold_; size_t osr_threshold_; + uint16_t priority_thread_weight_; bool dump_info_on_shutdown_; bool save_profiling_info_; diff --git a/runtime/jit/jit_instrumentation.cc b/runtime/jit/jit_instrumentation.cc index d2180c7ce2..b2c0c20237 100644 --- a/runtime/jit/jit_instrumentation.cc +++ b/runtime/jit/jit_instrumentation.cc @@ -82,10 +82,12 @@ class JitCompileTask FINAL : public Task { JitInstrumentationCache::JitInstrumentationCache(uint16_t hot_method_threshold, uint16_t warm_method_threshold, - uint16_t osr_method_threshold) + uint16_t osr_method_threshold, + uint16_t priority_thread_weight) : hot_method_threshold_(hot_method_threshold), warm_method_threshold_(warm_method_threshold), osr_method_threshold_(osr_method_threshold), + priority_thread_weight_(priority_thread_weight), listener_(this) { } @@ -145,8 +147,13 @@ void JitInstrumentationCache::AddSamples(Thread* self, ArtMethod* method, uint16 DCHECK_GT(warm_method_threshold_, 0); DCHECK_GT(hot_method_threshold_, warm_method_threshold_); DCHECK_GT(osr_method_threshold_, hot_method_threshold_); + DCHECK_GE(priority_thread_weight_, 1); + DCHECK_LE(priority_thread_weight_, hot_method_threshold_); int32_t starting_count = method->GetCounter(); + if (Jit::ShouldUsePriorityThreadWeight()) { + count *= priority_thread_weight_; + } int32_t new_count = starting_count + count; // int32 here to avoid wrap-around; if (starting_count < warm_method_threshold_) { if (new_count >= warm_method_threshold_) { diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h index 7ffd4ebb84..d0545f8e24 100644 --- a/runtime/jit/jit_instrumentation.h +++ b/runtime/jit/jit_instrumentation.h @@ -99,7 +99,8 @@ class JitInstrumentationCache { public: JitInstrumentationCache(uint16_t hot_method_threshold, uint16_t warm_method_threshold, - uint16_t osr_method_threshold); + uint16_t osr_method_threshold, + uint16_t priority_thread_weight); void AddSamples(Thread* self, ArtMethod* method, uint16_t samples) SHARED_REQUIRES(Locks::mutator_lock_); void CreateThreadPool(); @@ -117,6 +118,10 @@ class JitInstrumentationCache { return warm_method_threshold_; } + size_t PriorityThreadWeight() const { + return priority_thread_weight_; + } + // Wait until there is no more pending compilation tasks. void WaitForCompilationToFinish(Thread* self); @@ -124,6 +129,7 @@ class JitInstrumentationCache { uint16_t hot_method_threshold_; uint16_t warm_method_threshold_; uint16_t osr_method_threshold_; + uint16_t priority_thread_weight_; JitInstrumentationListener listener_; std::unique_ptr<ThreadPool> thread_pool_; diff --git a/runtime/monitor.cc b/runtime/monitor.cc index a262c7a8f3..6290cb2ff7 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -67,19 +67,10 @@ static constexpr uint64_t kLongWaitMs = 100; * at any given time. */ -bool (*Monitor::is_sensitive_thread_hook_)() = nullptr; uint32_t Monitor::lock_profiling_threshold_ = 0; -bool Monitor::IsSensitiveThread() { - if (is_sensitive_thread_hook_ != nullptr) { - return (*is_sensitive_thread_hook_)(); - } - return false; -} - -void Monitor::Init(uint32_t lock_profiling_threshold, bool (*is_sensitive_thread_hook)()) { +void Monitor::Init(uint32_t lock_profiling_threshold) { lock_profiling_threshold_ = lock_profiling_threshold; - is_sensitive_thread_hook_ = is_sensitive_thread_hook; } Monitor::Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code) diff --git a/runtime/monitor.h b/runtime/monitor.h index 707d0f112c..ae9b3cca82 100644 --- a/runtime/monitor.h +++ b/runtime/monitor.h @@ -55,8 +55,7 @@ class Monitor { ~Monitor(); - static bool IsSensitiveThread(); - static void Init(uint32_t lock_profiling_threshold, bool (*is_sensitive_thread_hook)()); + static void Init(uint32_t lock_profiling_threshold); // Return the thread id of the lock owner or 0 when there is no owner. static uint32_t GetLockOwnerThreadId(mirror::Object* obj) @@ -240,7 +239,6 @@ class Monitor { uint32_t GetOwnerThreadId() REQUIRES(!monitor_lock_); - static bool (*is_sensitive_thread_hook_)(); static uint32_t lock_profiling_threshold_; Mutex monitor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; diff --git a/runtime/monitor_android.cc b/runtime/monitor_android.cc index 82ef2d841a..671cb60037 100644 --- a/runtime/monitor_android.cc +++ b/runtime/monitor_android.cc @@ -66,7 +66,7 @@ void Monitor::LogContentionEvent(Thread* self, uint32_t wait_ms, uint32_t sample cp = EventLogWriteString(cp, procName, len); // Emit the sensitive thread ("main thread") status, 5 bytes. - cp = EventLogWriteInt(cp, Monitor::IsSensitiveThread()); + cp = EventLogWriteInt(cp, Thread::IsSensitiveThread()); // Emit self thread name string, <= 37 bytes. std::string thread_name; diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 48c91f6050..c8d429158c 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -169,6 +169,9 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .Define("-Xjitosrthreshold:_") .WithType<unsigned int>() .IntoKey(M::JITOsrThreshold) + .Define("-Xjitprithreadweight:_") + .WithType<unsigned int>() + .IntoKey(M::JITPriorityThreadWeight) .Define("-Xjitsaveprofilinginfo") .WithValue(true) .IntoKey(M::JITSaveProfilingInfo) @@ -702,6 +705,7 @@ void ParsedOptions::Usage(const char* fmt, ...) { UsageMessage(stream, " -Xjitmaxsize:N\n"); UsageMessage(stream, " -Xjitwarmupthreshold:integervalue\n"); UsageMessage(stream, " -Xjitosrthreshold:integervalue\n"); + UsageMessage(stream, " -Xjitprithreadweight:integervalue\n"); UsageMessage(stream, " -X[no]relocate\n"); UsageMessage(stream, " -X[no]dex2oat (Whether to invoke dex2oat on the application)\n"); UsageMessage(stream, " -X[no]image-dex2oat (Whether to create and use a boot image)\n"); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 0a65b6b1ff..37bb4c1fc1 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -903,8 +903,8 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { oat_file_manager_ = new OatFileManager; - Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold), - runtime_options.GetOrDefault(Opt::HookIsSensitiveThread)); + Thread::SetSensitiveThreadHook(runtime_options.GetOrDefault(Opt::HookIsSensitiveThread)); + Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold)); boot_class_path_string_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath); class_path_string_ = runtime_options.ReleaseOrDefault(Opt::ClassPath); @@ -1924,7 +1924,8 @@ void Runtime::CreateJit() { if (jit_.get() != nullptr) { jit_->CreateInstrumentationCache(jit_options_->GetCompileThreshold(), jit_options_->GetWarmupThreshold(), - jit_options_->GetOsrThreshold()); + jit_options_->GetOsrThreshold(), + jit_options_->GetPriorityThreadWeight()); jit_->CreateThreadPool(); // Notify native debugger about the classes already loaded before the creation of the jit. diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index 6a50ffaf86..6433c3352f 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -71,6 +71,7 @@ RUNTIME_OPTIONS_KEY (bool, DumpNativeStackOnSigQuit, true) RUNTIME_OPTIONS_KEY (unsigned int, JITCompileThreshold, jit::Jit::kDefaultCompileThreshold) RUNTIME_OPTIONS_KEY (unsigned int, JITWarmupThreshold) RUNTIME_OPTIONS_KEY (unsigned int, JITOsrThreshold) +RUNTIME_OPTIONS_KEY (unsigned int, JITPriorityThreadWeight) RUNTIME_OPTIONS_KEY (MemoryKiB, JITCodeCacheInitialCapacity, jit::JitCodeCache::kInitialCapacity) RUNTIME_OPTIONS_KEY (MemoryKiB, JITCodeCacheMaxCapacity, jit::JitCodeCache::kMaxCapacity) RUNTIME_OPTIONS_KEY (bool, JITSaveProfilingInfo, false) diff --git a/runtime/thread.cc b/runtime/thread.cc index 57ccabc09c..e015833c9c 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -88,6 +88,8 @@ bool Thread::is_started_ = false; pthread_key_t Thread::pthread_key_self_; ConditionVariable* Thread::resume_cond_ = nullptr; const size_t Thread::kStackOverflowImplicitCheckSize = GetStackOverflowReservedBytes(kRuntimeISA); +bool (*Thread::is_sensitive_thread_hook_)() = nullptr; + static constexpr bool kVerifyImageObjectsMarked = kIsDebugBuild; // For implicit overflow checks we reserve an extra piece of memory at the bottom diff --git a/runtime/thread.h b/runtime/thread.h index 3123c7147d..2218b5a9d8 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -1097,6 +1097,13 @@ class Thread { return debug_disallow_read_barrier_; } + static bool IsSensitiveThread() { + if (is_sensitive_thread_hook_ != nullptr) { + return (*is_sensitive_thread_hook_)(); + } + return false; + } + private: explicit Thread(bool daemon); ~Thread() REQUIRES(!Locks::mutator_lock_, !Locks::thread_suspend_count_lock_); @@ -1172,6 +1179,10 @@ class Thread { ALWAYS_INLINE void PassActiveSuspendBarriers() REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_); + static void SetSensitiveThreadHook(bool (*is_sensitive_thread_hook)()) { + is_sensitive_thread_hook_ = is_sensitive_thread_hook; + } + // 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to // change from being Suspended to Runnable without a suspend request occurring. union PACKED(4) StateAndFlags { @@ -1214,6 +1225,10 @@ class Thread { // their suspend count is > 0. static ConditionVariable* resume_cond_ GUARDED_BY(Locks::thread_suspend_count_lock_); + // Hook passed by framework which returns true + // when StrictMode events are traced for the current thread. + static bool (*is_sensitive_thread_hook_)(); + /***********************************************************************************************/ // Thread local storage. Fields are grouped by size to enable 32 <-> 64 searching to account for // pointer size differences. To encourage shorter encoding, more frequently used values appear |