blob: 4cbaf2cbfaf1a9f29b0b8d0518d516af56464995 [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
Mathieu Chartier36c01362015-09-25 14:39:40 -070028class JitCompileTask FINAL : public Task {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080029 public:
Nicolas Geoffray26705e22015-10-28 12:50:11 +000030 enum TaskKind {
31 kAllocateProfile,
32 kCompile
33 };
34
35 JitCompileTask(ArtMethod* method, TaskKind kind) : method_(method), kind_(kind) {
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -070036 ScopedObjectAccess soa(Thread::Current());
37 // Add a global ref to the class to prevent class unloading until compilation is done.
38 klass_ = soa.Vm()->AddGlobalRef(soa.Self(), method_->GetDeclaringClass());
39 CHECK(klass_ != nullptr);
40 }
41
42 ~JitCompileTask() {
43 ScopedObjectAccess soa(Thread::Current());
44 soa.Vm()->DeleteGlobalRef(soa.Self(), klass_);
45 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080046
Mathieu Chartier36c01362015-09-25 14:39:40 -070047 void Run(Thread* self) OVERRIDE {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080048 ScopedObjectAccess soa(self);
Nicolas Geoffray26705e22015-10-28 12:50:11 +000049 if (kind_ == kCompile) {
50 VLOG(jit) << "JitCompileTask compiling method " << PrettyMethod(method_);
51 if (!Runtime::Current()->GetJit()->CompileMethod(method_, self)) {
52 VLOG(jit) << "Failed to compile method " << PrettyMethod(method_);
53 }
54 } else {
55 DCHECK(kind_ == kAllocateProfile);
56 if (ProfilingInfo::Create(self, method_, /* retry_allocation */ true)) {
57 VLOG(jit) << "Start profiling " << PrettyMethod(method_);
58 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080059 }
60 }
61
Mathieu Chartier36c01362015-09-25 14:39:40 -070062 void Finalize() OVERRIDE {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080063 delete this;
64 }
65
66 private:
Mathieu Chartiere401d142015-04-22 13:56:20 -070067 ArtMethod* const method_;
Nicolas Geoffray26705e22015-10-28 12:50:11 +000068 const TaskKind kind_;
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -070069 jobject klass_;
Mathieu Chartier3130cdf2015-05-03 15:20:23 -070070
71 DISALLOW_IMPLICIT_CONSTRUCTORS(JitCompileTask);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080072};
73
Nicolas Geoffray5550ca82015-08-21 18:38:30 +010074JitInstrumentationCache::JitInstrumentationCache(size_t hot_method_threshold,
75 size_t warm_method_threshold)
76 : hot_method_threshold_(hot_method_threshold),
Nicolas Geoffray629e9352015-11-04 17:22:16 +000077 warm_method_threshold_(warm_method_threshold),
78 listener_(this) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080079}
80
81void JitInstrumentationCache::CreateThreadPool() {
Nicolas Geoffray629e9352015-11-04 17:22:16 +000082 // Create the thread pool before setting the instrumentation, so that
83 // when the threads stopped being suspended, they can use it directly.
84 // There is a DCHECK in the 'AddSamples' method to ensure the tread pool
85 // is not null when we instrument.
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080086 thread_pool_.reset(new ThreadPool("Jit thread pool", 1));
Nicolas Geoffray629e9352015-11-04 17:22:16 +000087 thread_pool_->StartWorkers(Thread::Current());
88 {
89 // Add Jit interpreter instrumentation, tells the interpreter when
90 // to notify the jit to compile something.
91 ScopedSuspendAll ssa(__FUNCTION__);
92 Runtime::Current()->GetInstrumentation()->AddListener(
93 &listener_, JitInstrumentationListener::kJitEvents);
94 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080095}
96
Nicolas Geoffray629e9352015-11-04 17:22:16 +000097void JitInstrumentationCache::DeleteThreadPool(Thread* self) {
98 DCHECK(Runtime::Current()->IsShuttingDown(self));
99 if (thread_pool_ != nullptr) {
100 // First remove the listener, to avoid having mutators enter
101 // 'AddSamples'.
102 ThreadPool* cache = nullptr;
103 {
104 ScopedSuspendAll ssa(__FUNCTION__);
105 Runtime::Current()->GetInstrumentation()->RemoveListener(
106 &listener_, JitInstrumentationListener::kJitEvents);
107 // Clear thread_pool_ field while the threads are suspended.
108 // A mutator in the 'AddSamples' method will check against it.
109 cache = thread_pool_.release();
110 }
111 cache->StopWorkers(self);
112 cache->RemoveAllTasks(self);
113 // We could just suspend all threads, but we know those threads
114 // will finish in a short period, so it's not worth adding a suspend logic
115 // here. Besides, this is only done for shutdown.
116 cache->Wait(self, false, false);
117 delete cache;
118 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800119}
120
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100121void JitInstrumentationCache::AddSamples(Thread* self, ArtMethod* method, size_t) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800122 // Since we don't have on-stack replacement, some methods can remain in the interpreter longer
123 // than we want resulting in samples even after the method is compiled.
Nicolas Geoffray1dad3f62015-10-23 14:59:54 +0100124 if (method->IsClassInitializer() || method->IsNative()) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800125 return;
126 }
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000127 DCHECK(thread_pool_ != nullptr);
128
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100129 uint16_t sample_count = method->IncrementCounter();
130 if (sample_count == warm_method_threshold_) {
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000131 bool success = ProfilingInfo::Create(self, method, /* retry_allocation */ false);
132 if (success) {
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100133 VLOG(jit) << "Start profiling " << PrettyMethod(method);
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000134 }
135
136 if (thread_pool_ == nullptr) {
137 // Calling ProfilingInfo::Create might put us in a suspended state, which could
138 // lead to the thread pool being deleted when we are shutting down.
139 DCHECK(Runtime::Current()->IsShuttingDown(self));
140 return;
141 }
142
143 if (!success) {
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000144 // We failed allocating. Instead of doing the collection on the Java thread, we push
145 // an allocation to a compiler thread, that will do the collection.
Nicolas Geoffray22cf3d32015-11-02 11:57:11 +0000146 thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kAllocateProfile));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800147 }
148 }
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000149
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100150 if (sample_count == hot_method_threshold_) {
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000151 DCHECK(thread_pool_ != nullptr);
Nicolas Geoffray22cf3d32015-11-02 11:57:11 +0000152 thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800153 }
154}
155
156JitInstrumentationListener::JitInstrumentationListener(JitInstrumentationCache* cache)
157 : instrumentation_cache_(cache) {
158 CHECK(instrumentation_cache_ != nullptr);
159}
160
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000161void JitInstrumentationListener::MethodEntered(Thread* thread,
162 mirror::Object* /*this_object*/,
163 ArtMethod* method,
164 uint32_t /*dex_pc*/) {
165 instrumentation_cache_->AddSamples(thread, method, 1);
166}
167
168void JitInstrumentationListener::BackwardBranch(Thread* thread,
169 ArtMethod* method,
170 int32_t dex_pc_offset) {
171 CHECK_LE(dex_pc_offset, 0);
172 instrumentation_cache_->AddSamples(thread, method, 1);
173}
174
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100175void JitInstrumentationListener::InvokeVirtualOrInterface(Thread* thread,
176 mirror::Object* this_object,
177 ArtMethod* caller,
178 uint32_t dex_pc,
179 ArtMethod* callee ATTRIBUTE_UNUSED) {
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000180 // We make sure we cannot be suspended, as the profiling info can be concurrently deleted.
Mathieu Chartier3fdb3fe2016-01-14 10:24:28 -0800181 instrumentation_cache_->AddSamples(thread, caller, 1);
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100182 DCHECK(this_object != nullptr);
Mathieu Chartier1147b9b2015-09-14 18:50:08 -0700183 ProfilingInfo* info = caller->GetProfilingInfo(sizeof(void*));
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100184 if (info != nullptr) {
Mathieu Chartier9ccf0512015-10-02 13:08:39 -0700185 // Since the instrumentation is marked from the declaring class we need to mark the card so
186 // that mod-union tables and card rescanning know about the update.
187 Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(caller->GetDeclaringClass());
Nicolas Geoffray26705e22015-10-28 12:50:11 +0000188 info->AddInvokeInfo(dex_pc, this_object->GetClass());
Nicolas Geoffray5550ca82015-08-21 18:38:30 +0100189 }
190}
191
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -0700192void JitInstrumentationCache::WaitForCompilationToFinish(Thread* self) {
Nicolas Geoffray629e9352015-11-04 17:22:16 +0000193 if (thread_pool_ != nullptr) {
194 thread_pool_->Wait(self, false, false);
195 }
Mathieu Chartiera50f9cf2015-09-25 11:34:45 -0700196}
197
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800198} // namespace jit
199} // namespace art