blob: d751e5aae91b35bd8f1582bf516753edf93b0c24 [file] [log] [blame]
Mathieu Chartiere5f13e52015-02-24 09:37:21 -08001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jit_instrumentation.h"
18
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "art_method-inl.h"
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080020#include "jit.h"
21#include "jit_code_cache.h"
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080022#include "scoped_thread_state_change.h"
Nicolas Geoffray629e9352015-11-04 17:22:16 +000023#include "thread_list.h"
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080024
25namespace art {
26namespace jit {
27
Andreas Gampe9e927f52016-02-29 20:49:38 -080028// At what priority to schedule jit threads. 9 is the lowest foreground priority on device.
29static constexpr int kJitPoolThreadPthreadPriority = 9;
30
Mathieu Chartier36c01362015-09-25 14:39:40 -070031class JitCompileTask FINAL : public Task {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080032 public:
Nicolas Geoffray26705e22015-10-28 12:50:11 +000033 enum TaskKind {
34 kAllocateProfile,
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000035 kCompile,
36 kCompileOsr
Nicolas Geoffray26705e22015-10-28 12:50:11 +000037 };
38
39 JitCompileTask(ArtMethod* method, TaskKind kind) : method_(method), kind_(kind) {
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -070040 ScopedObjectAccess soa(Thread::Current());
41 // Add a global ref to the class to prevent class unloading until compilation is done.
42 klass_ = soa.Vm()->AddGlobalRef(soa.Self(), method_->GetDeclaringClass());
43 CHECK(klass_ != nullptr);
44 }
45
46 ~JitCompileTask() {
47 ScopedObjectAccess soa(Thread::Current());
48 soa.Vm()->DeleteGlobalRef(soa.Self(), klass_);
49 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080050
Mathieu Chartier36c01362015-09-25 14:39:40 -070051 void Run(Thread* self) OVERRIDE {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080052 ScopedObjectAccess soa(self);
Nicolas Geoffray26705e22015-10-28 12:50:11 +000053 if (kind_ == kCompile) {
54 VLOG(jit) << "JitCompileTask compiling method " << PrettyMethod(method_);
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000055 if (!Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ false)) {
Nicolas Geoffray26705e22015-10-28 12:50:11 +000056 VLOG(jit) << "Failed to compile method " << PrettyMethod(method_);
57 }
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000058 } else if (kind_ == kCompileOsr) {
59 VLOG(jit) << "JitCompileTask compiling method osr " << PrettyMethod(method_);
60 if (!Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ true)) {
61 VLOG(jit) << "Failed to compile method osr " << PrettyMethod(method_);
62 }
Nicolas Geoffray26705e22015-10-28 12:50:11 +000063 } else {
64 DCHECK(kind_ == kAllocateProfile);
65 if (ProfilingInfo::Create(self, method_, /* retry_allocation */ true)) {
66 VLOG(jit) << "Start profiling " << PrettyMethod(method_);
67 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080068 }
69 }
70
Mathieu Chartier36c01362015-09-25 14:39:40 -070071 void Finalize() OVERRIDE {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080072 delete this;
73 }
74
75 private:
Mathieu Chartiere401d142015-04-22 13:56:20 -070076 ArtMethod* const method_;
Nicolas Geoffray26705e22015-10-28 12:50:11 +000077 const TaskKind kind_;
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -070078 jobject klass_;
Mathieu Chartier3130cdf2015-05-03 15:20:23 -070079
80 DISALLOW_IMPLICIT_CONSTRUCTORS(JitCompileTask);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080081};
82
Nicolas Geoffray5550ca82015-08-21 18:38:30 +010083JitInstrumentationCache::JitInstrumentationCache(size_t hot_method_threshold,
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000084 size_t warm_method_threshold,
85 size_t osr_method_threshold)
Nicolas Geoffray5550ca82015-08-21 18:38:30 +010086 : hot_method_threshold_(hot_method_threshold),
Nicolas Geoffray629e9352015-11-04 17:22:16 +000087 warm_method_threshold_(warm_method_threshold),
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +000088 osr_method_threshold_(osr_method_threshold),
Nicolas Geoffray629e9352015-11-04 17:22:16 +000089 listener_(this) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080090}
91
92void JitInstrumentationCache::CreateThreadPool() {
Nicolas Geoffray629e9352015-11-04 17:22:16 +000093 // Create the thread pool before setting the instrumentation, so that
94 // when the threads stopped being suspended, they can use it directly.
95 // There is a DCHECK in the 'AddSamples' method to ensure the tread pool
96 // is not null when we instrument.
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080097 thread_pool_.reset(new ThreadPool("Jit thread pool", 1));
Andreas Gampe9e927f52016-02-29 20:49:38 -080098 thread_pool_->SetPthreadPriority(kJitPoolThreadPthreadPriority);
Nicolas Geoffray629e9352015-11-04 17:22:16 +000099 thread_pool_->StartWorkers(Thread::Current());
100 {
101 // Add Jit interpreter instrumentation, tells the interpreter when
102 // to notify the jit to compile something.
103 ScopedSuspendAll ssa(__FUNCTION__);
104 Runtime::Current()->GetInstrumentation()->AddListener(
105 &listener_, JitInstrumentationListener::kJitEvents);
106 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800107}
108
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000109void JitInstrumentationCache::DeleteThreadPool(Thread* self) {
110 DCHECK(Runtime::Current()->IsShuttingDown(self));
111 if (thread_pool_ != nullptr) {
112 // First remove the listener, to avoid having mutators enter
113 // 'AddSamples'.
114 ThreadPool* cache = nullptr;
115 {
116 ScopedSuspendAll ssa(__FUNCTION__);
117 Runtime::Current()->GetInstrumentation()->RemoveListener(
118 &listener_, JitInstrumentationListener::kJitEvents);
119 // Clear thread_pool_ field while the threads are suspended.
120 // A mutator in the 'AddSamples' method will check against it.
121 cache = thread_pool_.release();
122 }
123 cache->StopWorkers(self);
124 cache->RemoveAllTasks(self);
125 // We could just suspend all threads, but we know those threads
126 // will finish in a short period, so it's not worth adding a suspend logic
127 // here. Besides, this is only done for shutdown.
128 cache->Wait(self, false, false);
129 delete cache;
130 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800131}
132
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100133void JitInstrumentationCache::AddSamples(Thread* self, ArtMethod* method, size_t) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800134 // Since we don't have on-stack replacement, some methods can remain in the interpreter longer
135 // than we want resulting in samples even after the method is compiled.
Nicolas Geoffray1dad3f62015-10-23 14:59:54 +0100136 if (method->IsClassInitializer() || method->IsNative()) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800137 return;
138 }
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000139 DCHECK(thread_pool_ != nullptr);
140
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100141 uint16_t sample_count = method->IncrementCounter();
142 if (sample_count == warm_method_threshold_) {
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000143 bool success = ProfilingInfo::Create(self, method, /* retry_allocation */ false);
144 if (success) {
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100145 VLOG(jit) << "Start profiling " << PrettyMethod(method);
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000146 }
147
148 if (thread_pool_ == nullptr) {
149 // Calling ProfilingInfo::Create might put us in a suspended state, which could
150 // lead to the thread pool being deleted when we are shutting down.
151 DCHECK(Runtime::Current()->IsShuttingDown(self));
152 return;
153 }
154
155 if (!success) {
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000156 // We failed allocating. Instead of doing the collection on the Java thread, we push
157 // an allocation to a compiler thread, that will do the collection.
Nicolas Geoffray22cf3d32015-11-02 11:57:11 +0000158 thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kAllocateProfile));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800159 }
160 }
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000161
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100162 if (sample_count == hot_method_threshold_) {
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000163 DCHECK(thread_pool_ != nullptr);
Nicolas Geoffray22cf3d32015-11-02 11:57:11 +0000164 thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800165 }
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000166
167 if (sample_count == osr_method_threshold_) {
168 DCHECK(thread_pool_ != nullptr);
169 thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr));
170 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800171}
172
173JitInstrumentationListener::JitInstrumentationListener(JitInstrumentationCache* cache)
174 : instrumentation_cache_(cache) {
175 CHECK(instrumentation_cache_ != nullptr);
176}
177
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000178void JitInstrumentationListener::MethodEntered(Thread* thread,
179 mirror::Object* /*this_object*/,
180 ArtMethod* method,
181 uint32_t /*dex_pc*/) {
Siva Chandra05d24152016-01-05 17:43:17 -0800182 if (UNLIKELY(Runtime::Current()->GetJit()->JitAtFirstUse())) {
183 // The compiler requires a ProfilingInfo object.
184 ProfilingInfo::Create(thread, method, /* retry_allocation */ true);
185 JitCompileTask compile_task(method, JitCompileTask::kCompile);
186 compile_task.Run(thread);
187 return;
188 }
189
Nicolas Geoffray35122442016-03-02 12:05:30 +0000190 ProfilingInfo* profiling_info = method->GetProfilingInfo(sizeof(void*));
191 // Update the entrypoint if the ProfilingInfo has one. The interpreter will call it
192 // instead of interpreting the method.
193 // We avoid doing this if exit stubs are installed to not mess with the instrumentation.
194 // TODO(ngeoffray): Clean up instrumentation and code cache interactions.
195 if ((profiling_info != nullptr) &&
196 (profiling_info->GetSavedEntryPoint() != nullptr) &&
197 !Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {
198 method->SetEntryPointFromQuickCompiledCode(profiling_info->GetSavedEntryPoint());
199 } else {
200 instrumentation_cache_->AddSamples(thread, method, 1);
201 }
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000202}
203
Nicolas Geoffray81f0f952016-01-20 16:25:19 +0000204void JitInstrumentationListener::Branch(Thread* thread,
205 ArtMethod* method,
Nicolas Geoffraycf226582016-01-21 15:47:37 +0000206 uint32_t dex_pc ATTRIBUTE_UNUSED,
Nicolas Geoffray81f0f952016-01-20 16:25:19 +0000207 int32_t dex_pc_offset) {
208 if (dex_pc_offset < 0) {
209 // Increment method hotness if it is a backward branch.
210 instrumentation_cache_->AddSamples(thread, method, 1);
211 }
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000212}
213
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100214void JitInstrumentationListener::InvokeVirtualOrInterface(Thread* thread,
215 mirror::Object* this_object,
216 ArtMethod* caller,
217 uint32_t dex_pc,
218 ArtMethod* callee ATTRIBUTE_UNUSED) {
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000219 // We make sure we cannot be suspended, as the profiling info can be concurrently deleted.
Mathieu Chartier3fdb3fe2016-01-14 10:24:28 -0800220 instrumentation_cache_->AddSamples(thread, caller, 1);
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100221 DCHECK(this_object != nullptr);
Mathieu Chartier1147b9b2015-09-14 18:50:08 -0700222 ProfilingInfo* info = caller->GetProfilingInfo(sizeof(void*));
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100223 if (info != nullptr) {
Mathieu Chartier9ccf0512015-10-02 13:08:39 -0700224 // Since the instrumentation is marked from the declaring class we need to mark the card so
225 // that mod-union tables and card rescanning know about the update.
226 Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(caller->GetDeclaringClass());
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000227 info->AddInvokeInfo(dex_pc, this_object->GetClass());
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100228 }
229}
230
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -0700231void JitInstrumentationCache::WaitForCompilationToFinish(Thread* self) {
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000232 if (thread_pool_ != nullptr) {
233 thread_pool_->Wait(self, false, false);
234 }
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -0700235}
236
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800237} // namespace jit
238} // namespace art