blob: da989381eb0dbec76c9f1027bc2db3f054943d42 [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>
Dave Allison39c3bfb2014-01-28 18:33:52 -080020#include <sys/file.h>
Dave Allison0aded082013-11-07 13:15:11 -080021
22#include "base/stl_util.h"
23#include "base/unix_file/fd_file.h"
24#include "class_linker.h"
25#include "common_throws.h"
26#include "debugger.h"
27#include "dex_file-inl.h"
28#include "instrumentation.h"
29#include "mirror/art_method-inl.h"
30#include "mirror/class-inl.h"
31#include "mirror/dex_cache.h"
32#include "mirror/object_array-inl.h"
33#include "mirror/object-inl.h"
34#include "object_utils.h"
35#include "os.h"
36#include "scoped_thread_state_change.h"
37#include "ScopedLocalRef.h"
38#include "thread.h"
39#include "thread_list.h"
Dave Allison4a7867b2014-01-30 17:44:12 -080040
41#ifdef HAVE_ANDROID_OS
42#include "cutils/properties.h"
43#endif
44
Dave Allison0aded082013-11-07 13:15:11 -080045#if !defined(ART_USE_PORTABLE_COMPILER)
46#include "entrypoints/quick/quick_entrypoints.h"
47#endif
48
49namespace art {
50
51BackgroundMethodSamplingProfiler* BackgroundMethodSamplingProfiler::profiler_ = nullptr;
52pthread_t BackgroundMethodSamplingProfiler::profiler_pthread_ = 0U;
53volatile bool BackgroundMethodSamplingProfiler::shutting_down_ = false;
54
55
56// TODO: this profiler runs regardless of the state of the machine. Maybe we should use the
57// wakelock or something to modify the run characteristics. This can be done when we
58// have some performance data after it's been used for a while.
59
60
61// This is called from either a thread list traversal or from a checkpoint. Regardless
62// of which caller, the mutator lock must be held.
63static void GetSample(Thread* thread, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
64 BackgroundMethodSamplingProfiler* profiler =
65 reinterpret_cast<BackgroundMethodSamplingProfiler*>(arg);
66 mirror::ArtMethod* method = thread->GetCurrentMethod(nullptr);
67 if (false && method == nullptr) {
68 LOG(INFO) << "No current method available";
69 std::ostringstream os;
70 thread->Dump(os);
71 std::string data(os.str());
72 LOG(INFO) << data;
73 }
74 profiler->RecordMethod(method);
75}
76
77
78
79// A closure that is called by the thread checkpoint code.
80class SampleCheckpoint : public Closure {
81 public:
82 explicit SampleCheckpoint(BackgroundMethodSamplingProfiler* const profiler) :
83 profiler_(profiler) {}
84
85 virtual void Run(Thread* thread) NO_THREAD_SAFETY_ANALYSIS {
86 Thread* self = Thread::Current();
87 if (thread == nullptr) {
88 LOG(ERROR) << "Checkpoint with nullptr thread";
89 return;
90 }
91
92 // Grab the mutator lock (shared access).
93 ScopedObjectAccess soa(self);
94
95 // Grab a sample.
96 GetSample(thread, this->profiler_);
97
98 // And finally tell the barrier that we're done.
99 this->profiler_->GetBarrier().Pass(self);
100 }
101
102 private:
103 BackgroundMethodSamplingProfiler* const profiler_;
104};
105
106bool BackgroundMethodSamplingProfiler::ShuttingDown(Thread* self) {
107 MutexLock mu(self, *Locks::profiler_lock_);
108 return shutting_down_;
109}
110
111void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
112 Runtime* runtime = Runtime::Current();
113 BackgroundMethodSamplingProfiler* profiler =
114 reinterpret_cast<BackgroundMethodSamplingProfiler*>(arg);
115
116 // Add a random delay for the first time run so that we don't hammer the CPU
117 // with all profiles running at the same time.
118 const int kRandomDelayMaxSecs = 30;
119 const double kMaxBackoffSecs = 24*60*60; // Max backoff time.
120
121 srand(MicroTime() * getpid());
122 int startup_delay = rand() % kRandomDelayMaxSecs; // random delay for startup.
123
124
125 CHECK(runtime->AttachCurrentThread("Profiler", true, runtime->GetSystemThreadGroup(),
126 !runtime->IsCompiler()));
127
128 Thread* self = Thread::Current();
129
130 while (true) {
131 if (ShuttingDown(self)) {
132 break;
133 }
134
135 {
136 // wait until we need to run another profile
137 uint64_t delay_secs = profiler->period_s_ * profiler->backoff_factor_;
138
139 // Add a startup delay to prevent all the profiles running at once.
140 delay_secs += startup_delay;
141
142 // Immediate startup for benchmarking?
143 if (profiler->start_immediately_ && startup_delay > 0) {
144 delay_secs = 0;
145 }
146
147 startup_delay = 0;
148
149 LOG(DEBUG) << "Delaying profile start for " << delay_secs << " secs";
150 MutexLock mu(self, profiler->wait_lock_);
151 profiler->period_condition_.TimedWait(self, delay_secs * 1000, 0);
152
153 // Expand the backoff by its coefficient, but don't go beyond the max.
154 double new_backoff = profiler->backoff_factor_ * profiler->backoff_coefficient_;
155 if (new_backoff < kMaxBackoffSecs) {
156 profiler->backoff_factor_ = new_backoff;
157 }
158 }
159
160 if (ShuttingDown(self)) {
161 break;
162 }
163
164
165 uint64_t start_us = MicroTime();
166 uint64_t end_us = start_us + profiler->duration_s_ * 1000000LL;
167 uint64_t now_us = start_us;
168
169 LOG(DEBUG) << "Starting profiling run now for " << PrettyDuration((end_us - start_us) * 1000);
170
171
172 SampleCheckpoint check_point(profiler);
173
Dave Allison39c3bfb2014-01-28 18:33:52 -0800174 size_t valid_samples = 0;
Dave Allison0aded082013-11-07 13:15:11 -0800175 while (now_us < end_us) {
176 if (ShuttingDown(self)) {
177 break;
178 }
179
180 usleep(profiler->interval_us_); // Non-interruptible sleep.
181
182 ThreadList* thread_list = runtime->GetThreadList();
183
184 profiler->profiler_barrier_->Init(self, 0);
Dave Allison39c3bfb2014-01-28 18:33:52 -0800185 size_t barrier_count = thread_list->RunCheckpointOnRunnableThreads(&check_point);
186
187 // All threads are suspended, nothing to do.
188 if (barrier_count == 0) {
189 now_us = MicroTime();
190 continue;
191 }
192
193 valid_samples += barrier_count;
Dave Allison0aded082013-11-07 13:15:11 -0800194
195 ThreadState old_state = self->SetState(kWaitingForCheckPointsToRun);
196
197 // Wait for the barrier to be crossed by all runnable threads. This wait
198 // is done with a timeout so that we can detect problems with the checkpoint
199 // running code. We should never see this.
200 const uint32_t kWaitTimeoutMs = 10000;
201 const uint32_t kWaitTimeoutUs = kWaitTimeoutMs * 1000;
202
203 uint64_t waitstart_us = MicroTime();
204 // Wait for all threads to pass the barrier.
205 profiler->profiler_barrier_->Increment(self, barrier_count, kWaitTimeoutMs);
206 uint64_t waitend_us = MicroTime();
207 uint64_t waitdiff_us = waitend_us - waitstart_us;
208
209 // We should never get a timeout. If we do, it suggests a problem with the checkpoint
210 // code. Crash the process in this case.
211 CHECK_LT(waitdiff_us, kWaitTimeoutUs);
212
213 self->SetState(old_state);
214
215 // Update the current time.
216 now_us = MicroTime();
217 }
218
Dave Allison39c3bfb2014-01-28 18:33:52 -0800219 if (valid_samples > 0 && !ShuttingDown(self)) {
Dave Allison0aded082013-11-07 13:15:11 -0800220 // After the profile has been taken, write it out.
221 ScopedObjectAccess soa(self); // Acquire the mutator lock.
222 uint32_t size = profiler->WriteProfile();
223 LOG(DEBUG) << "Profile size: " << size;
224 }
225 }
226
227 LOG(INFO) << "Profiler shutdown";
228 runtime->DetachCurrentThread();
229 return nullptr;
230}
231
232// Write out the profile file if we are generating a profile.
233uint32_t BackgroundMethodSamplingProfiler::WriteProfile() {
Dave Allison0aded082013-11-07 13:15:11 -0800234 std::string full_name = profile_file_name_;
Dave Allison0aded082013-11-07 13:15:11 -0800235 LOG(DEBUG) << "Saving profile to " << full_name;
236
Dave Allison39c3bfb2014-01-28 18:33:52 -0800237 int fd = open(full_name.c_str(), O_RDWR);
238 if (fd < 0) {
239 // Open failed.
240 LOG(ERROR) << "Failed to open profile file " << full_name;
Dave Allison0aded082013-11-07 13:15:11 -0800241 return 0;
242 }
Dave Allison39c3bfb2014-01-28 18:33:52 -0800243
244 // Lock the file for exclusive access. This will block if another process is using
245 // the file.
246 int err = flock(fd, LOCK_EX);
247 if (err < 0) {
248 LOG(ERROR) << "Failed to lock profile file " << full_name;
249 return 0;
250 }
251
252 // Read the previous profile.
253 profile_table_.ReadPrevious(fd);
254
255 // Move back to the start of the file.
256 lseek(fd, 0, SEEK_SET);
257
258 // Format the profile output and write to the file.
Dave Allison0aded082013-11-07 13:15:11 -0800259 std::ostringstream os;
260 uint32_t num_methods = DumpProfile(os);
261 std::string data(os.str());
Dave Allison39c3bfb2014-01-28 18:33:52 -0800262 const char *p = data.c_str();
263 size_t length = data.length();
264 size_t full_length = length;
265 do {
266 int n = ::write(fd, p, length);
267 p += n;
268 length -= n;
269 } while (length > 0);
270
271 // Truncate the file to the new length.
272 ftruncate(fd, full_length);
273
274 // Now unlock the file, allowing another process in.
275 err = flock(fd, LOCK_UN);
276 if (err < 0) {
277 LOG(ERROR) << "Failed to unlock profile file " << full_name;
278 }
279
280 // Done, close the file.
281 ::close(fd);
282
283 // Clean the profile for the next time.
284 CleanProfile();
285
Dave Allison0aded082013-11-07 13:15:11 -0800286 return num_methods;
287}
288
289// Start a profile thread with the user-supplied arguments.
290void BackgroundMethodSamplingProfiler::Start(int period, int duration,
Dave Allison39c3bfb2014-01-28 18:33:52 -0800291 const std::string& profile_file_name, const std::string& procName,
292 int interval_us,
Dave Allison0aded082013-11-07 13:15:11 -0800293 double backoff_coefficient, bool startImmediately) {
294 Thread* self = Thread::Current();
295 {
296 MutexLock mu(self, *Locks::profiler_lock_);
297 // Don't start two profiler threads.
298 if (profiler_ != nullptr) {
299 return;
300 }
301 }
302
Dave Allison4a7867b2014-01-30 17:44:12 -0800303 // Only on target...
304#ifdef HAVE_ANDROID_OS
Dave Allison39c3bfb2014-01-28 18:33:52 -0800305 if (!startImmediately) {
306 // Switch off profiler if the dalvik.vm.profiler property has value 0.
307 char buf[PROP_VALUE_MAX];
308 property_get("dalvik.vm.profiler", buf, "0");
309 if (strcmp(buf, "0") == 0) {
310 LOG(INFO) << "Profiler disabled. To enable setprop dalvik.vm.profiler 1";
311 return;
312 }
Dave Allison4a7867b2014-01-30 17:44:12 -0800313 }
314#endif
315
Dave Allison0aded082013-11-07 13:15:11 -0800316 LOG(INFO) << "Starting profile with period " << period << "s, duration " << duration <<
317 "s, interval " << interval_us << "us. Profile file " << profile_file_name;
318
319 {
320 MutexLock mu(self, *Locks::profiler_lock_);
321 profiler_ = new BackgroundMethodSamplingProfiler(period, duration, profile_file_name,
Dave Allison39c3bfb2014-01-28 18:33:52 -0800322 procName,
Dave Allison0aded082013-11-07 13:15:11 -0800323 backoff_coefficient,
324 interval_us, startImmediately);
325
326 CHECK_PTHREAD_CALL(pthread_create, (&profiler_pthread_, nullptr, &RunProfilerThread,
327 reinterpret_cast<void*>(profiler_)),
328 "Profiler thread");
329 }
330}
331
332
333
334void BackgroundMethodSamplingProfiler::Stop() {
335 BackgroundMethodSamplingProfiler* profiler = nullptr;
336 pthread_t profiler_pthread = 0U;
337 {
338 MutexLock trace_mu(Thread::Current(), *Locks::profiler_lock_);
339 profiler = profiler_;
340 shutting_down_ = true;
341 profiler_pthread = profiler_pthread_;
342 }
343
344 // Now wake up the sampler thread if it sleeping.
345 {
346 MutexLock profile_mu(Thread::Current(), profiler->wait_lock_);
347 profiler->period_condition_.Signal(Thread::Current());
348 }
349 // Wait for the sample thread to stop.
350 CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profiler thread shutdown");
351
352 {
353 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
354 profiler_ = nullptr;
355 }
356 delete profiler;
357}
358
359
360void BackgroundMethodSamplingProfiler::Shutdown() {
361 Stop();
362}
363
364BackgroundMethodSamplingProfiler::BackgroundMethodSamplingProfiler(int period, int duration,
Dave Allison39c3bfb2014-01-28 18:33:52 -0800365 const std::string& profile_file_name,
366 const std::string& process_name,
Dave Allison0aded082013-11-07 13:15:11 -0800367 double backoff_coefficient, int interval_us, bool startImmediately)
Dave Allison39c3bfb2014-01-28 18:33:52 -0800368 : profile_file_name_(profile_file_name), process_name_(process_name),
Dave Allison0aded082013-11-07 13:15:11 -0800369 period_s_(period), start_immediately_(startImmediately),
370 interval_us_(interval_us), backoff_factor_(1.0),
371 backoff_coefficient_(backoff_coefficient), duration_s_(duration),
372 wait_lock_("Profile wait lock"),
373 period_condition_("Profile condition", wait_lock_),
374 profile_table_(wait_lock_),
375 profiler_barrier_(new Barrier(0)) {
376 // Populate the filtered_methods set.
377 // This is empty right now, but to add a method, do this:
378 //
379 // filtered_methods_.insert("void java.lang.Object.wait(long, int)");
380}
381
382// A method has been hit, record its invocation in the method map.
383// The mutator_lock must be held (shared) when this is called.
384void BackgroundMethodSamplingProfiler::RecordMethod(mirror::ArtMethod* method) {
385 if (method == nullptr) {
386 profile_table_.NullMethod();
387 // Don't record a nullptr method.
388 return;
389 }
390
391 mirror::Class* cls = method->GetDeclaringClass();
392 if (cls != nullptr) {
393 if (cls->GetClassLoader() == nullptr) {
394 // Don't include things in the boot
395 profile_table_.BootMethod();
396 return;
397 }
398 }
399
400 bool is_filtered = false;
401
402 MethodHelper mh(method);
403 if (strcmp(mh.GetName(), "<clinit>") == 0) {
404 // always filter out class init
405 is_filtered = true;
406 }
407
408 // Filter out methods by name if there are any.
409 if (!is_filtered && filtered_methods_.size() > 0) {
410 std::string method_full_name = PrettyMethod(method);
411
412 // Don't include specific filtered methods.
413 is_filtered = filtered_methods_.count(method_full_name) != 0;
414 }
415
416 // Add to the profile table unless it is filtered out.
417 if (!is_filtered) {
418 profile_table_.Put(method);
419 }
420}
421
422// Clean out any recordings for the method traces.
423void BackgroundMethodSamplingProfiler::CleanProfile() {
424 profile_table_.Clear();
425}
426
427uint32_t BackgroundMethodSamplingProfiler::DumpProfile(std::ostream& os) {
428 return profile_table_.Write(os);
429}
430
431// Profile Table.
432// This holds a mapping of mirror::ArtMethod* to a count of how many times a sample
433// hit it at the top of the stack.
434ProfileSampleResults::ProfileSampleResults(Mutex& lock) : lock_(lock), num_samples_(0),
435 num_null_methods_(0),
436 num_boot_methods_(0) {
437 for (int i = 0; i < kHashSize; i++) {
438 table[i] = nullptr;
439 }
440}
441
442ProfileSampleResults::~ProfileSampleResults() {
443 for (int i = 0; i < kHashSize; i++) {
444 delete table[i];
445 }
446}
447
448// Add a method to the profile table. If it the first time the method
449// has been seen, add it with count=1, otherwise increment the count.
450void ProfileSampleResults::Put(mirror::ArtMethod* method) {
451 lock_.Lock(Thread::Current());
452 uint32_t index = Hash(method);
453 if (table[index] == nullptr) {
454 table[index] = new Map();
455 }
456 Map::iterator i = table[index]->find(method);
457 if (i == table[index]->end()) {
458 (*table[index])[method] = 1;
459 } else {
460 i->second++;
461 }
462 num_samples_++;
463 lock_.Unlock(Thread::Current());
464}
465
Dave Allison39c3bfb2014-01-28 18:33:52 -0800466// Write the profile table to the output stream. Also merge with the previous profile.
Dave Allison0aded082013-11-07 13:15:11 -0800467uint32_t ProfileSampleResults::Write(std::ostream &os) {
468 ScopedObjectAccess soa(Thread::Current());
Dave Allison39c3bfb2014-01-28 18:33:52 -0800469 num_samples_ += previous_num_samples_;
470 num_null_methods_ += previous_num_null_methods_;
471 num_boot_methods_ += previous_num_boot_methods_;
472
Dave Allison0aded082013-11-07 13:15:11 -0800473 LOG(DEBUG) << "Profile: " << num_samples_ << "/" << num_null_methods_ << "/" << num_boot_methods_;
474 os << num_samples_ << "/" << num_null_methods_ << "/" << num_boot_methods_ << "\n";
475 uint32_t num_methods = 0;
476 for (int i = 0 ; i < kHashSize; i++) {
477 Map *map = table[i];
478 if (map != nullptr) {
479 for (const auto &meth_iter : *map) {
Dave Allison39c3bfb2014-01-28 18:33:52 -0800480 mirror::ArtMethod *method = meth_iter.first;
481 std::string method_name = PrettyMethod(method);
482
483 MethodHelper mh(method);
484 const DexFile::CodeItem* codeitem = mh.GetCodeItem();
485 uint32_t method_size = 0;
486 if (codeitem != nullptr) {
487 method_size = codeitem->insns_size_in_code_units_;
488 }
489 uint32_t count = meth_iter.second;
490
491 // Merge this profile entry with one from a previous run (if present). Also
492 // remove the previous entry.
493 PreviousProfile::iterator pi = previous_.find(method_name);
494 if (pi != previous_.end()) {
495 count += pi->second.count_;
496 previous_.erase(pi);
497 }
498 os << StringPrintf("%s/%u/%u\n", method_name.c_str(), count, method_size);
499 ++num_methods;
500 }
Dave Allison0aded082013-11-07 13:15:11 -0800501 }
502 }
Dave Allison39c3bfb2014-01-28 18:33:52 -0800503
504 // Now we write out the remaining previous methods.
505 for (PreviousProfile::iterator pi = previous_.begin(); pi != previous_.end(); ++pi) {
506 os << StringPrintf("%s/%u/%u\n", pi->first.c_str(), pi->second.count_, pi->second.method_size_);
507 ++num_methods;
508 }
Dave Allison0aded082013-11-07 13:15:11 -0800509 return num_methods;
510}
511
512void ProfileSampleResults::Clear() {
513 num_samples_ = 0;
514 num_null_methods_ = 0;
515 num_boot_methods_ = 0;
516 for (int i = 0; i < kHashSize; i++) {
517 delete table[i];
518 table[i] = nullptr;
519 }
Dave Allison39c3bfb2014-01-28 18:33:52 -0800520 previous_.clear();
Dave Allison0aded082013-11-07 13:15:11 -0800521}
522
523uint32_t ProfileSampleResults::Hash(mirror::ArtMethod* method) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800524 return (PointerToLowMemUInt32(method) >> 3) % kHashSize;
Dave Allison0aded082013-11-07 13:15:11 -0800525}
526
Dave Allison39c3bfb2014-01-28 18:33:52 -0800527// Read a single line into the given string. Returns true if everything OK, false
528// on EOF or error.
529static bool ReadProfileLine(int fd, std::string& line) {
530 char buf[4];
531 line.clear();
532 while (true) {
533 int n = read(fd, buf, 1); // TODO: could speed this up but is it worth it?
534 if (n != 1) {
535 return false;
536 }
537 if (buf[0] == '\n') {
538 break;
539 }
540 line += buf[0];
541 }
542 return true;
543}
544
545void ProfileSampleResults::ReadPrevious(int fd) {
546 // Reset counters.
547 previous_num_samples_ = previous_num_null_methods_ = previous_num_boot_methods_ = 0;
548
549 std::string line;
550
551 // The first line contains summary information.
552 if (!ReadProfileLine(fd, line)) {
553 return;
554 }
555 std::vector<std::string> summary_info;
556 Split(line, '/', summary_info);
557 if (summary_info.size() != 3) {
558 // Bad summary info. It should be count/nullcount/bootcount
559 return;
560 }
561 previous_num_samples_ = atoi(summary_info[0].c_str());
562 previous_num_null_methods_ = atoi(summary_info[1].c_str());
563 previous_num_boot_methods_ = atoi(summary_info[2].c_str());
564
565 // Now read each line until the end of file. Each line consists of 3 fields separated by /
566 while (true) {
567 if (!ReadProfileLine(fd, line)) {
568 break;
569 }
570 std::vector<std::string> info;
571 Split(line, '/', info);
572 if (info.size() != 3) {
573 // Malformed.
574 break;
575 }
576 std::string methodname = info[0];
577 uint32_t count = atoi(info[1].c_str());
578 uint32_t size = atoi(info[2].c_str());
579 previous_[methodname] = PreviousValue(count, size);
580 }
581}
Dave Allison0aded082013-11-07 13:15:11 -0800582} // namespace art
583