diff options
author | Mathieu Chartier <mathieuc@google.com> | 2015-02-24 09:37:21 -0800 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2015-02-24 10:47:02 -0800 |
commit | e5f13e57ff8fa36342beb33830b3ec5942a61cca (patch) | |
tree | 02e370ecc4e0d955f28bfc71a41015f94fbb19b7 /runtime/jit | |
parent | 354d58ba776866ea7b1c71f0d0848d5aaa013ae3 (diff) | |
download | art-e5f13e57ff8fa36342beb33830b3ec5942a61cca.zip art-e5f13e57ff8fa36342beb33830b3ec5942a61cca.tar.gz art-e5f13e57ff8fa36342beb33830b3ec5942a61cca.tar.bz2 |
Revert "Revert "Add JIT""
Added missing EntryPointToCodePointer.
This reverts commit a5ca888d715cd0c6c421313211caa1928be3e399.
Change-Id: Ia74df0ef3a7babbdcb0466fd24da28e304e3f5af
Diffstat (limited to 'runtime/jit')
-rw-r--r-- | runtime/jit/jit.cc | 160 | ||||
-rw-r--r-- | runtime/jit/jit.h | 102 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 121 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.h | 118 | ||||
-rw-r--r-- | runtime/jit/jit_instrumentation.cc | 117 | ||||
-rw-r--r-- | runtime/jit/jit_instrumentation.h | 107 |
6 files changed, 725 insertions, 0 deletions
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc new file mode 100644 index 0000000..539c181 --- /dev/null +++ b/runtime/jit/jit.cc @@ -0,0 +1,160 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jit.h" + +#include <dlfcn.h> + +#include "entrypoints/runtime_asm_entrypoints.h" +#include "interpreter/interpreter.h" +#include "jit_code_cache.h" +#include "jit_instrumentation.h" +#include "mirror/art_method-inl.h" +#include "runtime.h" +#include "runtime_options.h" +#include "thread_list.h" +#include "utils.h" + +namespace art { +namespace jit { + +JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& options) { + if (!options.GetOrDefault(RuntimeArgumentMap::UseJIT)) { + return nullptr; + } + auto* jit_options = new JitOptions; + jit_options->code_cache_capacity_ = + options.GetOrDefault(RuntimeArgumentMap::JITCodeCacheCapacity); + jit_options->compile_threshold_ = + options.GetOrDefault(RuntimeArgumentMap::JITCompileThreshold); + return jit_options; +} + +Jit::Jit() + : jit_library_handle_(nullptr), jit_compiler_handle_(nullptr), jit_load_(nullptr), + jit_compile_method_(nullptr) { +} + +Jit* Jit::Create(JitOptions* options, std::string* error_msg) { + std::unique_ptr<Jit> jit(new Jit); + if (!jit->LoadCompiler(error_msg)) { + return nullptr; + } + jit->code_cache_.reset(JitCodeCache::Create(options->GetCodeCacheCapacity(), error_msg)); + if (jit->GetCodeCache() == nullptr) { + return nullptr; + } + LOG(INFO) << "JIT created with code_cache_capacity=" + << PrettySize(options->GetCodeCacheCapacity()) + << " compile_threshold=" << options->GetCompileThreshold(); + return jit.release(); +} + +bool Jit::LoadCompiler(std::string* error_msg) { + jit_library_handle_ = dlopen( + kIsDebugBuild ? "libartd-compiler.so" : "libart-compiler.so", RTLD_NOW); + if (jit_library_handle_ == nullptr) { + std::ostringstream oss; + oss << "JIT could not load libart-compiler.so: " << dlerror(); + *error_msg = oss.str(); + return false; + } + jit_load_ = reinterpret_cast<void* (*)(CompilerCallbacks**)>( + dlsym(jit_library_handle_, "jit_load")); + if (jit_load_ == nullptr) { + dlclose(jit_library_handle_); + *error_msg = "JIT couldn't find jit_load entry point"; + return false; + } + jit_unload_ = reinterpret_cast<void (*)(void*)>( + dlsym(jit_library_handle_, "jit_unload")); + if (jit_unload_ == nullptr) { + dlclose(jit_library_handle_); + *error_msg = "JIT couldn't find jit_unload entry point"; + return false; + } + jit_compile_method_ = reinterpret_cast<bool (*)(void*, mirror::ArtMethod*, Thread*)>( + dlsym(jit_library_handle_, "jit_compile_method")); + if (jit_compile_method_ == nullptr) { + dlclose(jit_library_handle_); + *error_msg = "JIT couldn't find jit_compile_method entry point"; + return false; + } + CompilerCallbacks* callbacks = nullptr; + VLOG(jit) << "Calling JitLoad interpreter_only=" + << Runtime::Current()->GetInstrumentation()->InterpretOnly(); + jit_compiler_handle_ = (jit_load_)(&callbacks); + if (jit_compiler_handle_ == nullptr) { + dlclose(jit_library_handle_); + *error_msg = "JIT couldn't load compiler"; + return false; + } + if (callbacks == nullptr) { + dlclose(jit_library_handle_); + *error_msg = "JIT compiler callbacks were not set"; + jit_compiler_handle_ = nullptr; + return false; + } + compiler_callbacks_ = callbacks; + return true; +} + +bool Jit::CompileMethod(mirror::ArtMethod* method, Thread* self) { + DCHECK(!method->IsRuntimeMethod()); + const bool result = jit_compile_method_(jit_compiler_handle_, method, self); + if (result) { + method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); + } + return result; +} + +void Jit::CreateThreadPool() { + CHECK(instrumentation_cache_.get() != nullptr); + instrumentation_cache_->CreateThreadPool(); +} + +void Jit::DeleteThreadPool() { + if (instrumentation_cache_.get() != nullptr) { + instrumentation_cache_->DeleteThreadPool(); + } +} + +Jit::~Jit() { + DeleteThreadPool(); + if (jit_compiler_handle_ != nullptr) { + jit_unload_(jit_compiler_handle_); + } + if (jit_library_handle_ != nullptr) { + dlclose(jit_library_handle_); + } +} + +void Jit::CreateInstrumentationCache(size_t compile_threshold) { + CHECK_GT(compile_threshold, 0U); + Runtime* const runtime = Runtime::Current(); + runtime->GetThreadList()->SuspendAll(); + // Add Jit interpreter instrumentation, tells the interpreter when to notify the jit to compile + // something. + instrumentation_cache_.reset(new jit::JitInstrumentationCache(compile_threshold)); + runtime->GetInstrumentation()->AddListener( + new jit::JitInstrumentationListener(instrumentation_cache_.get()), + instrumentation::Instrumentation::kMethodEntered | + instrumentation::Instrumentation::kBackwardBranch); + runtime->GetThreadList()->ResumeAll(); +} + +} // namespace jit +} // namespace art diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h new file mode 100644 index 0000000..b80015f --- /dev/null +++ b/runtime/jit/jit.h @@ -0,0 +1,102 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_JIT_JIT_H_ +#define ART_RUNTIME_JIT_JIT_H_ + +#include <unordered_map> + +#include "instrumentation.h" + +#include "atomic.h" +#include "base/macros.h" +#include "base/mutex.h" +#include "gc_root.h" +#include "jni.h" +#include "object_callbacks.h" +#include "thread_pool.h" + +namespace art { + +class CompilerCallbacks; +struct RuntimeArgumentMap; + +namespace jit { + +class JitCodeCache; +class JitInstrumentationCache; +class JitOptions; + +class Jit { + public: + static constexpr bool kStressMode = kIsDebugBuild; + static constexpr size_t kDefaultCompileThreshold = kStressMode ? 1 : 1000; + + virtual ~Jit(); + static Jit* Create(JitOptions* options, std::string* error_msg); + bool CompileMethod(mirror::ArtMethod* method, Thread* self) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void CreateInstrumentationCache(size_t compile_threshold); + void CreateThreadPool(); + CompilerCallbacks* GetCompilerCallbacks() { + return compiler_callbacks_; + } + const JitCodeCache* GetCodeCache() const { + return code_cache_.get(); + } + JitCodeCache* GetCodeCache() { + return code_cache_.get(); + } + void DeleteThreadPool(); + + private: + Jit(); + bool LoadCompiler(std::string* error_msg); + + // JIT compiler + void* jit_library_handle_; + void* jit_compiler_handle_; + void* (*jit_load_)(CompilerCallbacks**); + void (*jit_unload_)(void*); + bool (*jit_compile_method_)(void*, mirror::ArtMethod*, Thread*); + + std::unique_ptr<jit::JitInstrumentationCache> instrumentation_cache_; + std::unique_ptr<jit::JitCodeCache> code_cache_; + CompilerCallbacks* compiler_callbacks_; // Owned by the jit compiler. +}; + +class JitOptions { + public: + static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options); + size_t GetCompileThreshold() const { + return compile_threshold_; + } + size_t GetCodeCacheCapacity() const { + return code_cache_capacity_; + } + + private: + size_t code_cache_capacity_; + size_t compile_threshold_; + + JitOptions() : code_cache_capacity_(0), compile_threshold_(0) { + } +}; + +} // namespace jit +} // namespace art + +#endif // ART_RUNTIME_JIT_JIT_H_ diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc new file mode 100644 index 0000000..8d4965e --- /dev/null +++ b/runtime/jit/jit_code_cache.cc @@ -0,0 +1,121 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jit_code_cache.h" + +#include <sstream> + +#include "mem_map.h" +#include "mirror/art_method-inl.h" +#include "oat_file-inl.h" + +namespace art { +namespace jit { + +JitCodeCache* JitCodeCache::Create(size_t capacity, std::string* error_msg) { + CHECK_GT(capacity, 0U); + CHECK_LT(capacity, kMaxCapacity); + std::string error_str; + // Map name specific for android_os_Debug.cpp accounting. + MemMap* map = MemMap::MapAnonymous("jit-code-cache", nullptr, capacity, + PROT_READ | PROT_WRITE | PROT_EXEC, false, &error_str); + if (map == nullptr) { + std::ostringstream oss; + oss << "Failed to create read write execute cache: " << error_str << " size=" << capacity; + *error_msg = oss.str(); + return nullptr; + } + return new JitCodeCache(map); +} + +JitCodeCache::JitCodeCache(MemMap* mem_map) + : lock_("Jit code cache", kJitCodeCacheLock), num_methods_(0) { + VLOG(jit) << "Created jit code cache size=" << PrettySize(mem_map->Size()); + mem_map_.reset(mem_map); + uint8_t* divider = mem_map->Begin() + RoundUp(mem_map->Size() / 4, kPageSize); + // Data cache is 1 / 4 of the map. TODO: Make this variable? + // Put data at the start. + data_cache_ptr_ = mem_map->Begin(); + data_cache_end_ = divider; + data_cache_begin_ = data_cache_ptr_; + mprotect(data_cache_ptr_, data_cache_end_ - data_cache_begin_, PROT_READ | PROT_WRITE); + // Code cache after. + code_cache_begin_ = divider; + code_cache_ptr_ = divider; + code_cache_end_ = mem_map->End(); +} + +bool JitCodeCache::ContainsMethod(mirror::ArtMethod* method) const { + return ContainsCodePtr(method->GetEntryPointFromQuickCompiledCode()); +} + +bool JitCodeCache::ContainsCodePtr(const void* ptr) const { + return ptr >= code_cache_begin_ && ptr < code_cache_end_; +} + +void JitCodeCache::FlushInstructionCache() { + UNIMPLEMENTED(FATAL); + // TODO: Investigate if we need to do this. + // __clear_cache(reinterpret_cast<char*>(code_cache_begin_), static_cast<int>(CodeCacheSize())); +} + +uint8_t* JitCodeCache::ReserveCode(Thread* self, size_t size) { + MutexLock mu(self, lock_); + if (size > CodeCacheRemain()) { + return nullptr; + } + code_cache_ptr_ += size; + return code_cache_ptr_ - size; +} + +uint8_t* JitCodeCache::AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end) { + MutexLock mu(self, lock_); + const size_t size = end - begin; + if (size > DataCacheRemain()) { + return nullptr; // Out of space in the data cache. + } + std::copy(begin, end, data_cache_ptr_); + data_cache_ptr_ += size; + return data_cache_ptr_ - size; +} + +const void* JitCodeCache::GetCodeFor(mirror::ArtMethod* method) { + const void* code = method->GetEntryPointFromQuickCompiledCode(); + if (ContainsCodePtr(code)) { + return code; + } + MutexLock mu(Thread::Current(), lock_); + auto it = method_code_map_.find(method); + if (it != method_code_map_.end()) { + return it->second; + } + return nullptr; +} + +void JitCodeCache::SaveCompiledCode(mirror::ArtMethod* method, const void* old_code_ptr) { + DCHECK_EQ(method->GetEntryPointFromQuickCompiledCode(), old_code_ptr); + DCHECK(ContainsCodePtr(old_code_ptr)) << PrettyMethod(method) << " old_code_ptr=" + << old_code_ptr; + MutexLock mu(Thread::Current(), lock_); + auto it = method_code_map_.find(method); + if (it != method_code_map_.end()) { + return; + } + method_code_map_.Put(method, old_code_ptr); +} + +} // namespace jit +} // namespace art diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h new file mode 100644 index 0000000..aa8c717 --- /dev/null +++ b/runtime/jit/jit_code_cache.h @@ -0,0 +1,118 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_JIT_JIT_CODE_CACHE_H_ +#define ART_RUNTIME_JIT_JIT_CODE_CACHE_H_ + +#include "instrumentation.h" + +#include "atomic.h" +#include "base/macros.h" +#include "base/mutex.h" +#include "gc_root.h" +#include "jni.h" +#include "oat_file.h" +#include "object_callbacks.h" +#include "safe_map.h" +#include "thread_pool.h" + +namespace art { + +class CompiledMethod; +class CompilerCallbacks; + +namespace mirror { +class ArtMethod; +} // namespcae mirror + +namespace jit { + +class JitInstrumentationCache; + +class JitCodeCache { + public: + static constexpr size_t kMaxCapacity = 1 * GB; + static constexpr size_t kDefaultCapacity = 2 * MB; + + static JitCodeCache* Create(size_t capacity, std::string* error_msg); + + const uint8_t* CodeCachePtr() const { + return code_cache_ptr_; + } + size_t CodeCacheSize() const { + return code_cache_ptr_ - code_cache_begin_; + } + size_t CodeCacheRemain() const { + return code_cache_end_ - code_cache_ptr_; + } + size_t DataCacheSize() const { + return data_cache_ptr_ - data_cache_begin_; + } + size_t DataCacheRemain() const { + return data_cache_end_ - data_cache_ptr_; + } + size_t NumMethods() const { + return num_methods_; + } + + bool ContainsMethod(mirror::ArtMethod* method) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool ContainsCodePtr(const void* ptr) const; + + uint8_t* ReserveCode(Thread* self, size_t size) LOCKS_EXCLUDED(lock_); + + uint8_t* AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end) + LOCKS_EXCLUDED(lock_); + + // Get code for a method, returns null if it is not in the jit cache. + const void* GetCodeFor(mirror::ArtMethod* method) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_); + + void SaveCompiledCode(mirror::ArtMethod* method, const void* old_code_ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_); + + private: + // Takes ownership of code_mem_map. + explicit JitCodeCache(MemMap* code_mem_map); + void FlushInstructionCache(); + + Mutex lock_; + // Mem map which holds code and data. We do this since we need to have 32 bit offsets from method + // headers in code cache which point to things in the data cache. If the maps are more than 4GB + // apart, having multiple maps wouldn't work. + std::unique_ptr<MemMap> mem_map_; + // Code cache section. + uint8_t* code_cache_ptr_; + const uint8_t* code_cache_begin_; + const uint8_t* code_cache_end_; + // Data cache section. + uint8_t* data_cache_ptr_; + const uint8_t* data_cache_begin_; + const uint8_t* data_cache_end_; + size_t num_methods_; + // TODO: This relies on methods not moving. + // This map holds code for methods if they were deoptimized by the instrumentation stubs. This is + // required since we have to implement ClassLinker::GetQuickOatCodeFor for walking stacks. + SafeMap<mirror::ArtMethod*, const void*> method_code_map_; + + DISALLOW_COPY_AND_ASSIGN(JitCodeCache); +}; + + +} // namespace jit +} // namespace art + +#endif // ART_RUNTIME_JIT_JIT_CODE_CACHE_H_ diff --git a/runtime/jit/jit_instrumentation.cc b/runtime/jit/jit_instrumentation.cc new file mode 100644 index 0000000..160e678 --- /dev/null +++ b/runtime/jit/jit_instrumentation.cc @@ -0,0 +1,117 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jit_instrumentation.h" + +#include "jit.h" +#include "jit_code_cache.h" +#include "mirror/art_method-inl.h" +#include "scoped_thread_state_change.h" + +namespace art { +namespace jit { + +class JitCompileTask : public Task { + public: + explicit JitCompileTask(mirror::ArtMethod* method, JitInstrumentationCache* cache) + : method_(method), cache_(cache) { + } + + virtual void Run(Thread* self) OVERRIDE { + ScopedObjectAccess soa(self); + VLOG(jit) << "JitCompileTask compiling method " << PrettyMethod(method_); + if (Runtime::Current()->GetJit()->CompileMethod(method_, self)) { + cache_->SignalCompiled(self, method_); + } else { + VLOG(jit) << "Failed to compile method " << PrettyMethod(method_); + } + } + + virtual void Finalize() OVERRIDE { + delete this; + } + + private: + mirror::ArtMethod* const method_; + JitInstrumentationCache* const cache_; +}; + +JitInstrumentationCache::JitInstrumentationCache(size_t hot_method_threshold) + : lock_("jit instrumentation lock"), hot_method_threshold_(hot_method_threshold) { +} + +void JitInstrumentationCache::CreateThreadPool() { + thread_pool_.reset(new ThreadPool("Jit thread pool", 1)); +} + +void JitInstrumentationCache::DeleteThreadPool() { + thread_pool_.reset(); +} + +void JitInstrumentationCache::SignalCompiled(Thread* self, mirror::ArtMethod* method) { + ScopedObjectAccessUnchecked soa(self); + jmethodID method_id = soa.EncodeMethod(method); + MutexLock mu(self, lock_); + auto it = samples_.find(method_id); + if (it != samples_.end()) { + samples_.erase(it); + } +} + +void JitInstrumentationCache::AddSamples(Thread* self, mirror::ArtMethod* method, size_t count) { + ScopedObjectAccessUnchecked soa(self); + // Since we don't have on-stack replacement, some methods can remain in the interpreter longer + // than we want resulting in samples even after the method is compiled. + if (method->IsClassInitializer() || + Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method)) { + return; + } + jmethodID method_id = soa.EncodeMethod(method); + bool is_hot = false; + { + MutexLock mu(self, lock_); + size_t sample_count = 0; + auto it = samples_.find(method_id); + if (it != samples_.end()) { + it->second += count; + sample_count = it->second; + } else { + sample_count = count; + samples_.insert(std::make_pair(method_id, count)); + } + // If we have enough samples, mark as hot and request Jit compilation. + if (sample_count >= hot_method_threshold_ && sample_count - count < hot_method_threshold_) { + is_hot = true; + } + } + if (is_hot) { + if (thread_pool_.get() != nullptr) { + thread_pool_->AddTask(self, new JitCompileTask(method->GetInterfaceMethodIfProxy(), this)); + thread_pool_->StartWorkers(self); + } else { + VLOG(jit) << "Compiling hot method " << PrettyMethod(method); + Runtime::Current()->GetJit()->CompileMethod(method->GetInterfaceMethodIfProxy(), self); + } + } +} + +JitInstrumentationListener::JitInstrumentationListener(JitInstrumentationCache* cache) + : instrumentation_cache_(cache) { + CHECK(instrumentation_cache_ != nullptr); +} + +} // namespace jit +} // namespace art diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h new file mode 100644 index 0000000..9576f4b --- /dev/null +++ b/runtime/jit/jit_instrumentation.h @@ -0,0 +1,107 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_JIT_JIT_INSTRUMENTATION_H_ +#define ART_RUNTIME_JIT_JIT_INSTRUMENTATION_H_ + +#include <unordered_map> + +#include "instrumentation.h" + +#include "atomic.h" +#include "base/macros.h" +#include "base/mutex.h" +#include "gc_root.h" +#include "jni.h" +#include "object_callbacks.h" +#include "thread_pool.h" + +namespace art { +namespace mirror { + class ArtField; + class ArtMethod; + class Class; + class Object; + class Throwable; +} // namespace mirror +union JValue; +class Thread; +class ThrowLocation; + +namespace jit { + +// Keeps track of which methods are hot. +class JitInstrumentationCache { + public: + explicit JitInstrumentationCache(size_t hot_method_threshold); + void AddSamples(Thread* self, mirror::ArtMethod* method, size_t samples) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SignalCompiled(Thread* self, mirror::ArtMethod* method) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void CreateThreadPool(); + void DeleteThreadPool(); + + private: + Mutex lock_; + std::unordered_map<jmethodID, size_t> samples_; + size_t hot_method_threshold_; + std::unique_ptr<ThreadPool> thread_pool_; +}; + +class JitInstrumentationListener : public instrumentation::InstrumentationListener { + public: + explicit JitInstrumentationListener(JitInstrumentationCache* cache); + + virtual void MethodEntered(Thread* thread, mirror::Object* /*this_object*/, + mirror::ArtMethod* method, uint32_t /*dex_pc*/) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + instrumentation_cache_->AddSamples(thread, method, 1); + } + virtual void MethodExited(Thread* /*thread*/, mirror::Object* /*this_object*/, + mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/, + const JValue& /*return_value*/) + OVERRIDE { } + virtual void MethodUnwind(Thread* /*thread*/, mirror::Object* /*this_object*/, + mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/) OVERRIDE { } + virtual void FieldRead(Thread* /*thread*/, mirror::Object* /*this_object*/, + mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/, + mirror::ArtField* /*field*/) OVERRIDE { } + virtual void FieldWritten(Thread* /*thread*/, mirror::Object* /*this_object*/, + mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/, + mirror::ArtField* /*field*/, const JValue& /*field_value*/) + OVERRIDE { } + virtual void ExceptionCaught(Thread* /*thread*/, const ThrowLocation& /*throw_location*/, + mirror::ArtMethod* /*catch_method*/, uint32_t /*catch_dex_pc*/, + mirror::Throwable* /*exception_object*/) OVERRIDE { } + + virtual void DexPcMoved(Thread* /*self*/, mirror::Object* /*this_object*/, + mirror::ArtMethod* /*method*/, uint32_t /*new_dex_pc*/) OVERRIDE { } + + // We only care about how many dex instructions were executed in the Jit. + virtual void BackwardBranch(Thread* thread, mirror::ArtMethod* method, int32_t dex_pc_offset) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK_LE(dex_pc_offset, 0); + instrumentation_cache_->AddSamples(thread, method, 1); + } + + private: + JitInstrumentationCache* const instrumentation_cache_; +}; + +} // namespace jit +} // namespace art + +#endif // ART_RUNTIME_JIT_JIT_INSTRUMENTATION_H_ |