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_file-inl.h" 35 #include "gc/scoped_gc_critical_section.h" 36 #include "instrumentation.h" 37 #include "mirror/class-inl.h" 38 #include "mirror/dex_cache-inl.h" 39 #include "mirror/object_array-inl.h" 40 #include "mirror/object-inl.h" 41 #include "os.h" 42 #include "scoped_thread_state_change-inl.h" 43 #include "ScopedLocalRef.h" 44 #include "thread.h" 45 #include "thread_list.h" 46 #include "utils.h" 47 #include "entrypoints/quick/quick_entrypoints.h" 48 49 namespace art { 50 51 using android::base::StringPrintf; 52 53 static constexpr size_t TraceActionBits = MinimumBitsToStore( 54 static_cast<size_t>(kTraceMethodActionMask)); 55 static constexpr uint8_t kOpNewMethod = 1U; 56 static constexpr uint8_t kOpNewThread = 2U; 57 static constexpr uint8_t kOpTraceSummary = 3U; 58 59 class BuildStackTraceVisitor : public StackVisitor { 60 public: 61 explicit BuildStackTraceVisitor(Thread* thread) 62 : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), 63 method_trace_(Trace::AllocStackTrace()) {} 64 65 bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) { 66 ArtMethod* m = GetMethod(); 67 // Ignore runtime frames (in particular callee save). 68 if (!m->IsRuntimeMethod()) { 69 method_trace_->push_back(m); 70 } 71 return true; 72 } 73 74 // Returns a stack trace where the topmost frame corresponds with the first element of the vector. 75 std::vector<ArtMethod*>* GetStackTrace() const { 76 return method_trace_; 77 } 78 79 private: 80 std::vector<ArtMethod*>* const method_trace_; 81 82 DISALLOW_COPY_AND_ASSIGN(BuildStackTraceVisitor); 83 }; 84 85 static const char kTraceTokenChar = '*'; 86 static const uint16_t kTraceHeaderLength = 32; 87 static const uint32_t kTraceMagicValue = 0x574f4c53; 88 static const uint16_t kTraceVersionSingleClock = 2; 89 static const uint16_t kTraceVersionDualClock = 3; 90 static const uint16_t kTraceRecordSizeSingleClock = 10; // using v2 91 static const uint16_t kTraceRecordSizeDualClock = 14; // using v3 with two timestamps 92 93 TraceClockSource Trace::default_clock_source_ = kDefaultTraceClockSource; 94 95 Trace* volatile Trace::the_trace_ = nullptr; 96 pthread_t Trace::sampling_pthread_ = 0U; 97 std::unique_ptr<std::vector<ArtMethod*>> Trace::temp_stack_trace_; 98 99 // The key identifying the tracer to update instrumentation. 100 static constexpr const char* kTracerInstrumentationKey = "Tracer"; 101 102 static TraceAction DecodeTraceAction(uint32_t tmid) { 103 return static_cast<TraceAction>(tmid & kTraceMethodActionMask); 104 } 105 106 ArtMethod* Trace::DecodeTraceMethod(uint32_t tmid) { 107 MutexLock mu(Thread::Current(), *unique_methods_lock_); 108 return unique_methods_[tmid >> TraceActionBits]; 109 } 110 111 uint32_t Trace::EncodeTraceMethod(ArtMethod* method) { 112 MutexLock mu(Thread::Current(), *unique_methods_lock_); 113 uint32_t idx; 114 auto it = art_method_id_map_.find(method); 115 if (it != art_method_id_map_.end()) { 116 idx = it->second; 117 } else { 118 unique_methods_.push_back(method); 119 idx = unique_methods_.size() - 1; 120 art_method_id_map_.emplace(method, idx); 121 } 122 DCHECK_LT(idx, unique_methods_.size()); 123 DCHECK_EQ(unique_methods_[idx], method); 124 return idx; 125 } 126 127 uint32_t Trace::EncodeTraceMethodAndAction(ArtMethod* method, TraceAction action) { 128 uint32_t tmid = (EncodeTraceMethod(method) << TraceActionBits) | action; 129 DCHECK_EQ(method, DecodeTraceMethod(tmid)); 130 return tmid; 131 } 132 133 std::vector<ArtMethod*>* Trace::AllocStackTrace() { 134 return (temp_stack_trace_.get() != nullptr) ? temp_stack_trace_.release() : 135 new std::vector<ArtMethod*>(); 136 } 137 138 void Trace::FreeStackTrace(std::vector<ArtMethod*>* stack_trace) { 139 stack_trace->clear(); 140 temp_stack_trace_.reset(stack_trace); 141 } 142 143 void Trace::SetDefaultClockSource(TraceClockSource clock_source) { 144 #if defined(__linux__) 145 default_clock_source_ = clock_source; 146 #else 147 if (clock_source != TraceClockSource::kWall) { 148 LOG(WARNING) << "Ignoring tracing request to use CPU time."; 149 } 150 #endif 151 } 152 153 static uint16_t GetTraceVersion(TraceClockSource clock_source) { 154 return (clock_source == TraceClockSource::kDual) ? kTraceVersionDualClock 155 : kTraceVersionSingleClock; 156 } 157 158 static uint16_t GetRecordSize(TraceClockSource clock_source) { 159 return (clock_source == TraceClockSource::kDual) ? kTraceRecordSizeDualClock 160 : kTraceRecordSizeSingleClock; 161 } 162 163 bool Trace::UseThreadCpuClock() { 164 return (clock_source_ == TraceClockSource::kThreadCpu) || 165 (clock_source_ == TraceClockSource::kDual); 166 } 167 168 bool Trace::UseWallClock() { 169 return (clock_source_ == TraceClockSource::kWall) || 170 (clock_source_ == TraceClockSource::kDual); 171 } 172 173 void Trace::MeasureClockOverhead() { 174 if (UseThreadCpuClock()) { 175 Thread::Current()->GetCpuMicroTime(); 176 } 177 if (UseWallClock()) { 178 MicroTime(); 179 } 180 } 181 182 // Compute an average time taken to measure clocks. 183 uint32_t Trace::GetClockOverheadNanoSeconds() { 184 Thread* self = Thread::Current(); 185 uint64_t start = self->GetCpuMicroTime(); 186 187 for (int i = 4000; i > 0; i--) { 188 MeasureClockOverhead(); 189 MeasureClockOverhead(); 190 MeasureClockOverhead(); 191 MeasureClockOverhead(); 192 MeasureClockOverhead(); 193 MeasureClockOverhead(); 194 MeasureClockOverhead(); 195 MeasureClockOverhead(); 196 } 197 198 uint64_t elapsed_us = self->GetCpuMicroTime() - start; 199 return static_cast<uint32_t>(elapsed_us / 32); 200 } 201 202 // TODO: put this somewhere with the big-endian equivalent used by JDWP. 203 static void Append2LE(uint8_t* buf, uint16_t val) { 204 *buf++ = static_cast<uint8_t>(val); 205 *buf++ = static_cast<uint8_t>(val >> 8); 206 } 207 208 // TODO: put this somewhere with the big-endian equivalent used by JDWP. 209 static void Append4LE(uint8_t* buf, uint32_t val) { 210 *buf++ = static_cast<uint8_t>(val); 211 *buf++ = static_cast<uint8_t>(val >> 8); 212 *buf++ = static_cast<uint8_t>(val >> 16); 213 *buf++ = static_cast<uint8_t>(val >> 24); 214 } 215 216 // TODO: put this somewhere with the big-endian equivalent used by JDWP. 217 static void Append8LE(uint8_t* buf, uint64_t val) { 218 *buf++ = static_cast<uint8_t>(val); 219 *buf++ = static_cast<uint8_t>(val >> 8); 220 *buf++ = static_cast<uint8_t>(val >> 16); 221 *buf++ = static_cast<uint8_t>(val >> 24); 222 *buf++ = static_cast<uint8_t>(val >> 32); 223 *buf++ = static_cast<uint8_t>(val >> 40); 224 *buf++ = static_cast<uint8_t>(val >> 48); 225 *buf++ = static_cast<uint8_t>(val >> 56); 226 } 227 228 static void GetSample(Thread* thread, void* arg) REQUIRES_SHARED(Locks::mutator_lock_) { 229 BuildStackTraceVisitor build_trace_visitor(thread); 230 build_trace_visitor.WalkStack(); 231 std::vector<ArtMethod*>* stack_trace = build_trace_visitor.GetStackTrace(); 232 Trace* the_trace = reinterpret_cast<Trace*>(arg); 233 the_trace->CompareAndUpdateStackTrace(thread, stack_trace); 234 } 235 236 static void ClearThreadStackTraceAndClockBase(Thread* thread, void* arg ATTRIBUTE_UNUSED) { 237 thread->SetTraceClockBase(0); 238 std::vector<ArtMethod*>* stack_trace = thread->GetStackTraceSample(); 239 thread->SetStackTraceSample(nullptr); 240 delete stack_trace; 241 } 242 243 void Trace::CompareAndUpdateStackTrace(Thread* thread, 244 std::vector<ArtMethod*>* stack_trace) { 245 CHECK_EQ(pthread_self(), sampling_pthread_); 246 std::vector<ArtMethod*>* old_stack_trace = thread->GetStackTraceSample(); 247 // Update the thread's stack trace sample. 248 thread->SetStackTraceSample(stack_trace); 249 // Read timer clocks to use for all events in this trace. 250 uint32_t thread_clock_diff = 0; 251 uint32_t wall_clock_diff = 0; 252 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 253 if (old_stack_trace == nullptr) { 254 // If there's no previous stack trace sample for this thread, log an entry event for all 255 // methods in the trace. 256 for (auto rit = stack_trace->rbegin(); rit != stack_trace->rend(); ++rit) { 257 LogMethodTraceEvent(thread, *rit, instrumentation::Instrumentation::kMethodEntered, 258 thread_clock_diff, wall_clock_diff); 259 } 260 } else { 261 // If there's a previous stack trace for this thread, diff the traces and emit entry and exit 262 // events accordingly. 263 auto old_rit = old_stack_trace->rbegin(); 264 auto rit = stack_trace->rbegin(); 265 // Iterate bottom-up over both traces until there's a difference between them. 266 while (old_rit != old_stack_trace->rend() && rit != stack_trace->rend() && *old_rit == *rit) { 267 old_rit++; 268 rit++; 269 } 270 // Iterate top-down over the old trace until the point where they differ, emitting exit events. 271 for (auto old_it = old_stack_trace->begin(); old_it != old_rit.base(); ++old_it) { 272 LogMethodTraceEvent(thread, *old_it, instrumentation::Instrumentation::kMethodExited, 273 thread_clock_diff, wall_clock_diff); 274 } 275 // Iterate bottom-up over the new trace from the point where they differ, emitting entry events. 276 for (; rit != stack_trace->rend(); ++rit) { 277 LogMethodTraceEvent(thread, *rit, instrumentation::Instrumentation::kMethodEntered, 278 thread_clock_diff, wall_clock_diff); 279 } 280 FreeStackTrace(old_stack_trace); 281 } 282 } 283 284 void* Trace::RunSamplingThread(void* arg) { 285 Runtime* runtime = Runtime::Current(); 286 intptr_t interval_us = reinterpret_cast<intptr_t>(arg); 287 CHECK_GE(interval_us, 0); 288 CHECK(runtime->AttachCurrentThread("Sampling Profiler", true, runtime->GetSystemThreadGroup(), 289 !runtime->IsAotCompiler())); 290 291 while (true) { 292 usleep(interval_us); 293 ScopedTrace trace("Profile sampling"); 294 Thread* self = Thread::Current(); 295 Trace* the_trace; 296 { 297 MutexLock mu(self, *Locks::trace_lock_); 298 the_trace = the_trace_; 299 if (the_trace == nullptr) { 300 break; 301 } 302 } 303 { 304 ScopedSuspendAll ssa(__FUNCTION__); 305 MutexLock mu(self, *Locks::thread_list_lock_); 306 runtime->GetThreadList()->ForEach(GetSample, the_trace); 307 } 308 } 309 310 runtime->DetachCurrentThread(); 311 return nullptr; 312 } 313 314 void Trace::Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags, 315 TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) { 316 Thread* self = Thread::Current(); 317 { 318 MutexLock mu(self, *Locks::trace_lock_); 319 if (the_trace_ != nullptr) { 320 LOG(ERROR) << "Trace already in progress, ignoring this request"; 321 return; 322 } 323 } 324 325 // Check interval if sampling is enabled 326 if (trace_mode == TraceMode::kSampling && interval_us <= 0) { 327 LOG(ERROR) << "Invalid sampling interval: " << interval_us; 328 ScopedObjectAccess soa(self); 329 ThrowRuntimeException("Invalid sampling interval: %d", interval_us); 330 return; 331 } 332 333 // Open trace file if not going directly to ddms. 334 std::unique_ptr<File> trace_file; 335 if (output_mode != TraceOutputMode::kDDMS) { 336 if (trace_fd < 0) { 337 trace_file.reset(OS::CreateEmptyFileWriteOnly(trace_filename)); 338 } else { 339 trace_file.reset(new File(trace_fd, "tracefile")); 340 trace_file->DisableAutoClose(); 341 } 342 if (trace_file.get() == nullptr) { 343 PLOG(ERROR) << "Unable to open trace file '" << trace_filename << "'"; 344 ScopedObjectAccess soa(self); 345 ThrowRuntimeException("Unable to open trace file '%s'", trace_filename); 346 return; 347 } 348 } 349 350 Runtime* runtime = Runtime::Current(); 351 352 // Enable count of allocs if specified in the flags. 353 bool enable_stats = false; 354 355 // Create Trace object. 356 { 357 // Required since EnableMethodTracing calls ConfigureStubs which visits class linker classes. 358 gc::ScopedGCCriticalSection gcs(self, 359 gc::kGcCauseInstrumentation, 360 gc::kCollectorTypeInstrumentation); 361 ScopedSuspendAll ssa(__FUNCTION__); 362 MutexLock mu(self, *Locks::trace_lock_); 363 if (the_trace_ != nullptr) { 364 LOG(ERROR) << "Trace already in progress, ignoring this request"; 365 } else { 366 enable_stats = (flags && kTraceCountAllocs) != 0; 367 the_trace_ = new Trace(trace_file.release(), trace_filename, buffer_size, flags, output_mode, 368 trace_mode); 369 if (trace_mode == TraceMode::kSampling) { 370 CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, nullptr, &RunSamplingThread, 371 reinterpret_cast<void*>(interval_us)), 372 "Sampling profiler thread"); 373 the_trace_->interval_us_ = interval_us; 374 } else { 375 runtime->GetInstrumentation()->AddListener(the_trace_, 376 instrumentation::Instrumentation::kMethodEntered | 377 instrumentation::Instrumentation::kMethodExited | 378 instrumentation::Instrumentation::kMethodUnwind); 379 // TODO: In full-PIC mode, we don't need to fully deopt. 380 runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey); 381 } 382 } 383 } 384 385 // Can't call this when holding the mutator lock. 386 if (enable_stats) { 387 runtime->SetStatsEnabled(true); 388 } 389 } 390 391 void Trace::StopTracing(bool finish_tracing, bool flush_file) { 392 bool stop_alloc_counting = false; 393 Runtime* const runtime = Runtime::Current(); 394 Trace* the_trace = nullptr; 395 Thread* const self = Thread::Current(); 396 pthread_t sampling_pthread = 0U; 397 { 398 MutexLock mu(self, *Locks::trace_lock_); 399 if (the_trace_ == nullptr) { 400 LOG(ERROR) << "Trace stop requested, but no trace currently running"; 401 } else { 402 the_trace = the_trace_; 403 the_trace_ = nullptr; 404 sampling_pthread = sampling_pthread_; 405 } 406 } 407 // Make sure that we join before we delete the trace since we don't want to have 408 // the sampling thread access a stale pointer. This finishes since the sampling thread exits when 409 // the_trace_ is null. 410 if (sampling_pthread != 0U) { 411 CHECK_PTHREAD_CALL(pthread_join, (sampling_pthread, nullptr), "sampling thread shutdown"); 412 sampling_pthread_ = 0U; 413 } 414 415 { 416 gc::ScopedGCCriticalSection gcs(self, 417 gc::kGcCauseInstrumentation, 418 gc::kCollectorTypeInstrumentation); 419 ScopedSuspendAll ssa(__FUNCTION__); 420 if (the_trace != nullptr) { 421 stop_alloc_counting = (the_trace->flags_ & Trace::kTraceCountAllocs) != 0; 422 if (finish_tracing) { 423 the_trace->FinishTracing(); 424 } 425 426 if (the_trace->trace_mode_ == TraceMode::kSampling) { 427 MutexLock mu(self, *Locks::thread_list_lock_); 428 runtime->GetThreadList()->ForEach(ClearThreadStackTraceAndClockBase, nullptr); 429 } else { 430 runtime->GetInstrumentation()->DisableMethodTracing(kTracerInstrumentationKey); 431 runtime->GetInstrumentation()->RemoveListener( 432 the_trace, instrumentation::Instrumentation::kMethodEntered | 433 instrumentation::Instrumentation::kMethodExited | 434 instrumentation::Instrumentation::kMethodUnwind); 435 } 436 if (the_trace->trace_file_.get() != nullptr) { 437 // Do not try to erase, so flush and close explicitly. 438 if (flush_file) { 439 if (the_trace->trace_file_->Flush() != 0) { 440 PLOG(WARNING) << "Could not flush trace file."; 441 } 442 } else { 443 the_trace->trace_file_->MarkUnchecked(); // Do not trigger guard. 444 } 445 if (the_trace->trace_file_->Close() != 0) { 446 PLOG(ERROR) << "Could not close trace file."; 447 } 448 } 449 delete the_trace; 450 } 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 458 void Trace::Abort() { 459 // Do not write anything anymore. 460 StopTracing(false, false); 461 } 462 463 void Trace::Stop() { 464 // Finish writing. 465 StopTracing(true, true); 466 } 467 468 void Trace::Shutdown() { 469 if (GetMethodTracingMode() != kTracingInactive) { 470 Stop(); 471 } 472 } 473 474 void 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 531 void 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 574 TracingMode 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 590 static constexpr size_t kMinBufSize = 18U; // Trace header is up to 18B. 591 592 Trace::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 628 Trace::~Trace() { 629 delete streaming_lock_; 630 delete unique_methods_lock_; 631 } 632 633 static 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 641 void 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 654 void 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 iovec iov[2]; 720 iov[0].iov_base = reinterpret_cast<void*>(const_cast<char*>(header.c_str())); 721 iov[0].iov_len = header.length(); 722 iov[1].iov_base = buf_.get(); 723 iov[1].iov_len = final_offset; 724 Dbg::DdmSendChunkV(CHUNK_TYPE("MPSE"), iov, 2); 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 741 void Trace::DexPcMoved(Thread* thread ATTRIBUTE_UNUSED, 742 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 750 void Trace::FieldRead(Thread* thread ATTRIBUTE_UNUSED, 751 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 761 void Trace::FieldWritten(Thread* thread ATTRIBUTE_UNUSED, 762 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 773 void Trace::MethodEntered(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED, 774 ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) { 775 uint32_t thread_clock_diff = 0; 776 uint32_t wall_clock_diff = 0; 777 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 778 LogMethodTraceEvent(thread, method, instrumentation::Instrumentation::kMethodEntered, 779 thread_clock_diff, wall_clock_diff); 780 } 781 782 void Trace::MethodExited(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED, 783 ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED, 784 const JValue& return_value ATTRIBUTE_UNUSED) { 785 uint32_t thread_clock_diff = 0; 786 uint32_t wall_clock_diff = 0; 787 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 788 LogMethodTraceEvent(thread, method, instrumentation::Instrumentation::kMethodExited, 789 thread_clock_diff, wall_clock_diff); 790 } 791 792 void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED, 793 ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) { 794 uint32_t thread_clock_diff = 0; 795 uint32_t wall_clock_diff = 0; 796 ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); 797 LogMethodTraceEvent(thread, method, instrumentation::Instrumentation::kMethodUnwind, 798 thread_clock_diff, wall_clock_diff); 799 } 800 801 void Trace::ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, 802 mirror::Throwable* exception_object ATTRIBUTE_UNUSED) 803 REQUIRES_SHARED(Locks::mutator_lock_) { 804 LOG(ERROR) << "Unexpected exception caught event in tracing"; 805 } 806 807 void Trace::Branch(Thread* /*thread*/, ArtMethod* method, 808 uint32_t /*dex_pc*/, int32_t /*dex_pc_offset*/) 809 REQUIRES_SHARED(Locks::mutator_lock_) { 810 LOG(ERROR) << "Unexpected branch event in tracing" << ArtMethod::PrettyMethod(method); 811 } 812 813 void Trace::InvokeVirtualOrInterface(Thread*, 814 mirror::Object*, 815 ArtMethod* method, 816 uint32_t dex_pc, 817 ArtMethod*) { 818 LOG(ERROR) << "Unexpected invoke event in tracing" << ArtMethod::PrettyMethod(method) 819 << " " << dex_pc; 820 } 821 822 void Trace::ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wall_clock_diff) { 823 if (UseThreadCpuClock()) { 824 uint64_t clock_base = thread->GetTraceClockBase(); 825 if (UNLIKELY(clock_base == 0)) { 826 // First event, record the base time in the map. 827 uint64_t time = thread->GetCpuMicroTime(); 828 thread->SetTraceClockBase(time); 829 } else { 830 *thread_clock_diff = thread->GetCpuMicroTime() - clock_base; 831 } 832 } 833 if (UseWallClock()) { 834 *wall_clock_diff = MicroTime() - start_time_; 835 } 836 } 837 838 bool Trace::RegisterMethod(ArtMethod* method) { 839 mirror::DexCache* dex_cache = method->GetDexCache(); 840 const DexFile* dex_file = dex_cache->GetDexFile(); 841 if (seen_methods_.find(dex_file) == seen_methods_.end()) { 842 seen_methods_.insert(std::make_pair(dex_file, new DexIndexBitSet())); 843 } 844 DexIndexBitSet* bit_set = seen_methods_.find(dex_file)->second; 845 if (!(*bit_set)[method->GetDexMethodIndex()]) { 846 bit_set->set(method->GetDexMethodIndex()); 847 return true; 848 } 849 return false; 850 } 851 852 bool Trace::RegisterThread(Thread* thread) { 853 pid_t tid = thread->GetTid(); 854 CHECK_LT(0U, static_cast<uint32_t>(tid)); 855 CHECK_LT(static_cast<uint32_t>(tid), kMaxThreadIdNumber); 856 857 if (!(*seen_threads_)[tid]) { 858 seen_threads_->set(tid); 859 return true; 860 } 861 return false; 862 } 863 864 std::string Trace::GetMethodLine(ArtMethod* method) { 865 method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); 866 return StringPrintf("%#x\t%s\t%s\t%s\t%s\n", (EncodeTraceMethod(method) << TraceActionBits), 867 PrettyDescriptor(method->GetDeclaringClassDescriptor()).c_str(), method->GetName(), 868 method->GetSignature().ToString().c_str(), method->GetDeclaringClassSourceFile()); 869 } 870 871 void Trace::WriteToBuf(const uint8_t* src, size_t src_size) { 872 int32_t old_offset = cur_offset_.LoadRelaxed(); 873 int32_t new_offset = old_offset + static_cast<int32_t>(src_size); 874 if (dchecked_integral_cast<size_t>(new_offset) > buffer_size_) { 875 // Flush buffer. 876 if (!trace_file_->WriteFully(buf_.get(), old_offset)) { 877 PLOG(WARNING) << "Failed streaming a tracing event."; 878 } 879 880 // Check whether the data is too large for the buffer, then write immediately. 881 if (src_size >= buffer_size_) { 882 if (!trace_file_->WriteFully(src, src_size)) { 883 PLOG(WARNING) << "Failed streaming a tracing event."; 884 } 885 cur_offset_.StoreRelease(0); // Buffer is empty now. 886 return; 887 } 888 889 old_offset = 0; 890 new_offset = static_cast<int32_t>(src_size); 891 } 892 cur_offset_.StoreRelease(new_offset); 893 // Fill in data. 894 memcpy(buf_.get() + old_offset, src, src_size); 895 } 896 897 void Trace::FlushBuf() { 898 int32_t offset = cur_offset_.LoadRelaxed(); 899 if (!trace_file_->WriteFully(buf_.get(), offset)) { 900 PLOG(WARNING) << "Failed flush the remaining data in streaming."; 901 } 902 cur_offset_.StoreRelease(0); 903 } 904 905 void Trace::LogMethodTraceEvent(Thread* thread, ArtMethod* method, 906 instrumentation::Instrumentation::InstrumentationEvent event, 907 uint32_t thread_clock_diff, uint32_t wall_clock_diff) { 908 // Ensure we always use the non-obsolete version of the method so that entry/exit events have the 909 // same pointer value. 910 method = method->GetNonObsoleteMethod(); 911 // Advance cur_offset_ atomically. 912 int32_t new_offset; 913 int32_t old_offset = 0; 914 915 // We do a busy loop here trying to acquire the next offset. 916 if (trace_output_mode_ != TraceOutputMode::kStreaming) { 917 do { 918 old_offset = cur_offset_.LoadRelaxed(); 919 new_offset = old_offset + GetRecordSize(clock_source_); 920 if (static_cast<size_t>(new_offset) > buffer_size_) { 921 overflow_ = true; 922 return; 923 } 924 } while (!cur_offset_.CompareExchangeWeakSequentiallyConsistent(old_offset, new_offset)); 925 } 926 927 TraceAction action = kTraceMethodEnter; 928 switch (event) { 929 case instrumentation::Instrumentation::kMethodEntered: 930 action = kTraceMethodEnter; 931 break; 932 case instrumentation::Instrumentation::kMethodExited: 933 action = kTraceMethodExit; 934 break; 935 case instrumentation::Instrumentation::kMethodUnwind: 936 action = kTraceUnroll; 937 break; 938 default: 939 UNIMPLEMENTED(FATAL) << "Unexpected event: " << event; 940 } 941 942 uint32_t method_value = EncodeTraceMethodAndAction(method, action); 943 944 // Write data 945 uint8_t* ptr; 946 static constexpr size_t kPacketSize = 14U; // The maximum size of data in a packet. 947 uint8_t stack_buf[kPacketSize]; // Space to store a packet when in streaming mode. 948 if (trace_output_mode_ == TraceOutputMode::kStreaming) { 949 ptr = stack_buf; 950 } else { 951 ptr = buf_.get() + old_offset; 952 } 953 954 Append2LE(ptr, thread->GetTid()); 955 Append4LE(ptr + 2, method_value); 956 ptr += 6; 957 958 if (UseThreadCpuClock()) { 959 Append4LE(ptr, thread_clock_diff); 960 ptr += 4; 961 } 962 if (UseWallClock()) { 963 Append4LE(ptr, wall_clock_diff); 964 } 965 static_assert(kPacketSize == 2 + 4 + 4 + 4, "Packet size incorrect."); 966 967 if (trace_output_mode_ == TraceOutputMode::kStreaming) { 968 MutexLock mu(Thread::Current(), *streaming_lock_); // To serialize writing. 969 if (RegisterMethod(method)) { 970 // Write a special block with the name. 971 std::string method_line(GetMethodLine(method)); 972 uint8_t buf2[5]; 973 Append2LE(buf2, 0); 974 buf2[2] = kOpNewMethod; 975 Append2LE(buf2 + 3, static_cast<uint16_t>(method_line.length())); 976 WriteToBuf(buf2, sizeof(buf2)); 977 WriteToBuf(reinterpret_cast<const uint8_t*>(method_line.c_str()), method_line.length()); 978 } 979 if (RegisterThread(thread)) { 980 // It might be better to postpone this. Threads might not have received names... 981 std::string thread_name; 982 thread->GetThreadName(thread_name); 983 uint8_t buf2[7]; 984 Append2LE(buf2, 0); 985 buf2[2] = kOpNewThread; 986 Append2LE(buf2 + 3, static_cast<uint16_t>(thread->GetTid())); 987 Append2LE(buf2 + 5, static_cast<uint16_t>(thread_name.length())); 988 WriteToBuf(buf2, sizeof(buf2)); 989 WriteToBuf(reinterpret_cast<const uint8_t*>(thread_name.c_str()), thread_name.length()); 990 } 991 WriteToBuf(stack_buf, sizeof(stack_buf)); 992 } 993 } 994 995 void Trace::GetVisitedMethods(size_t buf_size, 996 std::set<ArtMethod*>* visited_methods) { 997 uint8_t* ptr = buf_.get() + kTraceHeaderLength; 998 uint8_t* end = buf_.get() + buf_size; 999 1000 while (ptr < end) { 1001 uint32_t tmid = ReadBytes(ptr + 2, sizeof(tmid)); 1002 ArtMethod* method = DecodeTraceMethod(tmid); 1003 visited_methods->insert(method); 1004 ptr += GetRecordSize(clock_source_); 1005 } 1006 } 1007 1008 void Trace::DumpMethodList(std::ostream& os, const std::set<ArtMethod*>& visited_methods) { 1009 for (const auto& method : visited_methods) { 1010 os << GetMethodLine(method); 1011 } 1012 } 1013 1014 static void DumpThread(Thread* t, void* arg) { 1015 std::ostream& os = *reinterpret_cast<std::ostream*>(arg); 1016 std::string name; 1017 t->GetThreadName(name); 1018 os << t->GetTid() << "\t" << name << "\n"; 1019 } 1020 1021 void Trace::DumpThreadList(std::ostream& os) { 1022 Thread* self = Thread::Current(); 1023 for (auto it : exited_threads_) { 1024 os << it.first << "\t" << it.second << "\n"; 1025 } 1026 Locks::thread_list_lock_->AssertNotHeld(self); 1027 MutexLock mu(self, *Locks::thread_list_lock_); 1028 Runtime::Current()->GetThreadList()->ForEach(DumpThread, &os); 1029 } 1030 1031 void Trace::StoreExitingThreadInfo(Thread* thread) { 1032 MutexLock mu(thread, *Locks::trace_lock_); 1033 if (the_trace_ != nullptr) { 1034 std::string name; 1035 thread->GetThreadName(name); 1036 // The same thread/tid may be used multiple times. As SafeMap::Put does not allow to override 1037 // a previous mapping, use SafeMap::Overwrite. 1038 the_trace_->exited_threads_.Overwrite(thread->GetTid(), name); 1039 } 1040 } 1041 1042 Trace::TraceOutputMode Trace::GetOutputMode() { 1043 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1044 CHECK(the_trace_ != nullptr) << "Trace output mode requested, but no trace currently running"; 1045 return the_trace_->trace_output_mode_; 1046 } 1047 1048 Trace::TraceMode Trace::GetMode() { 1049 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1050 CHECK(the_trace_ != nullptr) << "Trace mode requested, but no trace currently running"; 1051 return the_trace_->trace_mode_; 1052 } 1053 1054 size_t Trace::GetBufferSize() { 1055 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1056 CHECK(the_trace_ != nullptr) << "Trace mode requested, but no trace currently running"; 1057 return the_trace_->buffer_size_; 1058 } 1059 1060 bool Trace::IsTracingEnabled() { 1061 MutexLock mu(Thread::Current(), *Locks::trace_lock_); 1062 return the_trace_ != nullptr; 1063 } 1064 1065 } // namespace art 1066