Jit-zygote: Postpone pre-compilation until boot is completed.
Compile only needed (hot) methods during boot.
This saves about 1.5s from jit-zygote boot time.
Test: device boots
Bug: 119800099
Change-Id: If98540e42634bf1e9701231e5174d724e897ce67
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 3eeb0fa..b596ea7 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -169,6 +169,7 @@
Jit::Jit(JitCodeCache* code_cache, JitOptions* options)
: code_cache_(code_cache),
options_(options),
+ boot_completed_lock_("Jit::boot_completed_lock_"),
cumulative_timings_("JIT timings"),
memory_use_("Memory used for compilation", 16),
lock_("JIT memory use lock") {}
@@ -702,7 +703,7 @@
dex_files_,
profile,
loader,
- /* add_to_queue= */ false);
+ /* add_to_queue= */ true);
}
void Finalize() override {
@@ -756,7 +757,8 @@
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
- bool add_to_queue) {
+ bool add_to_queue,
+ bool compile_after_boot) {
ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType(
method_idx, dex_cache, class_loader);
if (method == nullptr) {
@@ -778,8 +780,16 @@
"Lcom/android/internal/os/ZygoteServer;")) {
CompileMethod(method, self, /* baseline= */ false, /* osr= */ false, /* prejit= */ true);
} else {
- thread_pool_->AddTask(self,
- new JitCompileTask(method, JitCompileTask::TaskKind::kPreCompile));
+ Task* task = new JitCompileTask(method, JitCompileTask::TaskKind::kPreCompile);
+ if (compile_after_boot) {
+ MutexLock mu(Thread::Current(), boot_completed_lock_);
+ if (!boot_completed_) {
+ tasks_after_boot_.push_back(task);
+ return true;
+ }
+ DCHECK(tasks_after_boot_.empty());
+ }
+ thread_pool_->AddTask(self, task);
return true;
}
}
@@ -820,7 +830,8 @@
pair.second,
dex_caches[pair.first],
class_loader,
- add_to_queue)) {
+ add_to_queue,
+ /*compile_after_boot=*/false)) {
++added_to_queue;
}
}
@@ -893,7 +904,8 @@
method_idx,
dex_cache,
class_loader,
- add_to_queue)) {
+ add_to_queue,
+ /*compile_after_boot=*/true)) {
++added_to_queue;
}
}
@@ -1141,6 +1153,19 @@
thread_pool_->CreateThreads();
}
+void Jit::BootCompleted() {
+ Thread* self = Thread::Current();
+ std::deque<Task*> tasks;
+ {
+ MutexLock mu(self, boot_completed_lock_);
+ tasks = std::move(tasks_after_boot_);
+ boot_completed_ = true;
+ }
+ for (Task* task : tasks) {
+ thread_pool_->AddTask(self, task);
+ }
+}
+
bool Jit::CanEncodeMethod(ArtMethod* method, bool is_for_shared_region) const {
return !is_for_shared_region ||
Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(method->GetDeclaringClass());
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 1b57754..c264f7c 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -329,6 +329,9 @@
// Adjust state after forking.
void PostZygoteFork();
+ // Called when system finishes booting.
+ void BootCompleted();
+
// Compile methods from the given profile (.prof extension). If `add_to_queue`
// is true, methods in the profile are added to the JIT queue. Otherwise they are compiled
// directly.
@@ -375,7 +378,8 @@
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
- bool add_to_queue)
+ bool add_to_queue,
+ bool compile_after_boot)
REQUIRES_SHARED(Locks::mutator_lock_);
// Compile the method if the number of samples passes a threshold.
@@ -402,6 +406,10 @@
std::unique_ptr<ThreadPool> thread_pool_;
std::vector<std::unique_ptr<OatDexFile>> type_lookup_tables_;
+ Mutex boot_completed_lock_;
+ bool boot_completed_ GUARDED_BY(boot_completed_lock_) = false;
+ std::deque<Task*> tasks_after_boot_ GUARDED_BY(boot_completed_lock_);
+
// Performance monitoring.
CumulativeLogger cumulative_timings_;
Histogram<uint64_t> memory_use_ GUARDED_BY(lock_);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 410c229..ca41ae8 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -46,6 +46,7 @@
#include "gc/space/image_space.h"
#include "gc/task_processor.h"
#include "intern_table.h"
+#include "jit/jit.h"
#include "jni/java_vm_ext.h"
#include "jni/jni_internal.h"
#include "mirror/array-alloc-inl.h"
@@ -724,6 +725,14 @@
return Runtime::Current()->GetHeap()->HasBootImageSpace() ? JNI_TRUE : JNI_FALSE;
}
+static void VMRuntime_bootCompleted(JNIEnv* env ATTRIBUTE_UNUSED,
+ jclass klass ATTRIBUTE_UNUSED) {
+ jit::Jit* jit = Runtime::Current()->GetJit();
+ if (jit != nullptr) {
+ jit->BootCompleted();
+ }
+}
+
static JNINativeMethod gMethods[] = {
FAST_NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"),
NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
@@ -773,6 +782,7 @@
NATIVE_METHOD(VMRuntime, setDedupeHiddenApiWarnings, "(Z)V"),
NATIVE_METHOD(VMRuntime, setProcessPackageName, "(Ljava/lang/String;)V"),
NATIVE_METHOD(VMRuntime, setProcessDataDirectory, "(Ljava/lang/String;)V"),
+ NATIVE_METHOD(VMRuntime, bootCompleted, "()V"),
};
void register_dalvik_system_VMRuntime(JNIEnv* env) {