trace.cc revision b2ec9f5c128673c43f776cbe12c8eeb0a6884ebb
1/* 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 "trace.h" 18 19#include <sys/uio.h> 20#include <unistd.h> 21 22#include "android-base/stringprintf.h" 23 24#include "art_method-inl.h" 25#include "base/casts.h" 26#include "base/enums.h" 27#include "base/stl_util.h" 28#include "base/systrace.h" 29#include "base/time_utils.h" 30#include "base/unix_file/fd_file.h" 31#include "class_linker.h" 32#include "common_throws.h" 33#include "debugger.h" 34#include "dex/descriptors_names.h" 35#include "dex/dex_file-inl.h" 36#include "entrypoints/quick/quick_entrypoints.h" 37#include "gc/scoped_gc_critical_section.h" 38#include "instrumentation.h" 39#include "mirror/class-inl.h" 40#include "mirror/dex_cache-inl.h" 41#include "mirror/object-inl.h" 42#include "mirror/object_array-inl.h" 43#include "nativehelper/scoped_local_ref.h" 44#include "os.h" 45#include "scoped_thread_state_change-inl.h" 46#include "stack.h" 47#include "thread.h" 48#include "thread_list.h" 49#include "utils.h" 50 51namespace art { 52 53using android::base::StringPrintf; 54 55static constexpr size_t TraceActionBits = MinimumBitsToStore( 56 static_cast<size_t>(kTraceMethodActionMask)); 57static constexpr uint8_t kOpNewMethod = 1U; 58static constexpr uint8_t kOpNewThread = 2U; 59static constexpr uint8_t kOpTraceSummary = 3U; 60 61class BuildStackTraceVisitor : public StackVisitor { 62 public: 63 explicit BuildStackTraceVisitor(Thread* thread) 64 : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), 65 method_trace_(Trace::AllocStackTrace()) {} 66 67 bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) { 68 ArtMethod* m = GetMethod(); 69 // Ignore runtime frames (in particular callee save). 70 if (!m->IsRuntimeMethod()) { 71 method_trace_->push_back(m); 72 } 73 return true; 74 } 75 76 // Returns a stack trace where the topmost frame corresponds with the first element of the vector. 77 std::vector<ArtMethod*>* GetStackTrace() const { 78 return method_trace_; 79 } 80 81 private: 82 std::vector<ArtMethod*>* const method_trace_; 83 84 DISALLOW_COPY_AND_ASSIGN(BuildStackTraceVisitor); 85}; 86 87static const char kTraceTokenChar = '*'; 88static const uint16_t kTraceHeaderLength = 32; 89static const uint32_t kTraceMagicValue = 0x574f4c53; 90static const uint16_t kTraceVersionSingleClock = 2; 91static const uint16_t kTraceVersionDualClock = 3; 92static const uint16_t kTraceRecordSizeSingleClock = 10; // using v2 93static const uint16_t kTraceRecordSizeDualClock = 14; // using v3 with two timestamps 94 95TraceClockSource Trace::default_clock_source_ = kDefaultTraceClockSource; 96 97Trace* volatile Trace::the_trace_ = nullptr; 98pthread_t Trace::sampling_pthread_ = 0U; 99std::unique_ptr<std::vector<ArtMethod*>> Trace::temp_stack_trace_; 100 101// The key identifying the tracer to update instrumentation. 102static constexpr const char* kTracerInstrumentationKey = "Tracer"; 103 104static TraceAction DecodeTraceAction(uint32_t tmid) { 105 return static_cast<TraceAction>(tmid & kTraceMethodActionMask); 106} 107 108ArtMethod* Trace::DecodeTraceMethod(uint32_t tmid) { 109 MutexLock mu(Thread::Current(), *unique_methods_lock_); 110 return unique_methods_[tmid >> TraceActionBits]; 111} 112 113uint32_t Trace::EncodeTraceMethod(ArtMethod* method) { 114 MutexLock mu(Thread::Current(), *unique_methods_lock_); 115 uint32_t idx; 116 auto it = art_method_id_map_.find(method); 117 if (it != art_method_id_map_.end()) { 118 idx = it->second; 119 } else { 120 unique_methods_.push_back(method); 121 idx = unique_methods_.size() - 1; 122 art_method_id_map_.emplace(method, idx); 123 } 124 DCHECK_LT(idx, unique_methods_.size()); 125 DCHECK_EQ(unique_methods_[idx], method); 126 return idx; 127} 128 129uint32_t Trace::EncodeTraceMethodAndAction(ArtMethod* method, TraceAction action) { 130 uint32_t tmid = (EncodeTraceMethod(method) << TraceActionBits) | action; 131 DCHECK_EQ(method, DecodeTraceMethod(tmid)); 132 return tmid; 133} 134 135std::vector<ArtMethod*>* Trace::AllocStackTrace() { 136 return (temp_stack_trace_.get() != nullptr) ? temp_stack_trace_.release() : 137 new std::vector<ArtMethod*>(); 138} 139 140void Trace::FreeStackTrace(std::vector<ArtMethod*>* stack_trace) { 141 stack_trace->clear(); 142 temp_stack_trace_.reset(stack_trace); 143} 144 145void Trace::SetDefaultClockSource(TraceClockSource clock_source) { 146#if defined(__linux__) 147 default_clock_source_ = clock_source; 148#else 149 if (clock_source != TraceClockSource::kWall) { 150 LOG(WARNING) << "Ignoring tracing request to use CPU time."; 151 } 152#endif 153} 154 155static uint16_t GetTraceVersion(TraceClockSource clock_source) { 156 return (clock_source == TraceClockSource::kDual) ? kTraceVersionDualClock 157 : kTraceVersionSingleClock; 158} 159 160static uint16_t GetRecordSize(TraceClockSource clock_source) { 161 return (clock_source == TraceClockSource::kDual) ? kTraceRecordSizeDualClock 162 : kTraceRecordSizeSingleClock; 163} 164 165bool Trace::UseThreadCpuClock() { 166 return (clock_source_ == TraceClockSource::kThreadCpu) || 167 (clock_source_ == TraceClockSource::kDual); 168} 169 170bool Trace::UseWallClock() { 171 return (clock_source_ == TraceClockSource::kWall) || 172 (clock_source_ == TraceClockSource::kDual); 173} 174 175void Trace::MeasureClockOverhead() { 176 if (UseThreadCpuClock()) { 177 Thread::Current()->GetCpuMicroTime(); 178 } 179 if (UseWallClock()) { 180 MicroTime(); 181 } 182} 183 184// Compute an average time taken to measure clocks. 185uint32_t Trace::GetClockOverheadNanoSeconds() { 186 Thread* self = Thread::Current(); 187 uint64_t start = self->GetCpuMicroTime(); 188 189 for (int i = 4000; i > 0; i--) { 190 MeasureClockOverhead(); 191 MeasureClockOverhead(); 192 MeasureClockOverhead(); 193 MeasureClockOverhead(); 194 MeasureClockOverhead(); 195 MeasureClockOverhead(); 196 MeasureClockOverhead(); 197 MeasureClockOverhead(); 198 } 199 200 uint64_t elapsed_us = self->GetCpuMicroTime() - start; 201 return static_cast<uint32_t>(elapsed_us / 32); 202} 203 204// TODO: put this somewhere with the big-endian equivalent used by JDWP. 205static void Append2LE(uint8_t* buf, uint16_t val) { 206 *buf++ = static_cast<uint8_t>(val); 207 *buf++ = static_cast<uint8_t>(val >> 8); 208} 209 210// TODO: put this somewhere with the big-endian equivalent used by JDWP. 211static void Append4LE(uint8_t* buf, uint32_t val) { 212 *buf++ = static_cast<uint8_t>(val); 213 *buf++ = static_cast<uint8_t>(val >> 8); 214 *buf++ = static_cast<uint8_t>(val >> 16); 215 *buf++ = static_cast<uint8_t>(val >> 24); 216} 217 218// TODO: put this somewhere with the big-endian equivalent used by JDWP. 219static void Append8LE(uint8_t* buf, uint64_t val) { 220 *buf++ = static_cast<uint8_t>(val); 221 *buf++ = static_cast<uint8_t>(val >> 8); 222 *buf++ = static_cast<uint8_t>(val >> 16); 223 *buf++ = static_cast<uint8_t>(val >> 24); 224 *buf++ = static_cast<uint8_t>(val >> 32); 225 *buf++ = static_cast<uint8_t>(val >> 40); 226 *buf++ = static_cast<uint8_t>(val >> 48); 227 *buf++ = static_cast<uint8_t>(val >> 56); 228} 229 230static void GetSample(Thread* thread, void* arg) REQUIRES_SHARED(Locks::mutator_lock_) { 231 BuildStackTraceVisitor build_trace_visitor(thread); 232 build_trace_visitor.WalkStack(); 233 std::vector<ArtMethod*>* stack_trace = build_trace_visitor.GetStackTrace(); 234 Trace* the_trace = reinterpret_cast<Trace*>(arg); 235 the_trace->CompareAndUpdateStackTrace(thread, stack_trace); 236} 237 238static void ClearThreadStackTraceAndClockBase(Thread* thread, void* arg ATTRIBUTE_UNUSED) { 239 thread->SetTraceClockBase(0); 240 std::vector<ArtMethod*>* stack_trace = thread->GetStackTraceSample(); 241 thread->SetStackTraceSample(nullptr); 242 delete stack_trace; 243} 244 245void Trace::CompareAndUpdateStackTrace(Thread* thread, 246 std::vector<ArtMethod*>* stack_trace) { 247 CHECK_EQ(pthread_self(), sampling_pthread_); 248 std::vector<ArtMethod*>* old_stack_trace = thread->GetStackTraceSample(); 249 // Update the thread's stack trace sample. 250 thread->SetStackTraceSample(stack_trace); 251 // Read timer clocks to use for all events in this trace. 252 uint32_t thread_clock_diff = 0; 253 uint32_t wall_clock_diff = 0; 254 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 255 if (old_stack_trace == nullptr) { 256 // If there's no previous stack trace sample for this thread, log an entry event for all 257 // methods in the trace. 258 for (auto rit = stack_trace->rbegin(); rit != stack_trace->rend(); ++rit) { 259 LogMethodTraceEvent(thread, *rit, instrumentation::Instrumentation::kMethodEntered, 260 thread_clock_diff, wall_clock_diff); 261 } 262 } else { 263 // If there's a previous stack trace for this thread, diff the traces and emit entry and exit 264 // events accordingly. 265 auto old_rit = old_stack_trace->rbegin(); 266 auto rit = stack_trace->rbegin(); 267 // Iterate bottom-up over both traces until there's a difference between them. 268 while (old_rit != old_stack_trace->rend() && rit != stack_trace->rend() && *old_rit == *rit) { 269 old_rit++; 270 rit++; 271 } 272 // Iterate top-down over the old trace until the point where they differ, emitting exit events. 273 for (auto old_it = old_stack_trace->begin(); old_it != old_rit.base(); ++old_it) { 274 LogMethodTraceEvent(thread, *old_it, instrumentation::Instrumentation::kMethodExited, 275 thread_clock_diff, wall_clock_diff); 276 } 277 // Iterate bottom-up over the new trace from the point where they differ, emitting entry events. 278 for (; rit != stack_trace->rend(); ++rit) { 279 LogMethodTraceEvent(thread, *rit, instrumentation::Instrumentation::kMethodEntered, 280 thread_clock_diff, wall_clock_diff); 281 } 282 FreeStackTrace(old_stack_trace); 283 } 284} 285 286void* Trace::RunSamplingThread(void* arg) { 287 Runtime* runtime = Runtime::Current(); 288 intptr_t interval_us = reinterpret_cast<intptr_t>(arg); 289 CHECK_GE(interval_us, 0); 290 CHECK(runtime->AttachCurrentThread("Sampling Profiler", true, runtime->GetSystemThreadGroup(), 291 !runtime->IsAotCompiler())); 292 293 while (true) { 294 usleep(interval_us); 295 ScopedTrace trace("Profile sampling"); 296 Thread* self = Thread::Current(); 297 Trace* the_trace; 298 { 299 MutexLock mu(self, *Locks::trace_lock_); 300 the_trace = the_trace_; 301 if (the_trace == nullptr) { 302 break; 303 } 304 } 305 { 306 ScopedSuspendAll ssa(__FUNCTION__); 307 MutexLock mu(self, *Locks::thread_list_lock_); 308 runtime->GetThreadList()->ForEach(GetSample, the_trace); 309 } 310 } 311 312 runtime->DetachCurrentThread(); 313 return nullptr; 314} 315 316void Trace::Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags, 317 TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) { 318 Thread* self = Thread::Current(); 319 { 320 MutexLock mu(self, *Locks::trace_lock_); 321 if (the_trace_ != nullptr) { 322 LOG(ERROR) << "Trace already in progress, ignoring this request"; 323 return; 324 } 325 } 326 327 // Check interval if sampling is enabled 328 if (trace_mode == TraceMode::kSampling && interval_us <= 0) { 329 LOG(ERROR) << "Invalid sampling interval: " << interval_us; 330 ScopedObjectAccess soa(self); 331 ThrowRuntimeException("Invalid sampling interval: %d", interval_us); 332 return; 333 } 334 335 // Open trace file if not going directly to ddms. 336 std::unique_ptr<File> trace_file; 337 if (output_mode != TraceOutputMode::kDDMS) { 338 if (trace_fd < 0) { 339 trace_file.reset(OS::CreateEmptyFileWriteOnly(trace_filename)); 340 } else { 341 trace_file.reset(new File(trace_fd, "tracefile")); 342 trace_file->DisableAutoClose(); 343 } 344 if (trace_file.get() == nullptr) { 345 PLOG(ERROR) << "Unable to open trace file '" << trace_filename << "'"; 346 ScopedObjectAccess soa(self); 347 ThrowRuntimeException("Unable to open trace file '%s'", trace_filename); 348 return; 349 } 350 } 351 352 Runtime* runtime = Runtime::Current(); 353 354 // Enable count of allocs if specified in the flags. 355 bool enable_stats = false; 356 357 // Create Trace object. 358 { 359 // Required since EnableMethodTracing calls ConfigureStubs which visits class linker classes. 360 gc::ScopedGCCriticalSection gcs(self, 361 gc::kGcCauseInstrumentation, 362 gc::kCollectorTypeInstrumentation); 363 ScopedSuspendAll ssa(__FUNCTION__); 364 MutexLock mu(self, *Locks::trace_lock_); 365 if (the_trace_ != nullptr) { 366 LOG(ERROR) << "Trace already in progress, ignoring this request"; 367 } else { 368 enable_stats = (flags && kTraceCountAllocs) != 0; 369 the_trace_ = new Trace(trace_file.release(), trace_filename, buffer_size, flags, output_mode, 370 trace_mode); 371 if (trace_mode == TraceMode::kSampling) { 372 CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, nullptr, &RunSamplingThread, 373 reinterpret_cast<void*>(interval_us)), 374 "Sampling profiler thread"); 375 the_trace_->interval_us_ = interval_us; 376 } else { 377 runtime->GetInstrumentation()->AddListener(the_trace_, 378 instrumentation::Instrumentation::kMethodEntered | 379 instrumentation::Instrumentation::kMethodExited | 380 instrumentation::Instrumentation::kMethodUnwind); 381 // TODO: In full-PIC mode, we don't need to fully deopt. 382 runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey); 383 } 384 } 385 } 386 387 // Can't call this when holding the mutator lock. 388 if (enable_stats) { 389 runtime->SetStatsEnabled(true); 390 } 391} 392 393void Trace::StopTracing(bool finish_tracing, bool flush_file) { 394 bool stop_alloc_counting = false; 395 Runtime* const runtime = Runtime::Current(); 396 Trace* the_trace = nullptr; 397 Thread* const self = Thread::Current(); 398 pthread_t sampling_pthread = 0U; 399 { 400 MutexLock mu(self, *Locks::trace_lock_); 401 if (the_trace_ == nullptr) { 402 LOG(ERROR) << "Trace stop requested, but no trace currently running"; 403 } else { 404 the_trace = the_trace_; 405 the_trace_ = nullptr; 406 sampling_pthread = sampling_pthread_; 407 } 408 } 409 // Make sure that we join before we delete the trace since we don't want to have 410 // the sampling thread access a stale pointer. This finishes since the sampling thread exits when 411 // the_trace_ is null. 412 if (sampling_pthread != 0U) { 413 CHECK_PTHREAD_CALL(pthread_join, (sampling_pthread, nullptr), "sampling thread shutdown"); 414 sampling_pthread_ = 0U; 415 } 416 417 if (the_trace != nullptr) { 418 stop_alloc_counting = (the_trace->flags_ & Trace::kTraceCountAllocs) != 0; 419 if (finish_tracing) { 420 the_trace->FinishTracing(); 421 } 422 gc::ScopedGCCriticalSection gcs(self, 423 gc::kGcCauseInstrumentation, 424 gc::kCollectorTypeInstrumentation); 425 ScopedSuspendAll ssa(__FUNCTION__); 426 427 if (the_trace->trace_mode_ == TraceMode::kSampling) { 428 MutexLock mu(self, *Locks::thread_list_lock_); 429 runtime->GetThreadList()->ForEach(ClearThreadStackTraceAndClockBase, nullptr); 430 } else { 431 runtime->GetInstrumentation()->DisableMethodTracing(kTracerInstrumentationKey); 432 runtime->GetInstrumentation()->RemoveListener( 433 the_trace, instrumentation::Instrumentation::kMethodEntered | 434 instrumentation::Instrumentation::kMethodExited | 435 instrumentation::Instrumentation::kMethodUnwind); 436 } 437 if (the_trace->trace_file_.get() != nullptr) { 438 // Do not try to erase, so flush and close explicitly. 439 if (flush_file) { 440 if (the_trace->trace_file_->Flush() != 0) { 441 PLOG(WARNING) << "Could not flush trace file."; 442 } 443 } else { 444 the_trace->trace_file_->MarkUnchecked(); // Do not trigger guard. 445 } 446 if (the_trace->trace_file_->Close() != 0) { 447 PLOG(ERROR) << "Could not close trace file."; 448 } 449 } 450 delete the_trace; 451 } 452 if (stop_alloc_counting) { 453 // Can be racy since SetStatsEnabled is not guarded by any locks. 454 runtime->SetStatsEnabled(false); 455 } 456} 457 458void Trace::Abort() { 459 // Do not write anything anymore. 460 StopTracing(false, false); 461} 462 463void Trace::Stop() { 464 // Finish writing. 465 StopTracing(true, true); 466} 467 468void Trace::Shutdown() { 469 if (GetMethodTracingMode() != kTracingInactive) { 470 Stop(); 471 } 472} 473 474void Trace::Pause() { 475 bool stop_alloc_counting = false; 476 Runtime* runtime = Runtime::Current(); 477 Trace* the_trace = nullptr; 478 479 Thread* const self = Thread::Current(); 480 pthread_t sampling_pthread = 0U; 481 { 482 MutexLock mu(self, *Locks::trace_lock_); 483 if (the_trace_ == nullptr) { 484 LOG(ERROR) << "Trace pause requested, but no trace currently running"; 485 return; 486 } else { 487 the_trace = the_trace_; 488 sampling_pthread = sampling_pthread_; 489 } 490 } 491 492 if (sampling_pthread != 0U) { 493 { 494 MutexLock mu(self, *Locks::trace_lock_); 495 the_trace_ = nullptr; 496 } 497 CHECK_PTHREAD_CALL(pthread_join, (sampling_pthread, nullptr), "sampling thread shutdown"); 498 sampling_pthread_ = 0U; 499 { 500 MutexLock mu(self, *Locks::trace_lock_); 501 the_trace_ = the_trace; 502 } 503 } 504 505 if (the_trace != nullptr) { 506 gc::ScopedGCCriticalSection gcs(self, 507 gc::kGcCauseInstrumentation, 508 gc::kCollectorTypeInstrumentation); 509 ScopedSuspendAll ssa(__FUNCTION__); 510 stop_alloc_counting = (the_trace->flags_ & Trace::kTraceCountAllocs) != 0; 511 512 if (the_trace->trace_mode_ == TraceMode::kSampling) { 513 MutexLock mu(self, *Locks::thread_list_lock_); 514 runtime->GetThreadList()->ForEach(ClearThreadStackTraceAndClockBase, nullptr); 515 } else { 516 runtime->GetInstrumentation()->DisableMethodTracing(kTracerInstrumentationKey); 517 runtime->GetInstrumentation()->RemoveListener( 518 the_trace, 519 instrumentation::Instrumentation::kMethodEntered | 520 instrumentation::Instrumentation::kMethodExited | 521 instrumentation::Instrumentation::kMethodUnwind); 522 } 523 } 524 525 if (stop_alloc_counting) { 526 // Can be racy since SetStatsEnabled is not guarded by any locks. 527 Runtime::Current()->SetStatsEnabled(false); 528 } 529} 530 531void Trace::Resume() { 532 Thread* self = Thread::Current(); 533 Trace* the_trace; 534 { 535 MutexLock mu(self, *Locks::trace_lock_); 536 if (the_trace_ == nullptr) { 537 LOG(ERROR) << "No trace to resume (or sampling mode), ignoring this request"; 538 return; 539 } 540 the_trace = the_trace_; 541 } 542 543 Runtime* runtime = Runtime::Current(); 544 545 // Enable count of allocs if specified in the flags. 546 bool enable_stats = (the_trace->flags_ && kTraceCountAllocs) != 0; 547 548 { 549 gc::ScopedGCCriticalSection gcs(self, 550 gc::kGcCauseInstrumentation, 551 gc::kCollectorTypeInstrumentation); 552 ScopedSuspendAll ssa(__FUNCTION__); 553 554 // Reenable. 555 if (the_trace->trace_mode_ == TraceMode::kSampling) { 556 CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, nullptr, &RunSamplingThread, 557 reinterpret_cast<void*>(the_trace->interval_us_)), "Sampling profiler thread"); 558 } else { 559 runtime->GetInstrumentation()->AddListener(the_trace, 560 instrumentation::Instrumentation::kMethodEntered | 561 instrumentation::Instrumentation::kMethodExited | 562 instrumentation::Instrumentation::kMethodUnwind); 563 // TODO: In full-PIC mode, we don't need to fully deopt. 564 runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey); 565 } 566 } 567 568 // Can't call this when holding the mutator lock. 569 if (enable_stats) { 570 runtime->SetStatsEnabled(true); 571 } 572} 573 574TracingMode Trace::GetMethodTracingMode() { 575 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 576 if (the_trace_ == nullptr) { 577 return kTracingInactive; 578 } else { 579 switch (the_trace_->trace_mode_) { 580 case TraceMode::kSampling: 581 return kSampleProfilingActive; 582 case TraceMode::kMethodTracing: 583 return kMethodTracingActive; 584 } 585 LOG(FATAL) << "Unreachable"; 586 UNREACHABLE(); 587 } 588} 589 590static constexpr size_t kMinBufSize = 18U; // Trace header is up to 18B. 591 592Trace::Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags, 593 TraceOutputMode output_mode, TraceMode trace_mode) 594 : trace_file_(trace_file), 595 buf_(new uint8_t[std::max(kMinBufSize, buffer_size)]()), 596 flags_(flags), trace_output_mode_(output_mode), trace_mode_(trace_mode), 597 clock_source_(default_clock_source_), 598 buffer_size_(std::max(kMinBufSize, buffer_size)), 599 start_time_(MicroTime()), clock_overhead_ns_(GetClockOverheadNanoSeconds()), cur_offset_(0), 600 overflow_(false), interval_us_(0), streaming_lock_(nullptr), 601 unique_methods_lock_(new Mutex("unique methods lock", kTracingUniqueMethodsLock)) { 602 uint16_t trace_version = GetTraceVersion(clock_source_); 603 if (output_mode == TraceOutputMode::kStreaming) { 604 trace_version |= 0xF0U; 605 } 606 // Set up the beginning of the trace. 607 memset(buf_.get(), 0, kTraceHeaderLength); 608 Append4LE(buf_.get(), kTraceMagicValue); 609 Append2LE(buf_.get() + 4, trace_version); 610 Append2LE(buf_.get() + 6, kTraceHeaderLength); 611 Append8LE(buf_.get() + 8, start_time_); 612 if (trace_version >= kTraceVersionDualClock) { 613 uint16_t record_size = GetRecordSize(clock_source_); 614 Append2LE(buf_.get() + 16, record_size); 615 } 616 static_assert(18 <= kMinBufSize, "Minimum buffer size not large enough for trace header"); 617 618 // Update current offset. 619 cur_offset_.StoreRelaxed(kTraceHeaderLength); 620 621 if (output_mode == TraceOutputMode::kStreaming) { 622 streaming_file_name_ = trace_name; 623 streaming_lock_ = new Mutex("tracing lock", LockLevel::kTracingStreamingLock); 624 seen_threads_.reset(new ThreadIDBitSet()); 625 } 626} 627 628Trace::~Trace() { 629 delete streaming_lock_; 630 delete unique_methods_lock_; 631} 632 633static uint64_t ReadBytes(uint8_t* buf, size_t bytes) { 634 uint64_t ret = 0; 635 for (size_t i = 0; i < bytes; ++i) { 636 ret |= static_cast<uint64_t>(buf[i]) << (i * 8); 637 } 638 return ret; 639} 640 641void Trace::DumpBuf(uint8_t* buf, size_t buf_size, TraceClockSource clock_source) { 642 uint8_t* ptr = buf + kTraceHeaderLength; 643 uint8_t* end = buf + buf_size; 644 645 while (ptr < end) { 646 uint32_t tmid = ReadBytes(ptr + 2, sizeof(tmid)); 647 ArtMethod* method = DecodeTraceMethod(tmid); 648 TraceAction action = DecodeTraceAction(tmid); 649 LOG(INFO) << ArtMethod::PrettyMethod(method) << " " << static_cast<int>(action); 650 ptr += GetRecordSize(clock_source); 651 } 652} 653 654void Trace::FinishTracing() { 655 size_t final_offset = 0; 656 657 std::set<ArtMethod*> visited_methods; 658 if (trace_output_mode_ == TraceOutputMode::kStreaming) { 659 // Clean up. 660 STLDeleteValues(&seen_methods_); 661 } else { 662 final_offset = cur_offset_.LoadRelaxed(); 663 GetVisitedMethods(final_offset, &visited_methods); 664 } 665 666 // Compute elapsed time. 667 uint64_t elapsed = MicroTime() - start_time_; 668 669 std::ostringstream os; 670 671 os << StringPrintf("%cversion\n", kTraceTokenChar); 672 os << StringPrintf("%d\n", GetTraceVersion(clock_source_)); 673 os << StringPrintf("data-file-overflow=%s\n", overflow_ ? "true" : "false"); 674 if (UseThreadCpuClock()) { 675 if (UseWallClock()) { 676 os << StringPrintf("clock=dual\n"); 677 } else { 678 os << StringPrintf("clock=thread-cpu\n"); 679 } 680 } else { 681 os << StringPrintf("clock=wall\n"); 682 } 683 os << StringPrintf("elapsed-time-usec=%" PRIu64 "\n", elapsed); 684 if (trace_output_mode_ != TraceOutputMode::kStreaming) { 685 size_t num_records = (final_offset - kTraceHeaderLength) / GetRecordSize(clock_source_); 686 os << StringPrintf("num-method-calls=%zd\n", num_records); 687 } 688 os << StringPrintf("clock-call-overhead-nsec=%d\n", clock_overhead_ns_); 689 os << StringPrintf("vm=art\n"); 690 os << StringPrintf("pid=%d\n", getpid()); 691 if ((flags_ & kTraceCountAllocs) != 0) { 692 os << StringPrintf("alloc-count=%d\n", Runtime::Current()->GetStat(KIND_ALLOCATED_OBJECTS)); 693 os << StringPrintf("alloc-size=%d\n", Runtime::Current()->GetStat(KIND_ALLOCATED_BYTES)); 694 os << StringPrintf("gc-count=%d\n", Runtime::Current()->GetStat(KIND_GC_INVOCATIONS)); 695 } 696 os << StringPrintf("%cthreads\n", kTraceTokenChar); 697 DumpThreadList(os); 698 os << StringPrintf("%cmethods\n", kTraceTokenChar); 699 DumpMethodList(os, visited_methods); 700 os << StringPrintf("%cend\n", kTraceTokenChar); 701 std::string header(os.str()); 702 703 if (trace_output_mode_ == TraceOutputMode::kStreaming) { 704 MutexLock mu(Thread::Current(), *streaming_lock_); // To serialize writing. 705 // Write a special token to mark the end of trace records and the start of 706 // trace summary. 707 uint8_t buf[7]; 708 Append2LE(buf, 0); 709 buf[2] = kOpTraceSummary; 710 Append4LE(buf + 3, static_cast<uint32_t>(header.length())); 711 WriteToBuf(buf, sizeof(buf)); 712 // Write the trace summary. The summary is identical to the file header when 713 // the output mode is not streaming (except for methods). 714 WriteToBuf(reinterpret_cast<const uint8_t*>(header.c_str()), header.length()); 715 // Flush the buffer, which may include some trace records before the summary. 716 FlushBuf(); 717 } else { 718 if (trace_file_.get() == nullptr) { 719 std::vector<uint8_t> data; 720 data.resize(header.length() + final_offset); 721 memcpy(data.data(), header.c_str(), header.length()); 722 memcpy(data.data() + header.length(), buf_.get(), final_offset); 723 Runtime::Current()->GetRuntimeCallbacks()->DdmPublishChunk(CHUNK_TYPE("MPSE"), 724 ArrayRef<const uint8_t>(data)); 725 const bool kDumpTraceInfo = false; 726 if (kDumpTraceInfo) { 727 LOG(INFO) << "Trace sent:\n" << header; 728 DumpBuf(buf_.get(), final_offset, clock_source_); 729 } 730 } else { 731 if (!trace_file_->WriteFully(header.c_str(), header.length()) || 732 !trace_file_->WriteFully(buf_.get(), final_offset)) { 733 std::string detail(StringPrintf("Trace data write failed: %s", strerror(errno))); 734 PLOG(ERROR) << detail; 735 ThrowRuntimeException("%s", detail.c_str()); 736 } 737 } 738 } 739} 740 741void Trace::DexPcMoved(Thread* thread ATTRIBUTE_UNUSED, 742 Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, 743 ArtMethod* method, 744 uint32_t new_dex_pc) { 745 // We're not recorded to listen to this kind of event, so complain. 746 LOG(ERROR) << "Unexpected dex PC event in tracing " << ArtMethod::PrettyMethod(method) 747 << " " << new_dex_pc; 748} 749 750void Trace::FieldRead(Thread* thread ATTRIBUTE_UNUSED, 751 Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, 752 ArtMethod* method, 753 uint32_t dex_pc, 754 ArtField* field ATTRIBUTE_UNUSED) 755 REQUIRES_SHARED(Locks::mutator_lock_) { 756 // We're not recorded to listen to this kind of event, so complain. 757 LOG(ERROR) << "Unexpected field read event in tracing " << ArtMethod::PrettyMethod(method) 758 << " " << dex_pc; 759} 760 761void Trace::FieldWritten(Thread* thread ATTRIBUTE_UNUSED, 762 Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, 763 ArtMethod* method, 764 uint32_t dex_pc, 765 ArtField* field ATTRIBUTE_UNUSED, 766 const JValue& field_value ATTRIBUTE_UNUSED) 767 REQUIRES_SHARED(Locks::mutator_lock_) { 768 // We're not recorded to listen to this kind of event, so complain. 769 LOG(ERROR) << "Unexpected field write event in tracing " << ArtMethod::PrettyMethod(method) 770 << " " << dex_pc; 771} 772 773void Trace::MethodEntered(Thread* thread, 774 Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, 775 ArtMethod* method, 776 uint32_t dex_pc ATTRIBUTE_UNUSED) { 777 uint32_t thread_clock_diff = 0; 778 uint32_t wall_clock_diff = 0; 779 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 780 LogMethodTraceEvent(thread, method, instrumentation::Instrumentation::kMethodEntered, 781 thread_clock_diff, wall_clock_diff); 782} 783 784void Trace::MethodExited(Thread* thread, 785 Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, 786 ArtMethod* method, 787 uint32_t dex_pc ATTRIBUTE_UNUSED, 788 const JValue& return_value ATTRIBUTE_UNUSED) { 789 uint32_t thread_clock_diff = 0; 790 uint32_t wall_clock_diff = 0; 791 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 792 LogMethodTraceEvent(thread, method, instrumentation::Instrumentation::kMethodExited, 793 thread_clock_diff, wall_clock_diff); 794} 795 796void Trace::MethodUnwind(Thread* thread, 797 Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, 798 ArtMethod* method, 799 uint32_t dex_pc ATTRIBUTE_UNUSED) { 800 uint32_t thread_clock_diff = 0; 801 uint32_t wall_clock_diff = 0; 802 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 803 LogMethodTraceEvent(thread, method, instrumentation::Instrumentation::kMethodUnwind, 804 thread_clock_diff, wall_clock_diff); 805} 806 807void Trace::ExceptionThrown(Thread* thread ATTRIBUTE_UNUSED, 808 Handle<mirror::Throwable> exception_object ATTRIBUTE_UNUSED) 809 REQUIRES_SHARED(Locks::mutator_lock_) { 810 LOG(ERROR) << "Unexpected exception thrown event in tracing"; 811} 812 813void Trace::ExceptionHandled(Thread* thread ATTRIBUTE_UNUSED, 814 Handle<mirror::Throwable> exception_object ATTRIBUTE_UNUSED) 815 REQUIRES_SHARED(Locks::mutator_lock_) { 816 LOG(ERROR) << "Unexpected exception thrown event in tracing"; 817} 818 819void Trace::Branch(Thread* /*thread*/, ArtMethod* method, 820 uint32_t /*dex_pc*/, int32_t /*dex_pc_offset*/) 821 REQUIRES_SHARED(Locks::mutator_lock_) { 822 LOG(ERROR) << "Unexpected branch event in tracing" << ArtMethod::PrettyMethod(method); 823} 824 825void Trace::InvokeVirtualOrInterface(Thread*, 826 Handle<mirror::Object>, 827 ArtMethod* method, 828 uint32_t dex_pc, 829 ArtMethod*) { 830 LOG(ERROR) << "Unexpected invoke event in tracing" << ArtMethod::PrettyMethod(method) 831 << " " << dex_pc; 832} 833 834void Trace::WatchedFramePop(Thread* self ATTRIBUTE_UNUSED, 835 const ShadowFrame& frame ATTRIBUTE_UNUSED) { 836 LOG(ERROR) << "Unexpected WatchedFramePop event in tracing"; 837} 838 839void Trace::ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wall_clock_diff) { 840 if (UseThreadCpuClock()) { 841 uint64_t clock_base = thread->GetTraceClockBase(); 842 if (UNLIKELY(clock_base == 0)) { 843 // First event, record the base time in the map. 844 uint64_t time = thread->GetCpuMicroTime(); 845 thread->SetTraceClockBase(time); 846 } else { 847 *thread_clock_diff = thread->GetCpuMicroTime() - clock_base; 848 } 849 } 850 if (UseWallClock()) { 851 *wall_clock_diff = MicroTime() - start_time_; 852 } 853} 854 855bool Trace::RegisterMethod(ArtMethod* method) { 856 mirror::DexCache* dex_cache = method->GetDexCache(); 857 const DexFile* dex_file = dex_cache->GetDexFile(); 858 if (seen_methods_.find(dex_file) == seen_methods_.end()) { 859 seen_methods_.insert(std::make_pair(dex_file, new DexIndexBitSet())); 860 } 861 DexIndexBitSet* bit_set = seen_methods_.find(dex_file)->second; 862 if (!(*bit_set)[method->GetDexMethodIndex()]) { 863 bit_set->set(method->GetDexMethodIndex()); 864 return true; 865 } 866 return false; 867} 868 869bool Trace::RegisterThread(Thread* thread) { 870 pid_t tid = thread->GetTid(); 871 CHECK_LT(0U, static_cast<uint32_t>(tid)); 872 CHECK_LT(static_cast<uint32_t>(tid), kMaxThreadIdNumber); 873 874 if (!(*seen_threads_)[tid]) { 875 seen_threads_->set(tid); 876 return true; 877 } 878 return false; 879} 880 881std::string Trace::GetMethodLine(ArtMethod* method) { 882 method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); 883 return StringPrintf("%#x\t%s\t%s\t%s\t%s\n", (EncodeTraceMethod(method) << TraceActionBits), 884 PrettyDescriptor(method->GetDeclaringClassDescriptor()).c_str(), method->GetName(), 885 method->GetSignature().ToString().c_str(), method->GetDeclaringClassSourceFile()); 886} 887 888void Trace::WriteToBuf(const uint8_t* src, size_t src_size) { 889 int32_t old_offset = cur_offset_.LoadRelaxed(); 890 int32_t new_offset = old_offset + static_cast<int32_t>(src_size); 891 if (dchecked_integral_cast<size_t>(new_offset) > buffer_size_) { 892 // Flush buffer. 893 if (!trace_file_->WriteFully(buf_.get(), old_offset)) { 894 PLOG(WARNING) << "Failed streaming a tracing event."; 895 } 896 897 // Check whether the data is too large for the buffer, then write immediately. 898 if (src_size >= buffer_size_) { 899 if (!trace_file_->WriteFully(src, src_size)) { 900 PLOG(WARNING) << "Failed streaming a tracing event."; 901 } 902 cur_offset_.StoreRelease(0); // Buffer is empty now. 903 return; 904 } 905 906 old_offset = 0; 907 new_offset = static_cast<int32_t>(src_size); 908 } 909 cur_offset_.StoreRelease(new_offset); 910 // Fill in data. 911 memcpy(buf_.get() + old_offset, src, src_size); 912} 913 914void Trace::FlushBuf() { 915 int32_t offset = cur_offset_.LoadRelaxed(); 916 if (!trace_file_->WriteFully(buf_.get(), offset)) { 917 PLOG(WARNING) << "Failed flush the remaining data in streaming."; 918 } 919 cur_offset_.StoreRelease(0); 920} 921 922void Trace::LogMethodTraceEvent(Thread* thread, ArtMethod* method, 923 instrumentation::Instrumentation::InstrumentationEvent event, 924 uint32_t thread_clock_diff, uint32_t wall_clock_diff) { 925 // Ensure we always use the non-obsolete version of the method so that entry/exit events have the 926 // same pointer value. 927 method = method->GetNonObsoleteMethod(); 928 // Advance cur_offset_ atomically. 929 int32_t new_offset; 930 int32_t old_offset = 0; 931 932 // We do a busy loop here trying to acquire the next offset. 933 if (trace_output_mode_ != TraceOutputMode::kStreaming) { 934 do { 935 old_offset = cur_offset_.LoadRelaxed(); 936 new_offset = old_offset + GetRecordSize(clock_source_); 937 if (static_cast<size_t>(new_offset) > buffer_size_) { 938 overflow_ = true; 939 return; 940 } 941 } while (!cur_offset_.CompareAndSetWeakSequentiallyConsistent(old_offset, new_offset)); 942 } 943 944 TraceAction action = kTraceMethodEnter; 945 switch (event) { 946 case instrumentation::Instrumentation::kMethodEntered: 947 action = kTraceMethodEnter; 948 break; 949 case instrumentation::Instrumentation::kMethodExited: 950 action = kTraceMethodExit; 951 break; 952 case instrumentation::Instrumentation::kMethodUnwind: 953 action = kTraceUnroll; 954 break; 955 default: 956 UNIMPLEMENTED(FATAL) << "Unexpected event: " << event; 957 } 958 959 uint32_t method_value = EncodeTraceMethodAndAction(method, action); 960 961 // Write data 962 uint8_t* ptr; 963 static constexpr size_t kPacketSize = 14U; // The maximum size of data in a packet. 964 uint8_t stack_buf[kPacketSize]; // Space to store a packet when in streaming mode. 965 if (trace_output_mode_ == TraceOutputMode::kStreaming) { 966 ptr = stack_buf; 967 } else { 968 ptr = buf_.get() + old_offset; 969 } 970 971 Append2LE(ptr, thread->GetTid()); 972 Append4LE(ptr + 2, method_value); 973 ptr += 6; 974 975 if (UseThreadCpuClock()) { 976 Append4LE(ptr, thread_clock_diff); 977 ptr += 4; 978 } 979 if (UseWallClock()) { 980 Append4LE(ptr, wall_clock_diff); 981 } 982 static_assert(kPacketSize == 2 + 4 + 4 + 4, "Packet size incorrect."); 983 984 if (trace_output_mode_ == TraceOutputMode::kStreaming) { 985 MutexLock mu(Thread::Current(), *streaming_lock_); // To serialize writing. 986 if (RegisterMethod(method)) { 987 // Write a special block with the name. 988 std::string method_line(GetMethodLine(method)); 989 uint8_t buf2[5]; 990 Append2LE(buf2, 0); 991 buf2[2] = kOpNewMethod; 992 Append2LE(buf2 + 3, static_cast<uint16_t>(method_line.length())); 993 WriteToBuf(buf2, sizeof(buf2)); 994 WriteToBuf(reinterpret_cast<const uint8_t*>(method_line.c_str()), method_line.length()); 995 } 996 if (RegisterThread(thread)) { 997 // It might be better to postpone this. Threads might not have received names... 998 std::string thread_name; 999 thread->GetThreadName(thread_name); 1000 uint8_t buf2[7]; 1001 Append2LE(buf2, 0); 1002 buf2[2] = kOpNewThread; 1003 Append2LE(buf2 + 3, static_cast<uint16_t>(thread->GetTid())); 1004 Append2LE(buf2 + 5, static_cast<uint16_t>(thread_name.length())); 1005 WriteToBuf(buf2, sizeof(buf2)); 1006 WriteToBuf(reinterpret_cast<const uint8_t*>(thread_name.c_str()), thread_name.length()); 1007 } 1008 WriteToBuf(stack_buf, sizeof(stack_buf)); 1009 } 1010} 1011 1012void Trace::GetVisitedMethods(size_t buf_size, 1013 std::set<ArtMethod*>* visited_methods) { 1014 uint8_t* ptr = buf_.get() + kTraceHeaderLength; 1015 uint8_t* end = buf_.get() + buf_size; 1016 1017 while (ptr < end) { 1018 uint32_t tmid = ReadBytes(ptr + 2, sizeof(tmid)); 1019 ArtMethod* method = DecodeTraceMethod(tmid); 1020 visited_methods->insert(method); 1021 ptr += GetRecordSize(clock_source_); 1022 } 1023} 1024 1025void Trace::DumpMethodList(std::ostream& os, const std::set<ArtMethod*>& visited_methods) { 1026 for (const auto& method : visited_methods) { 1027 os << GetMethodLine(method); 1028 } 1029} 1030 1031static void DumpThread(Thread* t, void* arg) { 1032 std::ostream& os = *reinterpret_cast<std::ostream*>(arg); 1033 std::string name; 1034 t->GetThreadName(name); 1035 os << t->GetTid() << "\t" << name << "\n"; 1036} 1037 1038void Trace::DumpThreadList(std::ostream& os) { 1039 Thread* self = Thread::Current(); 1040 for (auto it : exited_threads_) { 1041 os << it.first << "\t" << it.second << "\n"; 1042 } 1043 Locks::thread_list_lock_->AssertNotHeld(self); 1044 MutexLock mu(self, *Locks::thread_list_lock_); 1045 Runtime::Current()->GetThreadList()->ForEach(DumpThread, &os); 1046} 1047 1048void Trace::StoreExitingThreadInfo(Thread* thread) { 1049 MutexLock mu(thread, *Locks::trace_lock_); 1050 if (the_trace_ != nullptr) { 1051 std::string name; 1052 thread->GetThreadName(name); 1053 // The same thread/tid may be used multiple times. As SafeMap::Put does not allow to override 1054 // a previous mapping, use SafeMap::Overwrite. 1055 the_trace_->exited_threads_.Overwrite(thread->GetTid(), name); 1056 } 1057} 1058 1059Trace::TraceOutputMode Trace::GetOutputMode() { 1060 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1061 CHECK(the_trace_ != nullptr) << "Trace output mode requested, but no trace currently running"; 1062 return the_trace_->trace_output_mode_; 1063} 1064 1065Trace::TraceMode Trace::GetMode() { 1066 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1067 CHECK(the_trace_ != nullptr) << "Trace mode requested, but no trace currently running"; 1068 return the_trace_->trace_mode_; 1069} 1070 1071size_t Trace::GetBufferSize() { 1072 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1073 CHECK(the_trace_ != nullptr) << "Trace mode requested, but no trace currently running"; 1074 return the_trace_->buffer_size_; 1075} 1076 1077bool Trace::IsTracingEnabled() { 1078 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1079 return the_trace_ != nullptr; 1080} 1081 1082} // namespace art 1083