diff options
author | 2020-08-06 21:20:55 +0000 | |
---|---|---|
committer | 2020-08-06 22:51:54 +0000 | |
commit | a996425197a7946eae02d218f70610a853f2fe9a (patch) | |
tree | 402596c3af0e7928d7c19c3773ea02cb507998b1 | |
parent | 193b696b1c35a49d4173c8b669a4ed79cb24748a (diff) |
Revert "Cleanups around the creation of ProfilingInfo."
This reverts commit 0fa304ee0fa63149222bfc6756f56cd285c56bd1.
Reason for revert: 685-deoptimizeable test is failing on
host debuggable (and cdex-redefine-stress-jit once) targets
Bug: 112676029
Test: ./test.py --host --debuggable
Change-Id: I88cf51ec48d704f966066ea9f2dbb17d32648f5a
-rw-r--r-- | runtime/jit/jit.cc | 15 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 58 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.h | 13 | ||||
-rw-r--r-- | runtime/jit/profiling_info.cc | 4 | ||||
-rw-r--r-- | runtime/jit/profiling_info.h | 5 | ||||
-rw-r--r-- | test/570-checker-osr/osr.cc | 2 | ||||
-rw-r--r-- | test/595-profile-saving/profile-saving.cc | 2 | ||||
-rw-r--r-- | test/common/runtime_state.cc | 14 |
8 files changed, 88 insertions, 25 deletions
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index cdd69e0724..4921a99991 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -331,7 +331,8 @@ bool Jit::CompileMethod(ArtMethod* method, // If we get a request to compile a proxy method, we pass the actual Java method // of that proxy method, as the compiler does not expect a proxy method. ArtMethod* method_to_compile = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); - if (!code_cache_->NotifyCompilationOf(method_to_compile, self, compilation_kind, prejit)) { + if (!code_cache_->NotifyCompilationOf( + method_to_compile, self, compilation_kind, prejit, region)) { return false; } @@ -757,6 +758,7 @@ void Jit::NotifyZygoteCompilationDone() { class JitCompileTask final : public Task { public: enum class TaskKind { + kAllocateProfile, kCompile, kPreCompile, }; @@ -795,6 +797,12 @@ class JitCompileTask final : public Task { /* prejit= */ (kind_ == TaskKind::kPreCompile)); break; } + case TaskKind::kAllocateProfile: { + if (ProfilingInfo::Create(self, method_, /* retry_allocation= */ true)) { + VLOG(jit) << "Start profiling " << ArtMethod::PrettyMethod(method_); + } + break; + } } } ProfileSaver::NotifyJitActivity(); @@ -1587,6 +1595,10 @@ void Jit::MethodEntered(Thread* thread, ArtMethod* method) { if (UNLIKELY(runtime->UseJitCompilation() && JitAtFirstUse())) { ArtMethod* np_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); if (np_method->IsCompilable()) { + if (!np_method->IsNative() && GetCodeCache()->CanAllocateProfilingInfo()) { + // The compiler requires a ProfilingInfo object for non-native methods. + ProfilingInfo::Create(thread, np_method, /* retry_allocation= */ true); + } // TODO(ngeoffray): For JIT at first use, use kPreCompile. Currently we don't due to // conflicts with jitzygote optimizations. JitCompileTask compile_task( @@ -1801,6 +1813,7 @@ void Jit::EnqueueCompilationFromNterp(ArtMethod* method, Thread* self) { return; } if (GetCodeCache()->CanAllocateProfilingInfo()) { + ProfilingInfo::Create(self, method, /* retry_allocation= */ false); thread_pool_->AddTask( self, new JitCompileTask(method, JitCompileTask::TaskKind::kCompile, CompilationKind::kBaseline)); diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index cf28fe12df..4b9538d093 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -286,6 +286,15 @@ bool JitCodeCache::ContainsPc(const void* ptr) const { return PrivateRegionContainsPc(ptr) || shared_region_.IsInExecSpace(ptr); } +bool JitCodeCache::WillExecuteJitCode(ArtMethod* method) { + ScopedObjectAccess soa(art::Thread::Current()); + ScopedAssertNoThreadSuspension sants(__FUNCTION__); + if (ContainsPc(method->GetEntryPointFromQuickCompiledCode())) { + return true; + } + return false; +} + bool JitCodeCache::ContainsMethod(ArtMethod* method) { MutexLock mu(Thread::Current(), *Locks::jit_lock_); if (UNLIKELY(method->IsNative())) { @@ -1460,18 +1469,30 @@ OatQuickMethodHeader* JitCodeCache::LookupOsrMethodHeader(ArtMethod* method) { ProfilingInfo* JitCodeCache::AddProfilingInfo(Thread* self, ArtMethod* method, - const std::vector<uint32_t>& entries) { + const std::vector<uint32_t>& entries, + bool retry_allocation) + // No thread safety analysis as we are using TryLock/Unlock explicitly. + NO_THREAD_SAFETY_ANALYSIS { DCHECK(CanAllocateProfilingInfo()); ProfilingInfo* info = nullptr; - { - MutexLock mu(self, *Locks::jit_lock_); - info = AddProfilingInfoInternal(self, method, entries); - } + if (!retry_allocation) { + // If we are allocating for the interpreter, just try to lock, to avoid + // lock contention with the JIT. + if (Locks::jit_lock_->ExclusiveTryLock(self)) { + info = AddProfilingInfoInternal(self, method, entries); + Locks::jit_lock_->ExclusiveUnlock(self); + } + } else { + { + MutexLock mu(self, *Locks::jit_lock_); + info = AddProfilingInfoInternal(self, method, entries); + } - if (info == nullptr) { - GarbageCollectCache(self); - MutexLock mu(self, *Locks::jit_lock_); - info = AddProfilingInfoInternal(self, method, entries); + if (info == nullptr) { + GarbageCollectCache(self); + MutexLock mu(self, *Locks::jit_lock_); + info = AddProfilingInfoInternal(self, method, entries); + } } return info; } @@ -1604,7 +1625,8 @@ bool JitCodeCache::IsOsrCompiled(ArtMethod* method) { bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self, CompilationKind compilation_kind, - bool prejit) { + bool prejit, + JitMemoryRegion* region) { const void* existing_entry_point = method->GetEntryPointFromQuickCompiledCode(); if (compilation_kind != CompilationKind::kOsr && ContainsPc(existing_entry_point)) { OatQuickMethodHeader* method_header = @@ -1678,11 +1700,21 @@ bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, } return new_compilation; } else { + ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize); if (CanAllocateProfilingInfo() && (compilation_kind == CompilationKind::kBaseline) && - (method->GetProfilingInfo(kRuntimePointerSize) == nullptr)) { - if (ProfilingInfo::Create(self, method) == nullptr) { - VLOG(jit) << method->PrettyMethod() << " needs a ProfilingInfo to be compiled baseline"; + (info == nullptr)) { + // We can retry allocation here as we're the JIT thread. + if (ProfilingInfo::Create(self, method, /* retry_allocation= */ true)) { + info = method->GetProfilingInfo(kRuntimePointerSize); + } + } + if (info == nullptr) { + // When prejitting, we don't allocate a profiling info. + if (!prejit && !IsSharedRegion(*region)) { + VLOG(jit) << method->PrettyMethod() << " needs a ProfilingInfo to be compiled"; + // Because the counter is not atomic, there are some rare cases where we may not hit the + // threshold for creating the ProfilingInfo. Reset the counter now to "correct" this. ClearMethodCounter(method, /*was_warm=*/ false); return false; } diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h index 7c828aebdc..e8ab117cec 100644 --- a/runtime/jit/jit_code_cache.h +++ b/runtime/jit/jit_code_cache.h @@ -197,7 +197,8 @@ class JitCodeCache { bool NotifyCompilationOf(ArtMethod* method, Thread* self, CompilationKind compilation_kind, - bool prejit) + bool prejit, + JitMemoryRegion* region) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::jit_lock_); @@ -227,6 +228,10 @@ class JitCodeCache { // Return true if the code cache contains this pc in the private region (i.e. not from zygote). bool PrivateRegionContainsPc(const void* pc) const; + // Returns true if either the method's entrypoint is JIT compiled code or it is the + // instrumentation entrypoint and we can jump to jit code for this method. For testing use only. + bool WillExecuteJitCode(ArtMethod* method) REQUIRES(!Locks::jit_lock_); + // Return true if the code cache contains this method. bool ContainsMethod(ArtMethod* method) REQUIRES(!Locks::jit_lock_); @@ -309,10 +314,12 @@ class JitCodeCache { REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - // Create a 'ProfileInfo' for 'method'. + // Create a 'ProfileInfo' for 'method'. If 'retry_allocation' is true, + // will collect and retry if the first allocation is unsuccessful. ProfilingInfo* AddProfilingInfo(Thread* self, ArtMethod* method, - const std::vector<uint32_t>& entries) + const std::vector<uint32_t>& entries, + bool retry_allocation) REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc index 93951eeeca..a61a30df0e 100644 --- a/runtime/jit/profiling_info.cc +++ b/runtime/jit/profiling_info.cc @@ -36,7 +36,7 @@ ProfilingInfo::ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& ent } } -ProfilingInfo* ProfilingInfo::Create(Thread* self, ArtMethod* method) { +bool ProfilingInfo::Create(Thread* self, ArtMethod* method, bool retry_allocation) { // Walk over the dex instructions of the method and keep track of // instructions we are interested in profiling. DCHECK(!method->IsNative()); @@ -63,7 +63,7 @@ ProfilingInfo* ProfilingInfo::Create(Thread* self, ArtMethod* method) { // Allocate the `ProfilingInfo` object int the JIT's data space. jit::JitCodeCache* code_cache = Runtime::Current()->GetJit()->GetCodeCache(); - return code_cache->AddProfilingInfo(self, method, entries); + return code_cache->AddProfilingInfo(self, method, entries, retry_allocation) != nullptr; } InlineCache* ProfilingInfo::GetInlineCache(uint32_t dex_pc) { diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h index d136b4c6f6..cbe2445c01 100644 --- a/runtime/jit/profiling_info.h +++ b/runtime/jit/profiling_info.h @@ -63,8 +63,9 @@ class InlineCache { */ class ProfilingInfo { public: - // Create a ProfilingInfo for 'method'. - static ProfilingInfo* Create(Thread* self, ArtMethod* method) + // Create a ProfilingInfo for 'method'. Return whether it succeeded, or if it is + // not needed in case the method does not have virtual/interface invocations. + static bool Create(Thread* self, ArtMethod* method, bool retry_allocation) REQUIRES_SHARED(Locks::mutator_lock_); // Add information from an executed INVOKE instruction to the profile. diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc index d1caf3fc8c..b7365dd430 100644 --- a/test/570-checker-osr/osr.cc +++ b/test/570-checker-osr/osr.cc @@ -109,7 +109,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasProfilingInfo(JNIEnv* env, method_name, [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod* m = stack_visitor->GetMethod(); - ProfilingInfo::Create(Thread::Current(), m); + ProfilingInfo::Create(Thread::Current(), m, /* retry_allocation */ true); }); } diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc index 95aa7e9a81..d6ca447dc4 100644 --- a/test/595-profile-saving/profile-saving.cc +++ b/test/595-profile-saving/profile-saving.cc @@ -39,7 +39,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_ensureProfilingInfo(JNIEnv* env, ScopedObjectAccess soa(env); ObjPtr<mirror::Executable> exec = soa.Decode<mirror::Executable>(method); ArtMethod* art_method = exec->GetArtMethod(); - if (ProfilingInfo::Create(soa.Self(), art_method) == nullptr) { + if (!ProfilingInfo::Create(soa.Self(), art_method, /* retry_allocation */ true)) { LOG(ERROR) << "Failed to create profiling info for method " << art_method->PrettyMethod(); } } diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index 09f1a5322b..0e477827f7 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -230,9 +230,12 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledCode(JNIEnv* env, } static void ForceJitCompiled(Thread* self, ArtMethod* method) REQUIRES(!Locks::mutator_lock_) { + bool native = false; { ScopedObjectAccess soa(self); - if (!Runtime::Current()->GetRuntimeCallbacks()->IsMethodSafeToJit(method)) { + if (method->IsNative()) { + native = true; + } else if (!Runtime::Current()->GetRuntimeCallbacks()->IsMethodSafeToJit(method)) { std::string msg(method->PrettyMethod()); msg += ": is not safe to jit!"; ThrowIllegalStateException(msg.c_str()); @@ -267,17 +270,24 @@ static void ForceJitCompiled(Thread* self, ArtMethod* method) REQUIRES(!Locks::m // Note: this will apply to all JIT compilations. code_cache->SetGarbageCollectCode(false); while (true) { - if (code_cache->ContainsMethod(method)) { + if (native && code_cache->ContainsMethod(method)) { break; } else { // Sleep to yield to the compiler thread. usleep(1000); ScopedObjectAccess soa(self); + if (!native && jit->GetCodeCache()->CanAllocateProfilingInfo()) { + // Make sure there is a profiling info, required by the compiler. + ProfilingInfo::Create(self, method, /* retry_allocation */ true); + } // Will either ensure it's compiled or do the compilation itself. We do // this before checking if we will execute JIT code to make sure the // method is compiled 'optimized' and not baseline (tests expect optimized // compilation). jit->CompileMethod(method, self, CompilationKind::kOptimized, /*prejit=*/ false); + if (code_cache->WillExecuteJitCode(method)) { + break; + } } } } |