blob: 0e738124f70bc2bb7cb3ede9e7a1b1dc04f491bd [file] [log] [blame]
Dave Allison0aded082013-11-07 13:15:11 -08001/*
2 * Copyright (C) 2011 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 "profiler.h"
18
19#include <sys/uio.h>
20
21#include "base/stl_util.h"
22#include "base/unix_file/fd_file.h"
23#include "class_linker.h"
24#include "common_throws.h"
25#include "debugger.h"
26#include "dex_file-inl.h"
27#include "instrumentation.h"
28#include "mirror/art_method-inl.h"
29#include "mirror/class-inl.h"
30#include "mirror/dex_cache.h"
31#include "mirror/object_array-inl.h"
32#include "mirror/object-inl.h"
33#include "object_utils.h"
34#include "os.h"
35#include "scoped_thread_state_change.h"
36#include "ScopedLocalRef.h"
37#include "thread.h"
38#include "thread_list.h"
39#if !defined(ART_USE_PORTABLE_COMPILER)
40#include "entrypoints/quick/quick_entrypoints.h"
41#endif
42
43namespace art {
44
45BackgroundMethodSamplingProfiler* BackgroundMethodSamplingProfiler::profiler_ = nullptr;
46pthread_t BackgroundMethodSamplingProfiler::profiler_pthread_ = 0U;
47volatile bool BackgroundMethodSamplingProfiler::shutting_down_ = false;
48
49
50// TODO: this profiler runs regardless of the state of the machine. Maybe we should use the
51// wakelock or something to modify the run characteristics. This can be done when we
52// have some performance data after it's been used for a while.
53
54
55// This is called from either a thread list traversal or from a checkpoint. Regardless
56// of which caller, the mutator lock must be held.
57static void GetSample(Thread* thread, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
58 BackgroundMethodSamplingProfiler* profiler =
59 reinterpret_cast<BackgroundMethodSamplingProfiler*>(arg);
60 mirror::ArtMethod* method = thread->GetCurrentMethod(nullptr);
61 if (false && method == nullptr) {
62 LOG(INFO) << "No current method available";
63 std::ostringstream os;
64 thread->Dump(os);
65 std::string data(os.str());
66 LOG(INFO) << data;
67 }
68 profiler->RecordMethod(method);
69}
70
71
72
73// A closure that is called by the thread checkpoint code.
74class SampleCheckpoint : public Closure {
75 public:
76 explicit SampleCheckpoint(BackgroundMethodSamplingProfiler* const profiler) :
77 profiler_(profiler) {}
78
79 virtual void Run(Thread* thread) NO_THREAD_SAFETY_ANALYSIS {
80 Thread* self = Thread::Current();
81 if (thread == nullptr) {
82 LOG(ERROR) << "Checkpoint with nullptr thread";
83 return;
84 }
85
86 // Grab the mutator lock (shared access).
87 ScopedObjectAccess soa(self);
88
89 // Grab a sample.
90 GetSample(thread, this->profiler_);
91
92 // And finally tell the barrier that we're done.
93 this->profiler_->GetBarrier().Pass(self);
94 }
95
96 private:
97 BackgroundMethodSamplingProfiler* const profiler_;
98};
99
100bool BackgroundMethodSamplingProfiler::ShuttingDown(Thread* self) {
101 MutexLock mu(self, *Locks::profiler_lock_);
102 return shutting_down_;
103}
104
105void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
106 Runtime* runtime = Runtime::Current();
107 BackgroundMethodSamplingProfiler* profiler =
108 reinterpret_cast<BackgroundMethodSamplingProfiler*>(arg);
109
110 // Add a random delay for the first time run so that we don't hammer the CPU
111 // with all profiles running at the same time.
112 const int kRandomDelayMaxSecs = 30;
113 const double kMaxBackoffSecs = 24*60*60; // Max backoff time.
114
115 srand(MicroTime() * getpid());
116 int startup_delay = rand() % kRandomDelayMaxSecs; // random delay for startup.
117
118
119 CHECK(runtime->AttachCurrentThread("Profiler", true, runtime->GetSystemThreadGroup(),
120 !runtime->IsCompiler()));
121
122 Thread* self = Thread::Current();
123
124 while (true) {
125 if (ShuttingDown(self)) {
126 break;
127 }
128
129 {
130 // wait until we need to run another profile
131 uint64_t delay_secs = profiler->period_s_ * profiler->backoff_factor_;
132
133 // Add a startup delay to prevent all the profiles running at once.
134 delay_secs += startup_delay;
135
136 // Immediate startup for benchmarking?
137 if (profiler->start_immediately_ && startup_delay > 0) {
138 delay_secs = 0;
139 }
140
141 startup_delay = 0;
142
143 LOG(DEBUG) << "Delaying profile start for " << delay_secs << " secs";
144 MutexLock mu(self, profiler->wait_lock_);
145 profiler->period_condition_.TimedWait(self, delay_secs * 1000, 0);
146
147 // Expand the backoff by its coefficient, but don't go beyond the max.
148 double new_backoff = profiler->backoff_factor_ * profiler->backoff_coefficient_;
149 if (new_backoff < kMaxBackoffSecs) {
150 profiler->backoff_factor_ = new_backoff;
151 }
152 }
153
154 if (ShuttingDown(self)) {
155 break;
156 }
157
158
159 uint64_t start_us = MicroTime();
160 uint64_t end_us = start_us + profiler->duration_s_ * 1000000LL;
161 uint64_t now_us = start_us;
162
163 LOG(DEBUG) << "Starting profiling run now for " << PrettyDuration((end_us - start_us) * 1000);
164
165
166 SampleCheckpoint check_point(profiler);
167
168 while (now_us < end_us) {
169 if (ShuttingDown(self)) {
170 break;
171 }
172
173 usleep(profiler->interval_us_); // Non-interruptible sleep.
174
175 ThreadList* thread_list = runtime->GetThreadList();
176
177 profiler->profiler_barrier_->Init(self, 0);
178 size_t barrier_count = thread_list->RunCheckpoint(&check_point);
179
180 ThreadState old_state = self->SetState(kWaitingForCheckPointsToRun);
181
182 // Wait for the barrier to be crossed by all runnable threads. This wait
183 // is done with a timeout so that we can detect problems with the checkpoint
184 // running code. We should never see this.
185 const uint32_t kWaitTimeoutMs = 10000;
186 const uint32_t kWaitTimeoutUs = kWaitTimeoutMs * 1000;
187
188 uint64_t waitstart_us = MicroTime();
189 // Wait for all threads to pass the barrier.
190 profiler->profiler_barrier_->Increment(self, barrier_count, kWaitTimeoutMs);
191 uint64_t waitend_us = MicroTime();
192 uint64_t waitdiff_us = waitend_us - waitstart_us;
193
194 // We should never get a timeout. If we do, it suggests a problem with the checkpoint
195 // code. Crash the process in this case.
196 CHECK_LT(waitdiff_us, kWaitTimeoutUs);
197
198 self->SetState(old_state);
199
200 // Update the current time.
201 now_us = MicroTime();
202 }
203
204 if (!ShuttingDown(self)) {
205 // After the profile has been taken, write it out.
206 ScopedObjectAccess soa(self); // Acquire the mutator lock.
207 uint32_t size = profiler->WriteProfile();
208 LOG(DEBUG) << "Profile size: " << size;
209 }
210 }
211
212 LOG(INFO) << "Profiler shutdown";
213 runtime->DetachCurrentThread();
214 return nullptr;
215}
216
217// Write out the profile file if we are generating a profile.
218uint32_t BackgroundMethodSamplingProfiler::WriteProfile() {
219 UniquePtr<File> profile_file;
220 Runtime* runtime = Runtime::Current();
221 std::string classpath = runtime->GetClassPathString();
222 size_t colon = classpath.find(':');
223 if (colon != std::string::npos) {
224 // More than one file in the classpath. Possible?
225 classpath = classpath.substr(0, colon);
226 }
227
228 std::replace(classpath.begin(), classpath.end(), '/', '@');
229 std::string full_name = profile_file_name_;
230 if (classpath != "") {
231 full_name = StringPrintf("%s-%s", profile_file_name_.c_str(), classpath.c_str());
232 }
233 LOG(DEBUG) << "Saving profile to " << full_name;
234
235 profile_file.reset(OS::CreateEmptyFile(full_name.c_str()));
236 if (profile_file.get() == nullptr) {
237 // Failed to open the profile file, ignore.
238 LOG(INFO) << "Failed to op file";
239 return 0;
240 }
241 std::ostringstream os;
242 uint32_t num_methods = DumpProfile(os);
243 std::string data(os.str());
244 profile_file->WriteFully(data.c_str(), data.length());
245 profile_file->Close();
246 return num_methods;
247}
248
249// Start a profile thread with the user-supplied arguments.
250void BackgroundMethodSamplingProfiler::Start(int period, int duration,
251 std::string profile_file_name, int interval_us,
252 double backoff_coefficient, bool startImmediately) {
253 Thread* self = Thread::Current();
254 {
255 MutexLock mu(self, *Locks::profiler_lock_);
256 // Don't start two profiler threads.
257 if (profiler_ != nullptr) {
258 return;
259 }
260 }
261
262 LOG(INFO) << "Starting profile with period " << period << "s, duration " << duration <<
263 "s, interval " << interval_us << "us. Profile file " << profile_file_name;
264
265 {
266 MutexLock mu(self, *Locks::profiler_lock_);
267 profiler_ = new BackgroundMethodSamplingProfiler(period, duration, profile_file_name,
268 backoff_coefficient,
269 interval_us, startImmediately);
270
271 CHECK_PTHREAD_CALL(pthread_create, (&profiler_pthread_, nullptr, &RunProfilerThread,
272 reinterpret_cast<void*>(profiler_)),
273 "Profiler thread");
274 }
275}
276
277
278
279void BackgroundMethodSamplingProfiler::Stop() {
280 BackgroundMethodSamplingProfiler* profiler = nullptr;
281 pthread_t profiler_pthread = 0U;
282 {
283 MutexLock trace_mu(Thread::Current(), *Locks::profiler_lock_);
284 profiler = profiler_;
285 shutting_down_ = true;
286 profiler_pthread = profiler_pthread_;
287 }
288
289 // Now wake up the sampler thread if it sleeping.
290 {
291 MutexLock profile_mu(Thread::Current(), profiler->wait_lock_);
292 profiler->period_condition_.Signal(Thread::Current());
293 }
294 // Wait for the sample thread to stop.
295 CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profiler thread shutdown");
296
297 {
298 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
299 profiler_ = nullptr;
300 }
301 delete profiler;
302}
303
304
305void BackgroundMethodSamplingProfiler::Shutdown() {
306 Stop();
307}
308
309BackgroundMethodSamplingProfiler::BackgroundMethodSamplingProfiler(int period, int duration,
310 std::string profile_file_name,
311 double backoff_coefficient, int interval_us, bool startImmediately)
312 : profile_file_name_(profile_file_name),
313 period_s_(period), start_immediately_(startImmediately),
314 interval_us_(interval_us), backoff_factor_(1.0),
315 backoff_coefficient_(backoff_coefficient), duration_s_(duration),
316 wait_lock_("Profile wait lock"),
317 period_condition_("Profile condition", wait_lock_),
318 profile_table_(wait_lock_),
319 profiler_barrier_(new Barrier(0)) {
320 // Populate the filtered_methods set.
321 // This is empty right now, but to add a method, do this:
322 //
323 // filtered_methods_.insert("void java.lang.Object.wait(long, int)");
324}
325
326// A method has been hit, record its invocation in the method map.
327// The mutator_lock must be held (shared) when this is called.
328void BackgroundMethodSamplingProfiler::RecordMethod(mirror::ArtMethod* method) {
329 if (method == nullptr) {
330 profile_table_.NullMethod();
331 // Don't record a nullptr method.
332 return;
333 }
334
335 mirror::Class* cls = method->GetDeclaringClass();
336 if (cls != nullptr) {
337 if (cls->GetClassLoader() == nullptr) {
338 // Don't include things in the boot
339 profile_table_.BootMethod();
340 return;
341 }
342 }
343
344 bool is_filtered = false;
345
346 MethodHelper mh(method);
347 if (strcmp(mh.GetName(), "<clinit>") == 0) {
348 // always filter out class init
349 is_filtered = true;
350 }
351
352 // Filter out methods by name if there are any.
353 if (!is_filtered && filtered_methods_.size() > 0) {
354 std::string method_full_name = PrettyMethod(method);
355
356 // Don't include specific filtered methods.
357 is_filtered = filtered_methods_.count(method_full_name) != 0;
358 }
359
360 // Add to the profile table unless it is filtered out.
361 if (!is_filtered) {
362 profile_table_.Put(method);
363 }
364}
365
366// Clean out any recordings for the method traces.
367void BackgroundMethodSamplingProfiler::CleanProfile() {
368 profile_table_.Clear();
369}
370
371uint32_t BackgroundMethodSamplingProfiler::DumpProfile(std::ostream& os) {
372 return profile_table_.Write(os);
373}
374
375// Profile Table.
376// This holds a mapping of mirror::ArtMethod* to a count of how many times a sample
377// hit it at the top of the stack.
378ProfileSampleResults::ProfileSampleResults(Mutex& lock) : lock_(lock), num_samples_(0),
379 num_null_methods_(0),
380 num_boot_methods_(0) {
381 for (int i = 0; i < kHashSize; i++) {
382 table[i] = nullptr;
383 }
384}
385
386ProfileSampleResults::~ProfileSampleResults() {
387 for (int i = 0; i < kHashSize; i++) {
388 delete table[i];
389 }
390}
391
392// Add a method to the profile table. If it the first time the method
393// has been seen, add it with count=1, otherwise increment the count.
394void ProfileSampleResults::Put(mirror::ArtMethod* method) {
395 lock_.Lock(Thread::Current());
396 uint32_t index = Hash(method);
397 if (table[index] == nullptr) {
398 table[index] = new Map();
399 }
400 Map::iterator i = table[index]->find(method);
401 if (i == table[index]->end()) {
402 (*table[index])[method] = 1;
403 } else {
404 i->second++;
405 }
406 num_samples_++;
407 lock_.Unlock(Thread::Current());
408}
409
410// Write the profile table to the output stream.
411uint32_t ProfileSampleResults::Write(std::ostream &os) {
412 ScopedObjectAccess soa(Thread::Current());
413 LOG(DEBUG) << "Profile: " << num_samples_ << "/" << num_null_methods_ << "/" << num_boot_methods_;
414 os << num_samples_ << "/" << num_null_methods_ << "/" << num_boot_methods_ << "\n";
415 uint32_t num_methods = 0;
416 for (int i = 0 ; i < kHashSize; i++) {
417 Map *map = table[i];
418 if (map != nullptr) {
419 for (const auto &meth_iter : *map) {
420 mirror::ArtMethod *method = meth_iter.first;
421 std::string method_name = PrettyMethod(method);
422 uint32_t method_size = method->GetCodeSize();
423 os << StringPrintf("%s/%u/%u\n", method_name.c_str(), meth_iter.second, method_size);
424 ++num_methods;
425 }
426 }
427 }
428 return num_methods;
429}
430
431void ProfileSampleResults::Clear() {
432 num_samples_ = 0;
433 num_null_methods_ = 0;
434 num_boot_methods_ = 0;
435 for (int i = 0; i < kHashSize; i++) {
436 delete table[i];
437 table[i] = nullptr;
438 }
439}
440
441uint32_t ProfileSampleResults::Hash(mirror::ArtMethod* method) {
442 uint32_t value = reinterpret_cast<uint32_t>(method);
443 value >>= 2;
444 return value % kHashSize;
445}
446
447} // namespace art
448