1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/trace_event/trace_log.h" 6 7 #include <algorithm> 8 #include <cmath> 9 #include <utility> 10 11 #include "base/base_switches.h" 12 #include "base/bind.h" 13 #include "base/command_line.h" 14 #include "base/lazy_instance.h" 15 #include "base/location.h" 16 #include "base/macros.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/memory/singleton.h" 19 #include "base/process/process_metrics.h" 20 #include "base/stl_util.h" 21 #include "base/strings/string_split.h" 22 #include "base/strings/string_tokenizer.h" 23 #include "base/strings/stringprintf.h" 24 #include "base/sys_info.h" 25 #include "base/thread_task_runner_handle.h" 26 #include "base/threading/platform_thread.h" 27 #include "base/threading/thread_id_name_manager.h" 28 #include "base/threading/worker_pool.h" 29 #include "base/time/time.h" 30 #include "base/trace_event/heap_profiler_allocation_context_tracker.h" 31 #include "base/trace_event/memory_dump_manager.h" 32 #include "base/trace_event/memory_dump_provider.h" 33 #include "base/trace_event/process_memory_dump.h" 34 #include "base/trace_event/trace_buffer.h" 35 #include "base/trace_event/trace_event.h" 36 #include "base/trace_event/trace_event_synthetic_delay.h" 37 #include "base/trace_event/trace_sampling_thread.h" 38 #include "build/build_config.h" 39 40 #if defined(OS_WIN) 41 #include "base/trace_event/trace_event_etw_export_win.h" 42 #endif 43 44 // The thread buckets for the sampling profiler. 45 BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3]; 46 47 namespace base { 48 namespace internal { 49 50 class DeleteTraceLogForTesting { 51 public: 52 static void Delete() { 53 Singleton<trace_event::TraceLog, 54 LeakySingletonTraits<trace_event::TraceLog>>::OnExit(0); 55 } 56 }; 57 58 } // namespace internal 59 60 namespace trace_event { 61 62 namespace { 63 64 // Controls the number of trace events we will buffer in-memory 65 // before throwing them away. 66 const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize; 67 68 const size_t kTraceEventVectorBigBufferChunks = 69 512000000 / kTraceBufferChunkSize; 70 static_assert( 71 kTraceEventVectorBigBufferChunks <= TraceBufferChunk::kMaxChunkIndex, 72 "Too many big buffer chunks"); 73 const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize; 74 static_assert( 75 kTraceEventVectorBufferChunks <= TraceBufferChunk::kMaxChunkIndex, 76 "Too many vector buffer chunks"); 77 const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4; 78 79 // Can store results for 30 seconds with 1 ms sampling interval. 80 const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize; 81 // ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events. 82 const size_t kEchoToConsoleTraceEventBufferChunks = 256; 83 84 const size_t kTraceEventBufferSizeInBytes = 100 * 1024; 85 const int kThreadFlushTimeoutMs = 3000; 86 87 #define MAX_CATEGORY_GROUPS 100 88 89 // Parallel arrays g_category_groups and g_category_group_enabled are separate 90 // so that a pointer to a member of g_category_group_enabled can be easily 91 // converted to an index into g_category_groups. This allows macros to deal 92 // only with char enabled pointers from g_category_group_enabled, and we can 93 // convert internally to determine the category name from the char enabled 94 // pointer. 95 const char* g_category_groups[MAX_CATEGORY_GROUPS] = { 96 "toplevel", 97 "tracing already shutdown", 98 "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS", 99 "__metadata"}; 100 101 // The enabled flag is char instead of bool so that the API can be used from C. 102 unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0}; 103 // Indexes here have to match the g_category_groups array indexes above. 104 const int g_category_already_shutdown = 1; 105 const int g_category_categories_exhausted = 2; 106 const int g_category_metadata = 3; 107 const int g_num_builtin_categories = 4; 108 // Skip default categories. 109 base::subtle::AtomicWord g_category_index = g_num_builtin_categories; 110 111 // The name of the current thread. This is used to decide if the current 112 // thread name has changed. We combine all the seen thread names into the 113 // output name for the thread. 114 LazyInstance<ThreadLocalPointer<const char>>::Leaky g_current_thread_name = 115 LAZY_INSTANCE_INITIALIZER; 116 117 ThreadTicks ThreadNow() { 118 return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks(); 119 } 120 121 template <typename T> 122 void InitializeMetadataEvent(TraceEvent* trace_event, 123 int thread_id, 124 const char* metadata_name, 125 const char* arg_name, 126 const T& value) { 127 if (!trace_event) 128 return; 129 130 int num_args = 1; 131 unsigned char arg_type; 132 unsigned long long arg_value; 133 ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value); 134 trace_event->Initialize( 135 thread_id, 136 TimeTicks(), 137 ThreadTicks(), 138 TRACE_EVENT_PHASE_METADATA, 139 &g_category_group_enabled[g_category_metadata], 140 metadata_name, 141 trace_event_internal::kNoId, // id 142 trace_event_internal::kNoId, // bind_id 143 num_args, 144 &arg_name, 145 &arg_type, 146 &arg_value, 147 nullptr, 148 TRACE_EVENT_FLAG_NONE); 149 } 150 151 class AutoThreadLocalBoolean { 152 public: 153 explicit AutoThreadLocalBoolean(ThreadLocalBoolean* thread_local_boolean) 154 : thread_local_boolean_(thread_local_boolean) { 155 DCHECK(!thread_local_boolean_->Get()); 156 thread_local_boolean_->Set(true); 157 } 158 ~AutoThreadLocalBoolean() { thread_local_boolean_->Set(false); } 159 160 private: 161 ThreadLocalBoolean* thread_local_boolean_; 162 DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean); 163 }; 164 165 // Use this function instead of TraceEventHandle constructor to keep the 166 // overhead of ScopedTracer (trace_event.h) constructor minimum. 167 void MakeHandle(uint32_t chunk_seq, 168 size_t chunk_index, 169 size_t event_index, 170 TraceEventHandle* handle) { 171 DCHECK(chunk_seq); 172 DCHECK(chunk_index <= TraceBufferChunk::kMaxChunkIndex); 173 DCHECK(event_index < TraceBufferChunk::kTraceBufferChunkSize); 174 handle->chunk_seq = chunk_seq; 175 handle->chunk_index = static_cast<uint16_t>(chunk_index); 176 handle->event_index = static_cast<uint16_t>(event_index); 177 } 178 179 } // namespace 180 181 // A helper class that allows the lock to be acquired in the middle of the scope 182 // and unlocks at the end of scope if locked. 183 class TraceLog::OptionalAutoLock { 184 public: 185 explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {} 186 187 ~OptionalAutoLock() { 188 if (locked_) 189 lock_->Release(); 190 } 191 192 void EnsureAcquired() { 193 if (!locked_) { 194 lock_->Acquire(); 195 locked_ = true; 196 } 197 } 198 199 private: 200 Lock* lock_; 201 bool locked_; 202 DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock); 203 }; 204 205 class TraceLog::ThreadLocalEventBuffer 206 : public MessageLoop::DestructionObserver, 207 public MemoryDumpProvider { 208 public: 209 explicit ThreadLocalEventBuffer(TraceLog* trace_log); 210 ~ThreadLocalEventBuffer() override; 211 212 TraceEvent* AddTraceEvent(TraceEventHandle* handle); 213 214 TraceEvent* GetEventByHandle(TraceEventHandle handle) { 215 if (!chunk_ || handle.chunk_seq != chunk_->seq() || 216 handle.chunk_index != chunk_index_) { 217 return nullptr; 218 } 219 220 return chunk_->GetEventAt(handle.event_index); 221 } 222 223 int generation() const { return generation_; } 224 225 private: 226 // MessageLoop::DestructionObserver 227 void WillDestroyCurrentMessageLoop() override; 228 229 // MemoryDumpProvider implementation. 230 bool OnMemoryDump(const MemoryDumpArgs& args, 231 ProcessMemoryDump* pmd) override; 232 233 void FlushWhileLocked(); 234 235 void CheckThisIsCurrentBuffer() const { 236 DCHECK(trace_log_->thread_local_event_buffer_.Get() == this); 237 } 238 239 // Since TraceLog is a leaky singleton, trace_log_ will always be valid 240 // as long as the thread exists. 241 TraceLog* trace_log_; 242 scoped_ptr<TraceBufferChunk> chunk_; 243 size_t chunk_index_; 244 int generation_; 245 246 DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer); 247 }; 248 249 TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log) 250 : trace_log_(trace_log), 251 chunk_index_(0), 252 generation_(trace_log->generation()) { 253 // ThreadLocalEventBuffer is created only if the thread has a message loop, so 254 // the following message_loop won't be NULL. 255 MessageLoop* message_loop = MessageLoop::current(); 256 message_loop->AddDestructionObserver(this); 257 258 // This is to report the local memory usage when memory-infra is enabled. 259 MemoryDumpManager::GetInstance()->RegisterDumpProvider( 260 this, "ThreadLocalEventBuffer", ThreadTaskRunnerHandle::Get()); 261 262 AutoLock lock(trace_log->lock_); 263 trace_log->thread_message_loops_.insert(message_loop); 264 } 265 266 TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() { 267 CheckThisIsCurrentBuffer(); 268 MessageLoop::current()->RemoveDestructionObserver(this); 269 MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this); 270 271 { 272 AutoLock lock(trace_log_->lock_); 273 FlushWhileLocked(); 274 trace_log_->thread_message_loops_.erase(MessageLoop::current()); 275 } 276 trace_log_->thread_local_event_buffer_.Set(NULL); 277 } 278 279 TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent( 280 TraceEventHandle* handle) { 281 CheckThisIsCurrentBuffer(); 282 283 if (chunk_ && chunk_->IsFull()) { 284 AutoLock lock(trace_log_->lock_); 285 FlushWhileLocked(); 286 chunk_.reset(); 287 } 288 if (!chunk_) { 289 AutoLock lock(trace_log_->lock_); 290 chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_); 291 trace_log_->CheckIfBufferIsFullWhileLocked(); 292 } 293 if (!chunk_) 294 return NULL; 295 296 size_t event_index; 297 TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index); 298 if (trace_event && handle) 299 MakeHandle(chunk_->seq(), chunk_index_, event_index, handle); 300 301 return trace_event; 302 } 303 304 void TraceLog::ThreadLocalEventBuffer::WillDestroyCurrentMessageLoop() { 305 delete this; 306 } 307 308 bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump( 309 const MemoryDumpArgs& /* args */, 310 ProcessMemoryDump* pmd) { 311 if (!chunk_) 312 return true; 313 std::string dump_base_name = StringPrintf( 314 "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId())); 315 TraceEventMemoryOverhead overhead; 316 chunk_->EstimateTraceMemoryOverhead(&overhead); 317 overhead.DumpInto(dump_base_name.c_str(), pmd); 318 return true; 319 } 320 321 void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() { 322 if (!chunk_) 323 return; 324 325 trace_log_->lock_.AssertAcquired(); 326 if (trace_log_->CheckGeneration(generation_)) { 327 // Return the chunk to the buffer only if the generation matches. 328 trace_log_->logged_events_->ReturnChunk(chunk_index_, std::move(chunk_)); 329 } 330 // Otherwise this method may be called from the destructor, or TraceLog will 331 // find the generation mismatch and delete this buffer soon. 332 } 333 334 TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {} 335 336 TraceLogStatus::~TraceLogStatus() {} 337 338 // static 339 TraceLog* TraceLog::GetInstance() { 340 return Singleton<TraceLog, LeakySingletonTraits<TraceLog>>::get(); 341 } 342 343 TraceLog::TraceLog() 344 : mode_(DISABLED), 345 num_traces_recorded_(0), 346 event_callback_(0), 347 dispatching_to_observer_list_(false), 348 process_sort_index_(0), 349 process_id_hash_(0), 350 process_id_(0), 351 watch_category_(0), 352 trace_options_(kInternalRecordUntilFull), 353 sampling_thread_handle_(0), 354 trace_config_(TraceConfig()), 355 event_callback_trace_config_(TraceConfig()), 356 thread_shared_chunk_index_(0), 357 generation_(0), 358 use_worker_thread_(false) { 359 // Trace is enabled or disabled on one thread while other threads are 360 // accessing the enabled flag. We don't care whether edge-case events are 361 // traced or not, so we allow races on the enabled flag to keep the trace 362 // macros fast. 363 // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots: 364 // ANNOTATE_BENIGN_RACE_SIZED(g_category_group_enabled, 365 // sizeof(g_category_group_enabled), 366 // "trace_event category enabled"); 367 #if defined(OS_NACL) // NaCl shouldn't expose the process id. 368 SetProcessID(0); 369 #else 370 SetProcessID(static_cast<int>(GetCurrentProcId())); 371 #endif 372 373 logged_events_.reset(CreateTraceBuffer()); 374 375 MemoryDumpManager::GetInstance()->RegisterDumpProvider(this, "TraceLog", 376 nullptr); 377 } 378 379 TraceLog::~TraceLog() {} 380 381 void TraceLog::InitializeThreadLocalEventBufferIfSupported() { 382 // A ThreadLocalEventBuffer needs the message loop 383 // - to know when the thread exits; 384 // - to handle the final flush. 385 // For a thread without a message loop or the message loop may be blocked, the 386 // trace events will be added into the main buffer directly. 387 if (thread_blocks_message_loop_.Get() || !MessageLoop::current()) 388 return; 389 auto thread_local_event_buffer = thread_local_event_buffer_.Get(); 390 if (thread_local_event_buffer && 391 !CheckGeneration(thread_local_event_buffer->generation())) { 392 delete thread_local_event_buffer; 393 thread_local_event_buffer = NULL; 394 } 395 if (!thread_local_event_buffer) { 396 thread_local_event_buffer = new ThreadLocalEventBuffer(this); 397 thread_local_event_buffer_.Set(thread_local_event_buffer); 398 } 399 } 400 401 bool TraceLog::OnMemoryDump(const MemoryDumpArgs& /* args */, 402 ProcessMemoryDump* pmd) { 403 // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested 404 // (crbug.com/499731). 405 TraceEventMemoryOverhead overhead; 406 overhead.Add("TraceLog", sizeof(*this)); 407 { 408 AutoLock lock(lock_); 409 if (logged_events_) 410 logged_events_->EstimateTraceMemoryOverhead(&overhead); 411 412 for (auto& metadata_event : metadata_events_) 413 metadata_event->EstimateTraceMemoryOverhead(&overhead); 414 } 415 overhead.AddSelf(); 416 overhead.DumpInto("tracing/main_trace_log", pmd); 417 return true; 418 } 419 420 const unsigned char* TraceLog::GetCategoryGroupEnabled( 421 const char* category_group) { 422 TraceLog* tracelog = GetInstance(); 423 if (!tracelog) { 424 DCHECK(!g_category_group_enabled[g_category_already_shutdown]); 425 return &g_category_group_enabled[g_category_already_shutdown]; 426 } 427 return tracelog->GetCategoryGroupEnabledInternal(category_group); 428 } 429 430 const char* TraceLog::GetCategoryGroupName( 431 const unsigned char* category_group_enabled) { 432 // Calculate the index of the category group by finding 433 // category_group_enabled in g_category_group_enabled array. 434 uintptr_t category_begin = 435 reinterpret_cast<uintptr_t>(g_category_group_enabled); 436 uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled); 437 DCHECK(category_ptr >= category_begin && 438 category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled + 439 MAX_CATEGORY_GROUPS)) 440 << "out of bounds category pointer"; 441 uintptr_t category_index = 442 (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]); 443 return g_category_groups[category_index]; 444 } 445 446 void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) { 447 unsigned char enabled_flag = 0; 448 const char* category_group = g_category_groups[category_index]; 449 if (mode_ == RECORDING_MODE && 450 trace_config_.IsCategoryGroupEnabled(category_group)) 451 enabled_flag |= ENABLED_FOR_RECORDING; 452 else if (mode_ == MONITORING_MODE && 453 trace_config_.IsCategoryGroupEnabled(category_group)) 454 enabled_flag |= ENABLED_FOR_MONITORING; 455 if (event_callback_ && 456 event_callback_trace_config_.IsCategoryGroupEnabled(category_group)) 457 enabled_flag |= ENABLED_FOR_EVENT_CALLBACK; 458 #if defined(OS_WIN) 459 if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled( 460 category_group)) { 461 enabled_flag |= ENABLED_FOR_ETW_EXPORT; 462 } 463 #endif 464 465 g_category_group_enabled[category_index] = enabled_flag; 466 } 467 468 void TraceLog::UpdateCategoryGroupEnabledFlags() { 469 size_t category_index = base::subtle::NoBarrier_Load(&g_category_index); 470 for (size_t i = 0; i < category_index; i++) 471 UpdateCategoryGroupEnabledFlag(i); 472 } 473 474 void TraceLog::UpdateSyntheticDelaysFromTraceConfig() { 475 ResetTraceEventSyntheticDelays(); 476 const TraceConfig::StringList& delays = 477 trace_config_.GetSyntheticDelayValues(); 478 TraceConfig::StringList::const_iterator ci; 479 for (ci = delays.begin(); ci != delays.end(); ++ci) { 480 StringTokenizer tokens(*ci, ";"); 481 if (!tokens.GetNext()) 482 continue; 483 TraceEventSyntheticDelay* delay = 484 TraceEventSyntheticDelay::Lookup(tokens.token()); 485 while (tokens.GetNext()) { 486 std::string token = tokens.token(); 487 char* duration_end; 488 double target_duration = strtod(token.c_str(), &duration_end); 489 if (duration_end != token.c_str()) { 490 delay->SetTargetDuration(TimeDelta::FromMicroseconds( 491 static_cast<int64_t>(target_duration * 1e6))); 492 } else if (token == "static") { 493 delay->SetMode(TraceEventSyntheticDelay::STATIC); 494 } else if (token == "oneshot") { 495 delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT); 496 } else if (token == "alternating") { 497 delay->SetMode(TraceEventSyntheticDelay::ALTERNATING); 498 } 499 } 500 } 501 } 502 503 const unsigned char* TraceLog::GetCategoryGroupEnabledInternal( 504 const char* category_group) { 505 DCHECK(!strchr(category_group, '"')) 506 << "Category groups may not contain double quote"; 507 // The g_category_groups is append only, avoid using a lock for the fast path. 508 size_t current_category_index = base::subtle::Acquire_Load(&g_category_index); 509 510 // Search for pre-existing category group. 511 for (size_t i = 0; i < current_category_index; ++i) { 512 if (strcmp(g_category_groups[i], category_group) == 0) { 513 return &g_category_group_enabled[i]; 514 } 515 } 516 517 unsigned char* category_group_enabled = NULL; 518 // This is the slow path: the lock is not held in the case above, so more 519 // than one thread could have reached here trying to add the same category. 520 // Only hold to lock when actually appending a new category, and 521 // check the categories groups again. 522 AutoLock lock(lock_); 523 size_t category_index = base::subtle::Acquire_Load(&g_category_index); 524 for (size_t i = 0; i < category_index; ++i) { 525 if (strcmp(g_category_groups[i], category_group) == 0) { 526 return &g_category_group_enabled[i]; 527 } 528 } 529 530 // Create a new category group. 531 DCHECK(category_index < MAX_CATEGORY_GROUPS) 532 << "must increase MAX_CATEGORY_GROUPS"; 533 if (category_index < MAX_CATEGORY_GROUPS) { 534 // Don't hold on to the category_group pointer, so that we can create 535 // category groups with strings not known at compile time (this is 536 // required by SetWatchEvent). 537 const char* new_group = strdup(category_group); 538 g_category_groups[category_index] = new_group; 539 DCHECK(!g_category_group_enabled[category_index]); 540 // Note that if both included and excluded patterns in the 541 // TraceConfig are empty, we exclude nothing, 542 // thereby enabling this category group. 543 UpdateCategoryGroupEnabledFlag(category_index); 544 category_group_enabled = &g_category_group_enabled[category_index]; 545 // Update the max index now. 546 base::subtle::Release_Store(&g_category_index, category_index + 1); 547 } else { 548 category_group_enabled = 549 &g_category_group_enabled[g_category_categories_exhausted]; 550 } 551 return category_group_enabled; 552 } 553 554 void TraceLog::GetKnownCategoryGroups( 555 std::vector<std::string>* category_groups) { 556 AutoLock lock(lock_); 557 size_t category_index = base::subtle::NoBarrier_Load(&g_category_index); 558 for (size_t i = g_num_builtin_categories; i < category_index; i++) 559 category_groups->push_back(g_category_groups[i]); 560 } 561 562 void TraceLog::SetEnabled(const TraceConfig& trace_config, Mode mode) { 563 std::vector<EnabledStateObserver*> observer_list; 564 { 565 AutoLock lock(lock_); 566 567 // Can't enable tracing when Flush() is in progress. 568 DCHECK(!flush_task_runner_); 569 570 InternalTraceOptions new_options = 571 GetInternalOptionsFromTraceConfig(trace_config); 572 573 InternalTraceOptions old_options = trace_options(); 574 575 if (IsEnabled()) { 576 if (new_options != old_options) { 577 DLOG(ERROR) << "Attempting to re-enable tracing with a different " 578 << "set of options."; 579 } 580 581 if (mode != mode_) { 582 DLOG(ERROR) << "Attempting to re-enable tracing with a different mode."; 583 } 584 585 trace_config_.Merge(trace_config); 586 UpdateCategoryGroupEnabledFlags(); 587 return; 588 } 589 590 if (dispatching_to_observer_list_) { 591 DLOG(ERROR) 592 << "Cannot manipulate TraceLog::Enabled state from an observer."; 593 return; 594 } 595 596 mode_ = mode; 597 598 if (new_options != old_options) { 599 subtle::NoBarrier_Store(&trace_options_, new_options); 600 UseNextTraceBuffer(); 601 } 602 603 num_traces_recorded_++; 604 605 trace_config_ = TraceConfig(trace_config); 606 UpdateCategoryGroupEnabledFlags(); 607 UpdateSyntheticDelaysFromTraceConfig(); 608 609 if (new_options & kInternalEnableSampling) { 610 sampling_thread_.reset(new TraceSamplingThread); 611 sampling_thread_->RegisterSampleBucket( 612 &g_trace_state[0], "bucket0", 613 Bind(&TraceSamplingThread::DefaultSamplingCallback)); 614 sampling_thread_->RegisterSampleBucket( 615 &g_trace_state[1], "bucket1", 616 Bind(&TraceSamplingThread::DefaultSamplingCallback)); 617 sampling_thread_->RegisterSampleBucket( 618 &g_trace_state[2], "bucket2", 619 Bind(&TraceSamplingThread::DefaultSamplingCallback)); 620 if (!PlatformThread::Create(0, sampling_thread_.get(), 621 &sampling_thread_handle_)) { 622 DCHECK(false) << "failed to create thread"; 623 } 624 } 625 626 dispatching_to_observer_list_ = true; 627 observer_list = enabled_state_observer_list_; 628 } 629 // Notify observers outside the lock in case they trigger trace events. 630 for (size_t i = 0; i < observer_list.size(); ++i) 631 observer_list[i]->OnTraceLogEnabled(); 632 633 { 634 AutoLock lock(lock_); 635 dispatching_to_observer_list_ = false; 636 } 637 } 638 639 void TraceLog::SetArgumentFilterPredicate( 640 const ArgumentFilterPredicate& argument_filter_predicate) { 641 AutoLock lock(lock_); 642 DCHECK(!argument_filter_predicate.is_null()); 643 DCHECK(argument_filter_predicate_.is_null()); 644 argument_filter_predicate_ = argument_filter_predicate; 645 } 646 647 TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceConfig( 648 const TraceConfig& config) { 649 InternalTraceOptions ret = 650 config.IsSamplingEnabled() ? kInternalEnableSampling : kInternalNone; 651 if (config.IsArgumentFilterEnabled()) 652 ret |= kInternalEnableArgumentFilter; 653 switch (config.GetTraceRecordMode()) { 654 case RECORD_UNTIL_FULL: 655 return ret | kInternalRecordUntilFull; 656 case RECORD_CONTINUOUSLY: 657 return ret | kInternalRecordContinuously; 658 case ECHO_TO_CONSOLE: 659 return ret | kInternalEchoToConsole; 660 case RECORD_AS_MUCH_AS_POSSIBLE: 661 return ret | kInternalRecordAsMuchAsPossible; 662 } 663 NOTREACHED(); 664 return kInternalNone; 665 } 666 667 TraceConfig TraceLog::GetCurrentTraceConfig() const { 668 AutoLock lock(lock_); 669 return trace_config_; 670 } 671 672 void TraceLog::SetDisabled() { 673 AutoLock lock(lock_); 674 SetDisabledWhileLocked(); 675 } 676 677 void TraceLog::SetDisabledWhileLocked() { 678 lock_.AssertAcquired(); 679 680 if (!IsEnabled()) 681 return; 682 683 if (dispatching_to_observer_list_) { 684 DLOG(ERROR) 685 << "Cannot manipulate TraceLog::Enabled state from an observer."; 686 return; 687 } 688 689 mode_ = DISABLED; 690 691 if (sampling_thread_.get()) { 692 // Stop the sampling thread. 693 sampling_thread_->Stop(); 694 lock_.Release(); 695 PlatformThread::Join(sampling_thread_handle_); 696 lock_.Acquire(); 697 sampling_thread_handle_ = PlatformThreadHandle(); 698 sampling_thread_.reset(); 699 } 700 701 trace_config_.Clear(); 702 subtle::NoBarrier_Store(&watch_category_, 0); 703 watch_event_name_ = ""; 704 UpdateCategoryGroupEnabledFlags(); 705 AddMetadataEventsWhileLocked(); 706 707 // Remove metadata events so they will not get added to a subsequent trace. 708 metadata_events_.clear(); 709 710 dispatching_to_observer_list_ = true; 711 std::vector<EnabledStateObserver*> observer_list = 712 enabled_state_observer_list_; 713 714 { 715 // Dispatch to observers outside the lock in case the observer triggers a 716 // trace event. 717 AutoUnlock unlock(lock_); 718 for (size_t i = 0; i < observer_list.size(); ++i) 719 observer_list[i]->OnTraceLogDisabled(); 720 } 721 dispatching_to_observer_list_ = false; 722 } 723 724 int TraceLog::GetNumTracesRecorded() { 725 AutoLock lock(lock_); 726 if (!IsEnabled()) 727 return -1; 728 return num_traces_recorded_; 729 } 730 731 void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) { 732 AutoLock lock(lock_); 733 enabled_state_observer_list_.push_back(listener); 734 } 735 736 void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) { 737 AutoLock lock(lock_); 738 std::vector<EnabledStateObserver*>::iterator it = 739 std::find(enabled_state_observer_list_.begin(), 740 enabled_state_observer_list_.end(), listener); 741 if (it != enabled_state_observer_list_.end()) 742 enabled_state_observer_list_.erase(it); 743 } 744 745 bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const { 746 AutoLock lock(lock_); 747 return ContainsValue(enabled_state_observer_list_, listener); 748 } 749 750 TraceLogStatus TraceLog::GetStatus() const { 751 AutoLock lock(lock_); 752 TraceLogStatus result; 753 result.event_capacity = logged_events_->Capacity(); 754 result.event_count = logged_events_->Size(); 755 return result; 756 } 757 758 bool TraceLog::BufferIsFull() const { 759 AutoLock lock(lock_); 760 return logged_events_->IsFull(); 761 } 762 763 TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked( 764 TraceEventHandle* handle, 765 bool check_buffer_is_full) { 766 lock_.AssertAcquired(); 767 768 if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) { 769 logged_events_->ReturnChunk(thread_shared_chunk_index_, 770 std::move(thread_shared_chunk_)); 771 } 772 773 if (!thread_shared_chunk_) { 774 thread_shared_chunk_ = 775 logged_events_->GetChunk(&thread_shared_chunk_index_); 776 if (check_buffer_is_full) 777 CheckIfBufferIsFullWhileLocked(); 778 } 779 if (!thread_shared_chunk_) 780 return NULL; 781 782 size_t event_index; 783 TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index); 784 if (trace_event && handle) { 785 MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_, 786 event_index, handle); 787 } 788 return trace_event; 789 } 790 791 void TraceLog::CheckIfBufferIsFullWhileLocked() { 792 lock_.AssertAcquired(); 793 if (logged_events_->IsFull()) { 794 if (buffer_limit_reached_timestamp_.is_null()) { 795 buffer_limit_reached_timestamp_ = OffsetNow(); 796 } 797 SetDisabledWhileLocked(); 798 } 799 } 800 801 void TraceLog::SetEventCallbackEnabled(const TraceConfig& trace_config, 802 EventCallback cb) { 803 AutoLock lock(lock_); 804 subtle::NoBarrier_Store(&event_callback_, 805 reinterpret_cast<subtle::AtomicWord>(cb)); 806 event_callback_trace_config_ = trace_config; 807 UpdateCategoryGroupEnabledFlags(); 808 } 809 810 void TraceLog::SetEventCallbackDisabled() { 811 AutoLock lock(lock_); 812 subtle::NoBarrier_Store(&event_callback_, 0); 813 UpdateCategoryGroupEnabledFlags(); 814 } 815 816 // Flush() works as the following: 817 // 1. Flush() is called in thread A whose task runner is saved in 818 // flush_task_runner_; 819 // 2. If thread_message_loops_ is not empty, thread A posts task to each message 820 // loop to flush the thread local buffers; otherwise finish the flush; 821 // 3. FlushCurrentThread() deletes the thread local event buffer: 822 // - The last batch of events of the thread are flushed into the main buffer; 823 // - The message loop will be removed from thread_message_loops_; 824 // If this is the last message loop, finish the flush; 825 // 4. If any thread hasn't finish its flush in time, finish the flush. 826 void TraceLog::Flush(const TraceLog::OutputCallback& cb, 827 bool use_worker_thread) { 828 FlushInternal(cb, use_worker_thread, false); 829 } 830 831 void TraceLog::CancelTracing(const OutputCallback& cb) { 832 SetDisabled(); 833 FlushInternal(cb, false, true); 834 } 835 836 void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb, 837 bool use_worker_thread, 838 bool discard_events) { 839 use_worker_thread_ = use_worker_thread; 840 if (IsEnabled()) { 841 // Can't flush when tracing is enabled because otherwise PostTask would 842 // - generate more trace events; 843 // - deschedule the calling thread on some platforms causing inaccurate 844 // timing of the trace events. 845 scoped_refptr<RefCountedString> empty_result = new RefCountedString; 846 if (!cb.is_null()) 847 cb.Run(empty_result, false); 848 LOG(WARNING) << "Ignored TraceLog::Flush called when tracing is enabled"; 849 return; 850 } 851 852 int generation = this->generation(); 853 // Copy of thread_message_loops_ to be used without locking. 854 std::vector<scoped_refptr<SingleThreadTaskRunner>> 855 thread_message_loop_task_runners; 856 { 857 AutoLock lock(lock_); 858 DCHECK(!flush_task_runner_); 859 flush_task_runner_ = ThreadTaskRunnerHandle::IsSet() 860 ? ThreadTaskRunnerHandle::Get() 861 : nullptr; 862 DCHECK(!thread_message_loops_.size() || flush_task_runner_); 863 flush_output_callback_ = cb; 864 865 if (thread_shared_chunk_) { 866 logged_events_->ReturnChunk(thread_shared_chunk_index_, 867 std::move(thread_shared_chunk_)); 868 } 869 870 if (thread_message_loops_.size()) { 871 for (hash_set<MessageLoop*>::const_iterator it = 872 thread_message_loops_.begin(); 873 it != thread_message_loops_.end(); ++it) { 874 thread_message_loop_task_runners.push_back((*it)->task_runner()); 875 } 876 } 877 } 878 879 if (thread_message_loop_task_runners.size()) { 880 for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) { 881 thread_message_loop_task_runners[i]->PostTask( 882 FROM_HERE, Bind(&TraceLog::FlushCurrentThread, Unretained(this), 883 generation, discard_events)); 884 } 885 flush_task_runner_->PostDelayedTask( 886 FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation, 887 discard_events), 888 TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs)); 889 return; 890 } 891 892 FinishFlush(generation, discard_events); 893 } 894 895 // Usually it runs on a different thread. 896 void TraceLog::ConvertTraceEventsToTraceFormat( 897 scoped_ptr<TraceBuffer> logged_events, 898 const OutputCallback& flush_output_callback, 899 const ArgumentFilterPredicate& argument_filter_predicate) { 900 if (flush_output_callback.is_null()) 901 return; 902 903 // The callback need to be called at least once even if there is no events 904 // to let the caller know the completion of flush. 905 scoped_refptr<RefCountedString> json_events_str_ptr = new RefCountedString(); 906 while (const TraceBufferChunk* chunk = logged_events->NextChunk()) { 907 for (size_t j = 0; j < chunk->size(); ++j) { 908 size_t size = json_events_str_ptr->size(); 909 if (size > kTraceEventBufferSizeInBytes) { 910 flush_output_callback.Run(json_events_str_ptr, true); 911 json_events_str_ptr = new RefCountedString(); 912 } else if (size) { 913 json_events_str_ptr->data().append(",\n"); 914 } 915 chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()), 916 argument_filter_predicate); 917 } 918 } 919 flush_output_callback.Run(json_events_str_ptr, false); 920 } 921 922 void TraceLog::FinishFlush(int generation, bool discard_events) { 923 scoped_ptr<TraceBuffer> previous_logged_events; 924 OutputCallback flush_output_callback; 925 ArgumentFilterPredicate argument_filter_predicate; 926 927 if (!CheckGeneration(generation)) 928 return; 929 930 { 931 AutoLock lock(lock_); 932 933 previous_logged_events.swap(logged_events_); 934 UseNextTraceBuffer(); 935 thread_message_loops_.clear(); 936 937 flush_task_runner_ = NULL; 938 flush_output_callback = flush_output_callback_; 939 flush_output_callback_.Reset(); 940 941 if (trace_options() & kInternalEnableArgumentFilter) { 942 CHECK(!argument_filter_predicate_.is_null()); 943 argument_filter_predicate = argument_filter_predicate_; 944 } 945 } 946 947 if (discard_events) { 948 if (!flush_output_callback.is_null()) { 949 scoped_refptr<RefCountedString> empty_result = new RefCountedString; 950 flush_output_callback.Run(empty_result, false); 951 } 952 return; 953 } 954 955 if (use_worker_thread_ && 956 WorkerPool::PostTask( 957 FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat, 958 Passed(&previous_logged_events), 959 flush_output_callback, argument_filter_predicate), 960 true)) { 961 return; 962 } 963 964 ConvertTraceEventsToTraceFormat(std::move(previous_logged_events), 965 flush_output_callback, 966 argument_filter_predicate); 967 } 968 969 // Run in each thread holding a local event buffer. 970 void TraceLog::FlushCurrentThread(int generation, bool discard_events) { 971 { 972 AutoLock lock(lock_); 973 if (!CheckGeneration(generation) || !flush_task_runner_) { 974 // This is late. The corresponding flush has finished. 975 return; 976 } 977 } 978 979 // This will flush the thread local buffer. 980 delete thread_local_event_buffer_.Get(); 981 982 AutoLock lock(lock_); 983 if (!CheckGeneration(generation) || !flush_task_runner_ || 984 thread_message_loops_.size()) 985 return; 986 987 flush_task_runner_->PostTask( 988 FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation, 989 discard_events)); 990 } 991 992 void TraceLog::OnFlushTimeout(int generation, bool discard_events) { 993 { 994 AutoLock lock(lock_); 995 if (!CheckGeneration(generation) || !flush_task_runner_) { 996 // Flush has finished before timeout. 997 return; 998 } 999 1000 LOG(WARNING) 1001 << "The following threads haven't finished flush in time. " 1002 "If this happens stably for some thread, please call " 1003 "TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop() from " 1004 "the thread to avoid its trace events from being lost."; 1005 for (hash_set<MessageLoop*>::const_iterator it = 1006 thread_message_loops_.begin(); 1007 it != thread_message_loops_.end(); ++it) { 1008 LOG(WARNING) << "Thread: " << (*it)->thread_name(); 1009 } 1010 } 1011 FinishFlush(generation, discard_events); 1012 } 1013 1014 void TraceLog::FlushButLeaveBufferIntact( 1015 const TraceLog::OutputCallback& flush_output_callback) { 1016 scoped_ptr<TraceBuffer> previous_logged_events; 1017 ArgumentFilterPredicate argument_filter_predicate; 1018 { 1019 AutoLock lock(lock_); 1020 AddMetadataEventsWhileLocked(); 1021 if (thread_shared_chunk_) { 1022 // Return the chunk to the main buffer to flush the sampling data. 1023 logged_events_->ReturnChunk(thread_shared_chunk_index_, 1024 std::move(thread_shared_chunk_)); 1025 } 1026 previous_logged_events = logged_events_->CloneForIteration(); 1027 1028 if (trace_options() & kInternalEnableArgumentFilter) { 1029 CHECK(!argument_filter_predicate_.is_null()); 1030 argument_filter_predicate = argument_filter_predicate_; 1031 } 1032 } // release lock 1033 1034 ConvertTraceEventsToTraceFormat(std::move(previous_logged_events), 1035 flush_output_callback, 1036 argument_filter_predicate); 1037 } 1038 1039 void TraceLog::UseNextTraceBuffer() { 1040 logged_events_.reset(CreateTraceBuffer()); 1041 subtle::NoBarrier_AtomicIncrement(&generation_, 1); 1042 thread_shared_chunk_.reset(); 1043 thread_shared_chunk_index_ = 0; 1044 } 1045 1046 TraceEventHandle TraceLog::AddTraceEvent( 1047 char phase, 1048 const unsigned char* category_group_enabled, 1049 const char* name, 1050 unsigned long long id, 1051 int num_args, 1052 const char** arg_names, 1053 const unsigned char* arg_types, 1054 const unsigned long long* arg_values, 1055 const scoped_refptr<ConvertableToTraceFormat>* convertable_values, 1056 unsigned int flags) { 1057 int thread_id = static_cast<int>(base::PlatformThread::CurrentId()); 1058 base::TimeTicks now = base::TimeTicks::Now(); 1059 return AddTraceEventWithThreadIdAndTimestamp( 1060 phase, 1061 category_group_enabled, 1062 name, 1063 id, 1064 trace_event_internal::kNoId, // bind_id 1065 thread_id, 1066 now, 1067 num_args, 1068 arg_names, 1069 arg_types, 1070 arg_values, 1071 convertable_values, 1072 flags); 1073 } 1074 1075 TraceEventHandle TraceLog::AddTraceEventWithBindId( 1076 char phase, 1077 const unsigned char* category_group_enabled, 1078 const char* name, 1079 unsigned long long id, 1080 unsigned long long bind_id, 1081 int num_args, 1082 const char** arg_names, 1083 const unsigned char* arg_types, 1084 const unsigned long long* arg_values, 1085 const scoped_refptr<ConvertableToTraceFormat>* convertable_values, 1086 unsigned int flags) { 1087 int thread_id = static_cast<int>(base::PlatformThread::CurrentId()); 1088 base::TimeTicks now = base::TimeTicks::Now(); 1089 return AddTraceEventWithThreadIdAndTimestamp( 1090 phase, 1091 category_group_enabled, 1092 name, 1093 id, 1094 bind_id, 1095 thread_id, 1096 now, 1097 num_args, 1098 arg_names, 1099 arg_types, 1100 arg_values, 1101 convertable_values, 1102 flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID); 1103 } 1104 1105 TraceEventHandle TraceLog::AddTraceEventWithProcessId( 1106 char phase, 1107 const unsigned char* category_group_enabled, 1108 const char* name, 1109 unsigned long long id, 1110 int process_id, 1111 int num_args, 1112 const char** arg_names, 1113 const unsigned char* arg_types, 1114 const unsigned long long* arg_values, 1115 const scoped_refptr<ConvertableToTraceFormat>* convertable_values, 1116 unsigned int flags) { 1117 base::TimeTicks now = base::TimeTicks::Now(); 1118 return AddTraceEventWithThreadIdAndTimestamp( 1119 phase, 1120 category_group_enabled, 1121 name, 1122 id, 1123 trace_event_internal::kNoId, // bind_id 1124 process_id, 1125 now, 1126 num_args, 1127 arg_names, 1128 arg_types, 1129 arg_values, 1130 convertable_values, 1131 flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID); 1132 } 1133 1134 // Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp 1135 // with kNoId as bind_id 1136 TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp( 1137 char phase, 1138 const unsigned char* category_group_enabled, 1139 const char* name, 1140 unsigned long long id, 1141 int thread_id, 1142 const TimeTicks& timestamp, 1143 int num_args, 1144 const char** arg_names, 1145 const unsigned char* arg_types, 1146 const unsigned long long* arg_values, 1147 const scoped_refptr<ConvertableToTraceFormat>* convertable_values, 1148 unsigned int flags) { 1149 return AddTraceEventWithThreadIdAndTimestamp( 1150 phase, 1151 category_group_enabled, 1152 name, 1153 id, 1154 trace_event_internal::kNoId, // bind_id 1155 thread_id, 1156 timestamp, 1157 num_args, 1158 arg_names, 1159 arg_types, 1160 arg_values, 1161 convertable_values, 1162 flags); 1163 } 1164 1165 TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp( 1166 char phase, 1167 const unsigned char* category_group_enabled, 1168 const char* name, 1169 unsigned long long id, 1170 unsigned long long bind_id, 1171 int thread_id, 1172 const TimeTicks& timestamp, 1173 int num_args, 1174 const char** arg_names, 1175 const unsigned char* arg_types, 1176 const unsigned long long* arg_values, 1177 const scoped_refptr<ConvertableToTraceFormat>* convertable_values, 1178 unsigned int flags) { 1179 TraceEventHandle handle = {0, 0, 0}; 1180 if (!*category_group_enabled) 1181 return handle; 1182 1183 // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when 1184 // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) -> 1185 // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ... 1186 if (thread_is_in_trace_event_.Get()) 1187 return handle; 1188 1189 AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_); 1190 1191 DCHECK(name); 1192 DCHECK(!timestamp.is_null()); 1193 1194 if (flags & TRACE_EVENT_FLAG_MANGLE_ID) { 1195 if ((flags & TRACE_EVENT_FLAG_FLOW_IN) || 1196 (flags & TRACE_EVENT_FLAG_FLOW_OUT)) 1197 bind_id = MangleEventId(bind_id); 1198 id = MangleEventId(id); 1199 } 1200 1201 TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp); 1202 ThreadTicks thread_now = ThreadNow(); 1203 1204 // |thread_local_event_buffer_| can be null if the current thread doesn't have 1205 // a message loop or the message loop is blocked. 1206 InitializeThreadLocalEventBufferIfSupported(); 1207 auto thread_local_event_buffer = thread_local_event_buffer_.Get(); 1208 1209 // Check and update the current thread name only if the event is for the 1210 // current thread to avoid locks in most cases. 1211 if (thread_id == static_cast<int>(PlatformThread::CurrentId())) { 1212 const char* new_name = 1213 ThreadIdNameManager::GetInstance()->GetName(thread_id); 1214 // Check if the thread name has been set or changed since the previous 1215 // call (if any), but don't bother if the new name is empty. Note this will 1216 // not detect a thread name change within the same char* buffer address: we 1217 // favor common case performance over corner case correctness. 1218 if (new_name != g_current_thread_name.Get().Get() && new_name && 1219 *new_name) { 1220 g_current_thread_name.Get().Set(new_name); 1221 1222 AutoLock thread_info_lock(thread_info_lock_); 1223 1224 hash_map<int, std::string>::iterator existing_name = 1225 thread_names_.find(thread_id); 1226 if (existing_name == thread_names_.end()) { 1227 // This is a new thread id, and a new name. 1228 thread_names_[thread_id] = new_name; 1229 } else { 1230 // This is a thread id that we've seen before, but potentially with a 1231 // new name. 1232 std::vector<StringPiece> existing_names = base::SplitStringPiece( 1233 existing_name->second, ",", base::KEEP_WHITESPACE, 1234 base::SPLIT_WANT_NONEMPTY); 1235 bool found = std::find(existing_names.begin(), existing_names.end(), 1236 new_name) != existing_names.end(); 1237 if (!found) { 1238 if (existing_names.size()) 1239 existing_name->second.push_back(','); 1240 existing_name->second.append(new_name); 1241 } 1242 } 1243 } 1244 } 1245 1246 #if defined(OS_WIN) 1247 // This is done sooner rather than later, to avoid creating the event and 1248 // acquiring the lock, which is not needed for ETW as it's already threadsafe. 1249 if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT) 1250 TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id, 1251 num_args, arg_names, arg_types, arg_values, 1252 convertable_values); 1253 #endif // OS_WIN 1254 1255 std::string console_message; 1256 if (*category_group_enabled & 1257 (ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) { 1258 OptionalAutoLock lock(&lock_); 1259 1260 TraceEvent* trace_event = NULL; 1261 if (thread_local_event_buffer) { 1262 trace_event = thread_local_event_buffer->AddTraceEvent(&handle); 1263 } else { 1264 lock.EnsureAcquired(); 1265 trace_event = AddEventToThreadSharedChunkWhileLocked(&handle, true); 1266 } 1267 1268 if (trace_event) { 1269 trace_event->Initialize(thread_id, 1270 offset_event_timestamp, 1271 thread_now, 1272 phase, 1273 category_group_enabled, 1274 name, 1275 id, 1276 bind_id, 1277 num_args, 1278 arg_names, 1279 arg_types, 1280 arg_values, 1281 convertable_values, 1282 flags); 1283 1284 #if defined(OS_ANDROID) 1285 trace_event->SendToATrace(); 1286 #endif 1287 } 1288 1289 if (trace_options() & kInternalEchoToConsole) { 1290 console_message = EventToConsoleMessage( 1291 phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase, 1292 timestamp, trace_event); 1293 } 1294 } 1295 1296 if (console_message.size()) 1297 LOG(ERROR) << console_message; 1298 1299 if (reinterpret_cast<const unsigned char*>( 1300 subtle::NoBarrier_Load(&watch_category_)) == category_group_enabled) { 1301 bool event_name_matches; 1302 WatchEventCallback watch_event_callback_copy; 1303 { 1304 AutoLock lock(lock_); 1305 event_name_matches = watch_event_name_ == name; 1306 watch_event_callback_copy = watch_event_callback_; 1307 } 1308 if (event_name_matches) { 1309 if (!watch_event_callback_copy.is_null()) 1310 watch_event_callback_copy.Run(); 1311 } 1312 } 1313 1314 if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) { 1315 EventCallback event_callback = reinterpret_cast<EventCallback>( 1316 subtle::NoBarrier_Load(&event_callback_)); 1317 if (event_callback) { 1318 event_callback( 1319 offset_event_timestamp, 1320 phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase, 1321 category_group_enabled, name, id, num_args, arg_names, arg_types, 1322 arg_values, flags); 1323 } 1324 } 1325 1326 if (base::trace_event::AllocationContextTracker::capture_enabled()) { 1327 if (phase == TRACE_EVENT_PHASE_BEGIN || phase == TRACE_EVENT_PHASE_COMPLETE) 1328 base::trace_event::AllocationContextTracker::PushPseudoStackFrame(name); 1329 else if (phase == TRACE_EVENT_PHASE_END) 1330 // The pop for |TRACE_EVENT_PHASE_COMPLETE| events 1331 // is in |TraceLog::UpdateTraceEventDuration|. 1332 base::trace_event::AllocationContextTracker::PopPseudoStackFrame(name); 1333 } 1334 1335 return handle; 1336 } 1337 1338 void TraceLog::AddMetadataEvent( 1339 const char* name, 1340 int num_args, 1341 const char** arg_names, 1342 const unsigned char* arg_types, 1343 const unsigned long long* arg_values, 1344 const scoped_refptr<ConvertableToTraceFormat>* convertable_values, 1345 unsigned int flags) { 1346 scoped_ptr<TraceEvent> trace_event(new TraceEvent); 1347 AutoLock lock(lock_); 1348 trace_event->Initialize( 1349 0, // thread_id 1350 TimeTicks(), ThreadTicks(), TRACE_EVENT_PHASE_METADATA, 1351 &g_category_group_enabled[g_category_metadata], name, 1352 trace_event_internal::kNoId, // id 1353 trace_event_internal::kNoId, // bind_id 1354 num_args, arg_names, arg_types, arg_values, convertable_values, flags); 1355 metadata_events_.push_back(std::move(trace_event)); 1356 } 1357 1358 // May be called when a COMPELETE event ends and the unfinished event has been 1359 // recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL). 1360 std::string TraceLog::EventToConsoleMessage(unsigned char phase, 1361 const TimeTicks& timestamp, 1362 TraceEvent* trace_event) { 1363 AutoLock thread_info_lock(thread_info_lock_); 1364 1365 // The caller should translate TRACE_EVENT_PHASE_COMPLETE to 1366 // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END. 1367 DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE); 1368 1369 TimeDelta duration; 1370 int thread_id = 1371 trace_event ? trace_event->thread_id() : PlatformThread::CurrentId(); 1372 if (phase == TRACE_EVENT_PHASE_END) { 1373 duration = timestamp - thread_event_start_times_[thread_id].top(); 1374 thread_event_start_times_[thread_id].pop(); 1375 } 1376 1377 std::string thread_name = thread_names_[thread_id]; 1378 if (thread_colors_.find(thread_name) == thread_colors_.end()) 1379 thread_colors_[thread_name] = (thread_colors_.size() % 6) + 1; 1380 1381 std::ostringstream log; 1382 log << base::StringPrintf("%s: \x1b[0;3%dm", thread_name.c_str(), 1383 thread_colors_[thread_name]); 1384 1385 size_t depth = 0; 1386 if (thread_event_start_times_.find(thread_id) != 1387 thread_event_start_times_.end()) 1388 depth = thread_event_start_times_[thread_id].size(); 1389 1390 for (size_t i = 0; i < depth; ++i) 1391 log << "| "; 1392 1393 if (trace_event) 1394 trace_event->AppendPrettyPrinted(&log); 1395 if (phase == TRACE_EVENT_PHASE_END) 1396 log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF()); 1397 1398 log << "\x1b[0;m"; 1399 1400 if (phase == TRACE_EVENT_PHASE_BEGIN) 1401 thread_event_start_times_[thread_id].push(timestamp); 1402 1403 return log.str(); 1404 } 1405 1406 void TraceLog::UpdateTraceEventDuration( 1407 const unsigned char* category_group_enabled, 1408 const char* name, 1409 TraceEventHandle handle) { 1410 char category_group_enabled_local = *category_group_enabled; 1411 if (!category_group_enabled_local) 1412 return; 1413 1414 // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when 1415 // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) -> 1416 // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ... 1417 if (thread_is_in_trace_event_.Get()) 1418 return; 1419 1420 AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_); 1421 1422 ThreadTicks thread_now = ThreadNow(); 1423 TimeTicks now = OffsetNow(); 1424 1425 #if defined(OS_WIN) 1426 // Generate an ETW event that marks the end of a complete event. 1427 if (category_group_enabled_local & ENABLED_FOR_ETW_EXPORT) 1428 TraceEventETWExport::AddCompleteEndEvent(name); 1429 #endif // OS_WIN 1430 1431 std::string console_message; 1432 if (category_group_enabled_local & ENABLED_FOR_RECORDING) { 1433 OptionalAutoLock lock(&lock_); 1434 1435 TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock); 1436 if (trace_event) { 1437 DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE); 1438 trace_event->UpdateDuration(now, thread_now); 1439 #if defined(OS_ANDROID) 1440 trace_event->SendToATrace(); 1441 #endif 1442 } 1443 1444 if (trace_options() & kInternalEchoToConsole) { 1445 console_message = 1446 EventToConsoleMessage(TRACE_EVENT_PHASE_END, now, trace_event); 1447 } 1448 1449 if (base::trace_event::AllocationContextTracker::capture_enabled()) { 1450 // The corresponding push is in |AddTraceEventWithThreadIdAndTimestamp|. 1451 base::trace_event::AllocationContextTracker::PopPseudoStackFrame(name); 1452 } 1453 } 1454 1455 if (console_message.size()) 1456 LOG(ERROR) << console_message; 1457 1458 if (category_group_enabled_local & ENABLED_FOR_EVENT_CALLBACK) { 1459 EventCallback event_callback = reinterpret_cast<EventCallback>( 1460 subtle::NoBarrier_Load(&event_callback_)); 1461 if (event_callback) { 1462 event_callback(now, TRACE_EVENT_PHASE_END, category_group_enabled, name, 1463 trace_event_internal::kNoId, 0, 1464 nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_NONE); 1465 } 1466 } 1467 } 1468 1469 void TraceLog::SetWatchEvent(const std::string& category_name, 1470 const std::string& event_name, 1471 const WatchEventCallback& callback) { 1472 const unsigned char* category = 1473 GetCategoryGroupEnabled(category_name.c_str()); 1474 AutoLock lock(lock_); 1475 subtle::NoBarrier_Store(&watch_category_, 1476 reinterpret_cast<subtle::AtomicWord>(category)); 1477 watch_event_name_ = event_name; 1478 watch_event_callback_ = callback; 1479 } 1480 1481 void TraceLog::CancelWatchEvent() { 1482 AutoLock lock(lock_); 1483 subtle::NoBarrier_Store(&watch_category_, 0); 1484 watch_event_name_ = ""; 1485 watch_event_callback_.Reset(); 1486 } 1487 1488 uint64_t TraceLog::MangleEventId(uint64_t id) { 1489 return id ^ process_id_hash_; 1490 } 1491 1492 void TraceLog::AddMetadataEventsWhileLocked() { 1493 lock_.AssertAcquired(); 1494 1495 // Copy metadata added by |AddMetadataEvent| into the trace log. 1496 for (const scoped_ptr<TraceEvent>& event : metadata_events_) 1497 AddEventToThreadSharedChunkWhileLocked(nullptr, false)->CopyFrom(*event); 1498 1499 #if !defined(OS_NACL) // NaCl shouldn't expose the process id. 1500 InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false), 1501 0, "num_cpus", "number", 1502 base::SysInfo::NumberOfProcessors()); 1503 #endif 1504 1505 int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId()); 1506 if (process_sort_index_ != 0) { 1507 InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false), 1508 current_thread_id, "process_sort_index", 1509 "sort_index", process_sort_index_); 1510 } 1511 1512 if (process_name_.size()) { 1513 InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false), 1514 current_thread_id, "process_name", "name", 1515 process_name_); 1516 } 1517 1518 if (process_labels_.size() > 0) { 1519 std::vector<std::string> labels; 1520 for (base::hash_map<int, std::string>::iterator it = 1521 process_labels_.begin(); 1522 it != process_labels_.end(); it++) { 1523 labels.push_back(it->second); 1524 } 1525 InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false), 1526 current_thread_id, "process_labels", "labels", 1527 base::JoinString(labels, ",")); 1528 } 1529 1530 // Thread sort indices. 1531 for (hash_map<int, int>::iterator it = thread_sort_indices_.begin(); 1532 it != thread_sort_indices_.end(); it++) { 1533 if (it->second == 0) 1534 continue; 1535 InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false), 1536 it->first, "thread_sort_index", "sort_index", 1537 it->second); 1538 } 1539 1540 // Thread names. 1541 AutoLock thread_info_lock(thread_info_lock_); 1542 for (hash_map<int, std::string>::iterator it = thread_names_.begin(); 1543 it != thread_names_.end(); it++) { 1544 if (it->second.empty()) 1545 continue; 1546 InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false), 1547 it->first, "thread_name", "name", it->second); 1548 } 1549 1550 // If buffer is full, add a metadata record to report this. 1551 if (!buffer_limit_reached_timestamp_.is_null()) { 1552 InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false), 1553 current_thread_id, "trace_buffer_overflowed", 1554 "overflowed_at_ts", 1555 buffer_limit_reached_timestamp_); 1556 } 1557 } 1558 1559 void TraceLog::WaitSamplingEventForTesting() { 1560 if (!sampling_thread_) 1561 return; 1562 sampling_thread_->WaitSamplingEventForTesting(); 1563 } 1564 1565 void TraceLog::DeleteForTesting() { 1566 internal::DeleteTraceLogForTesting::Delete(); 1567 } 1568 1569 TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) { 1570 return GetEventByHandleInternal(handle, NULL); 1571 } 1572 1573 TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle, 1574 OptionalAutoLock* lock) { 1575 if (!handle.chunk_seq) 1576 return NULL; 1577 1578 if (thread_local_event_buffer_.Get()) { 1579 TraceEvent* trace_event = 1580 thread_local_event_buffer_.Get()->GetEventByHandle(handle); 1581 if (trace_event) 1582 return trace_event; 1583 } 1584 1585 // The event has been out-of-control of the thread local buffer. 1586 // Try to get the event from the main buffer with a lock. 1587 if (lock) 1588 lock->EnsureAcquired(); 1589 1590 if (thread_shared_chunk_ && 1591 handle.chunk_index == thread_shared_chunk_index_) { 1592 return handle.chunk_seq == thread_shared_chunk_->seq() 1593 ? thread_shared_chunk_->GetEventAt(handle.event_index) 1594 : NULL; 1595 } 1596 1597 return logged_events_->GetEventByHandle(handle); 1598 } 1599 1600 void TraceLog::SetProcessID(int process_id) { 1601 process_id_ = process_id; 1602 // Create a FNV hash from the process ID for XORing. 1603 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. 1604 unsigned long long offset_basis = 14695981039346656037ull; 1605 unsigned long long fnv_prime = 1099511628211ull; 1606 unsigned long long pid = static_cast<unsigned long long>(process_id_); 1607 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; 1608 } 1609 1610 void TraceLog::SetProcessSortIndex(int sort_index) { 1611 AutoLock lock(lock_); 1612 process_sort_index_ = sort_index; 1613 } 1614 1615 void TraceLog::SetProcessName(const std::string& process_name) { 1616 AutoLock lock(lock_); 1617 process_name_ = process_name; 1618 } 1619 1620 void TraceLog::UpdateProcessLabel(int label_id, 1621 const std::string& current_label) { 1622 if (!current_label.length()) 1623 return RemoveProcessLabel(label_id); 1624 1625 AutoLock lock(lock_); 1626 process_labels_[label_id] = current_label; 1627 } 1628 1629 void TraceLog::RemoveProcessLabel(int label_id) { 1630 AutoLock lock(lock_); 1631 base::hash_map<int, std::string>::iterator it = 1632 process_labels_.find(label_id); 1633 if (it == process_labels_.end()) 1634 return; 1635 1636 process_labels_.erase(it); 1637 } 1638 1639 void TraceLog::SetThreadSortIndex(PlatformThreadId thread_id, int sort_index) { 1640 AutoLock lock(lock_); 1641 thread_sort_indices_[static_cast<int>(thread_id)] = sort_index; 1642 } 1643 1644 void TraceLog::SetTimeOffset(TimeDelta offset) { 1645 time_offset_ = offset; 1646 } 1647 1648 size_t TraceLog::GetObserverCountForTest() const { 1649 return enabled_state_observer_list_.size(); 1650 } 1651 1652 void TraceLog::SetCurrentThreadBlocksMessageLoop() { 1653 thread_blocks_message_loop_.Set(true); 1654 if (thread_local_event_buffer_.Get()) { 1655 // This will flush the thread local buffer. 1656 delete thread_local_event_buffer_.Get(); 1657 } 1658 } 1659 1660 TraceBuffer* TraceLog::CreateTraceBuffer() { 1661 InternalTraceOptions options = trace_options(); 1662 if (options & kInternalRecordContinuously) 1663 return TraceBuffer::CreateTraceBufferRingBuffer( 1664 kTraceEventRingBufferChunks); 1665 else if ((options & kInternalEnableSampling) && mode_ == MONITORING_MODE) 1666 return TraceBuffer::CreateTraceBufferRingBuffer( 1667 kMonitorTraceEventBufferChunks); 1668 else if (options & kInternalEchoToConsole) 1669 return TraceBuffer::CreateTraceBufferRingBuffer( 1670 kEchoToConsoleTraceEventBufferChunks); 1671 else if (options & kInternalRecordAsMuchAsPossible) 1672 return TraceBuffer::CreateTraceBufferVectorOfSize( 1673 kTraceEventVectorBigBufferChunks); 1674 return TraceBuffer::CreateTraceBufferVectorOfSize( 1675 kTraceEventVectorBufferChunks); 1676 } 1677 1678 #if defined(OS_WIN) 1679 void TraceLog::UpdateETWCategoryGroupEnabledFlags() { 1680 AutoLock lock(lock_); 1681 size_t category_index = base::subtle::NoBarrier_Load(&g_category_index); 1682 // Go through each category and set/clear the ETW bit depending on whether the 1683 // category is enabled. 1684 for (size_t i = 0; i < category_index; i++) { 1685 const char* category_group = g_category_groups[i]; 1686 DCHECK(category_group); 1687 if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled( 1688 category_group)) { 1689 g_category_group_enabled[i] |= ENABLED_FOR_ETW_EXPORT; 1690 } else { 1691 g_category_group_enabled[i] &= ~ENABLED_FOR_ETW_EXPORT; 1692 } 1693 } 1694 } 1695 #endif // defined(OS_WIN) 1696 1697 void ConvertableToTraceFormat::EstimateTraceMemoryOverhead( 1698 TraceEventMemoryOverhead* overhead) { 1699 overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this)); 1700 } 1701 1702 } // namespace trace_event 1703 } // namespace base 1704 1705 namespace trace_event_internal { 1706 1707 ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient( 1708 const char* category_group, 1709 const char* name) { 1710 // The single atom works because for now the category_group can only be "gpu". 1711 DCHECK_EQ(strcmp(category_group, "gpu"), 0); 1712 static TRACE_EVENT_API_ATOMIC_WORD atomic = 0; 1713 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( 1714 category_group, atomic, category_group_enabled_); 1715 name_ = name; 1716 if (*category_group_enabled_) { 1717 event_handle_ = 1718 TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( 1719 TRACE_EVENT_PHASE_COMPLETE, 1720 category_group_enabled_, 1721 name, 1722 trace_event_internal::kNoId, // id 1723 static_cast<int>(base::PlatformThread::CurrentId()), // thread_id 1724 base::TimeTicks::Now(), 1725 trace_event_internal::kZeroNumArgs, 1726 nullptr, 1727 nullptr, 1728 nullptr, 1729 nullptr, 1730 TRACE_EVENT_FLAG_NONE); 1731 } 1732 } 1733 1734 ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() { 1735 if (*category_group_enabled_) { 1736 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, name_, 1737 event_handle_); 1738 } 1739 } 1740 1741 } // namespace trace_event_internal 1742