Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(630)

Side by Side Diff: base/debug/trace_event_impl.cc

Issue 10837082: implement SetWatchEvent and WaitForEvent for trace-based-tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: cleaned up and fixed a bug Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/debug/trace_event_impl.h" 5 #include "base/debug/trace_event_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/debug/leak_annotations.h"
10 #include "base/debug/trace_event.h" 11 #include "base/debug/trace_event.h"
11 #include "base/file_util.h" 12 #include "base/file_util.h"
12 #include "base/format_macros.h" 13 #include "base/format_macros.h"
13 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
14 #include "base/memory/singleton.h" 15 #include "base/memory/singleton.h"
15 #include "base/process_util.h" 16 #include "base/process_util.h"
17 #include "base/stl_util.h"
16 #include "base/stringprintf.h" 18 #include "base/stringprintf.h"
17 #include "base/string_tokenizer.h" 19 #include "base/string_tokenizer.h"
20 #include "base/string_util.h"
21 #include "base/sys_info.h"
22 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
18 #include "base/threading/platform_thread.h" 23 #include "base/threading/platform_thread.h"
19 #include "base/threading/thread_local.h" 24 #include "base/threading/thread_local.h"
25 #include "base/time.h"
20 #include "base/utf_string_conversions.h" 26 #include "base/utf_string_conversions.h"
21 #include "base/stl_util.h"
22 #include "base/sys_info.h"
23 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
24 #include "base/time.h"
25 27
26 #if defined(OS_WIN) 28 #if defined(OS_WIN)
27 #include "base/debug/trace_event_win.h" 29 #include "base/debug/trace_event_win.h"
28 #endif 30 #endif
29 31
30 class DeleteTraceLogForTesting { 32 class DeleteTraceLogForTesting {
31 public: 33 public:
32 static void Delete() { 34 static void Delete() {
33 Singleton<base::debug::TraceLog, 35 Singleton<base::debug::TraceLog,
34 StaticMemorySingletonTraits<base::debug::TraceLog> >::OnExit(0); 36 StaticMemorySingletonTraits<base::debug::TraceLog> >::OnExit(0);
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 void TraceResultBuffer::Finish() { 311 void TraceResultBuffer::Finish() {
310 output_callback_.Run("]"); 312 output_callback_.Run("]");
311 } 313 }
312 314
313 //////////////////////////////////////////////////////////////////////////////// 315 ////////////////////////////////////////////////////////////////////////////////
314 // 316 //
315 // TraceLog 317 // TraceLog
316 // 318 //
317 //////////////////////////////////////////////////////////////////////////////// 319 ////////////////////////////////////////////////////////////////////////////////
318 320
321 TraceLog::NotificationHelper::NotificationHelper(TraceLog* trace_log)
322 : trace_log_(trace_log)
323 , notification_(0) {
324 }
325
326 TraceLog::NotificationHelper::~NotificationHelper() {
327 }
328
329 void TraceLog::NotificationHelper::AddNotificationWhileLocked(
330 int notification) {
331 if (notification_ == 0) {
332 callback_copy_ = trace_log_->notification_callback_;
333 ++trace_log_->notification_thread_count_;
ccameron 2012/08/21 01:06:34 [RW-lock evangelism]: With a separate reader-write
334 }
335 notification_ |= notification;
336 }
337
338 void TraceLog::NotificationHelper::SendNotificationIfAny() {
339 if (notification_) {
ccameron 2012/08/21 01:06:34 [RW-lock evangelism]: With a separate reader-write
340 callback_copy_.Run(notification_);
341 callback_copy_.Reset();
342
343 AutoLock lock(trace_log_->lock_);
344 --trace_log_->notification_thread_count_;
345 // Signal other waiters (if any) in case they are waiting for the
346 // callback object to be unreferenced.
347 if (trace_log_->notification_thread_count_ == 0)
348 trace_log_->notification_condition_.Signal();
349 }
350 }
351
319 // static 352 // static
320 TraceLog* TraceLog::GetInstance() { 353 TraceLog* TraceLog::GetInstance() {
321 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get(); 354 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get();
322 } 355 }
323 356
324 TraceLog::TraceLog() 357 TraceLog::TraceLog()
325 : enabled_(false) 358 : enabled_(false)
326 , dispatching_to_observer_list_(false) { 359 , notification_condition_(&lock_)
360 , notification_thread_count_(0)
361 , dispatching_to_observer_list_(false)
362 , watch_category_(NULL)
363 , watch_count_(0) {
327 // Trace is enabled or disabled on one thread while other threads are 364 // Trace is enabled or disabled on one thread while other threads are
328 // accessing the enabled flag. We don't care whether edge-case events are 365 // accessing the enabled flag. We don't care whether edge-case events are
329 // traced or not, so we allow races on the enabled flag to keep the trace 366 // traced or not, so we allow races on the enabled flag to keep the trace
330 // macros fast. 367 // macros fast.
331 // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots: 368 // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots:
332 // ANNOTATE_BENIGN_RACE_SIZED(g_category_enabled, sizeof(g_category_enabled), 369 // ANNOTATE_BENIGN_RACE_SIZED(g_category_enabled, sizeof(g_category_enabled),
333 // "trace_event category enabled"); 370 // "trace_event category enabled");
334 for (int i = 0; i < TRACE_EVENT_MAX_CATEGORIES; ++i) { 371 for (int i = 0; i < TRACE_EVENT_MAX_CATEGORIES; ++i) {
335 ANNOTATE_BENIGN_RACE(&g_category_enabled[i], 372 ANNOTATE_BENIGN_RACE(&g_category_enabled[i],
336 "trace_event category enabled"); 373 "trace_event category enabled");
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 for (int i = 0; i < g_category_index; i++) { 436 for (int i = 0; i < g_category_index; i++) {
400 if (strcmp(g_categories[i], name) == 0) 437 if (strcmp(g_categories[i], name) == 0)
401 return &g_category_enabled[i]; 438 return &g_category_enabled[i];
402 } 439 }
403 440
404 // Create a new category 441 // Create a new category
405 DCHECK(g_category_index < TRACE_EVENT_MAX_CATEGORIES) << 442 DCHECK(g_category_index < TRACE_EVENT_MAX_CATEGORIES) <<
406 "must increase TRACE_EVENT_MAX_CATEGORIES"; 443 "must increase TRACE_EVENT_MAX_CATEGORIES";
407 if (g_category_index < TRACE_EVENT_MAX_CATEGORIES) { 444 if (g_category_index < TRACE_EVENT_MAX_CATEGORIES) {
408 int new_index = g_category_index++; 445 int new_index = g_category_index++;
409 g_categories[new_index] = name; 446 // Don't hold on to the name pointer, so that we can create categories with
447 // strings not known at compile time (this is required by SetWatchEvent).
448 const char* new_name = base::strdup(name);
449 ANNOTATE_LEAKING_OBJECT_PTR(new_name);
450 g_categories[new_index] = new_name;
410 DCHECK(!g_category_enabled[new_index]); 451 DCHECK(!g_category_enabled[new_index]);
411 if (enabled_) { 452 if (enabled_) {
412 // Note that if both included and excluded_categories are empty, the else 453 // Note that if both included and excluded_categories are empty, the else
413 // clause below excludes nothing, thereby enabling this category. 454 // clause below excludes nothing, thereby enabling this category.
414 if (!included_categories_.empty()) 455 if (!included_categories_.empty())
415 EnableMatchingCategory(new_index, included_categories_, 1); 456 EnableMatchingCategory(new_index, included_categories_, 1);
416 else 457 else
417 EnableMatchingCategory(new_index, excluded_categories_, 0); 458 EnableMatchingCategory(new_index, excluded_categories_, 0);
418 } else { 459 } else {
419 g_category_enabled[new_index] = 0; 460 g_category_enabled[new_index] = 0;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 std::vector<std::string>* included_out, 525 std::vector<std::string>* included_out,
485 std::vector<std::string>* excluded_out) { 526 std::vector<std::string>* excluded_out) {
486 AutoLock lock(lock_); 527 AutoLock lock(lock_);
487 if (enabled_) { 528 if (enabled_) {
488 *included_out = included_categories_; 529 *included_out = included_categories_;
489 *excluded_out = excluded_categories_; 530 *excluded_out = excluded_categories_;
490 } 531 }
491 } 532 }
492 533
493 void TraceLog::SetDisabled() { 534 void TraceLog::SetDisabled() {
494 { 535 AutoLock lock(lock_);
495 AutoLock lock(lock_); 536 if (!enabled_)
496 if (!enabled_) 537 return;
497 return;
498 538
499 if (dispatching_to_observer_list_) { 539 if (dispatching_to_observer_list_) {
500 DLOG(ERROR) 540 DLOG(ERROR)
501 << "Cannot manipulate TraceLog::Enabled state from an observer."; 541 << "Cannot manipulate TraceLog::Enabled state from an observer.";
502 return; 542 return;
503 } 543 }
504 544
505 dispatching_to_observer_list_ = true; 545 dispatching_to_observer_list_ = true;
506 FOR_EACH_OBSERVER(EnabledStateChangedObserver, enabled_state_observer_list_, 546 FOR_EACH_OBSERVER(EnabledStateChangedObserver, enabled_state_observer_list_,
507 OnTraceLogWillDisable()); 547 OnTraceLogWillDisable());
508 dispatching_to_observer_list_ = false; 548 dispatching_to_observer_list_ = false;
509 549
510 enabled_ = false; 550 enabled_ = false;
511 included_categories_.clear(); 551 included_categories_.clear();
512 excluded_categories_.clear(); 552 excluded_categories_.clear();
513 for (int i = 0; i < g_category_index; i++) 553 watch_category_ = NULL;
514 g_category_enabled[i] = 0; 554 watch_event_name_ = "";
515 AddThreadNameMetadataEvents(); 555 for (int i = 0; i < g_category_index; i++)
516 AddClockSyncMetadataEvents(); 556 g_category_enabled[i] = 0;
517 } // release lock 557 AddThreadNameMetadataEvents();
518 Flush(); 558 AddClockSyncMetadataEvents();
519 } 559 }
520 560
521 void TraceLog::SetEnabled(bool enabled) { 561 void TraceLog::SetEnabled(bool enabled) {
522 if (enabled) 562 if (enabled)
523 SetEnabled(std::vector<std::string>(), std::vector<std::string>()); 563 SetEnabled(std::vector<std::string>(), std::vector<std::string>());
524 else 564 else
525 SetDisabled(); 565 SetDisabled();
526 } 566 }
527 567
528 void TraceLog::AddEnabledStateObserver(EnabledStateChangedObserver* listener) { 568 void TraceLog::AddEnabledStateObserver(EnabledStateChangedObserver* listener) {
529 enabled_state_observer_list_.AddObserver(listener); 569 enabled_state_observer_list_.AddObserver(listener);
530 } 570 }
531 571
532 void TraceLog::RemoveEnabledStateObserver( 572 void TraceLog::RemoveEnabledStateObserver(
533 EnabledStateChangedObserver* listener) { 573 EnabledStateChangedObserver* listener) {
534 enabled_state_observer_list_.RemoveObserver(listener); 574 enabled_state_observer_list_.RemoveObserver(listener);
535 } 575 }
536 576
537 float TraceLog::GetBufferPercentFull() const { 577 float TraceLog::GetBufferPercentFull() const {
538 return (float)((double)logged_events_.size()/(double)kTraceEventBufferSize); 578 return (float)((double)logged_events_.size()/(double)kTraceEventBufferSize);
539 } 579 }
540 580
541 void TraceLog::SetOutputCallback(const TraceLog::OutputCallback& cb) { 581 void TraceLog::SetNotificationCallback(
582 const TraceLog::NotificationCallback& cb) {
542 AutoLock lock(lock_); 583 AutoLock lock(lock_);
ccameron 2012/08/21 01:06:34 [RW-lock evangelism]: With a separate reader-write
543 output_callback_ = cb; 584 // Wait until other threads are done using the callback.
585 while (notification_thread_count_ > 0)
586 notification_condition_.Wait();
587 notification_callback_ = cb;
544 } 588 }
545 589
546 void TraceLog::SetBufferFullCallback(const TraceLog::BufferFullCallback& cb) { 590 void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
547 AutoLock lock(lock_);
548 buffer_full_callback_ = cb;
549 }
550
551 void TraceLog::Flush() {
552 std::vector<TraceEvent> previous_logged_events; 591 std::vector<TraceEvent> previous_logged_events;
553 OutputCallback output_callback_copy;
554 { 592 {
555 AutoLock lock(lock_); 593 AutoLock lock(lock_);
556 previous_logged_events.swap(logged_events_); 594 previous_logged_events.swap(logged_events_);
557 output_callback_copy = output_callback_;
558 } // release lock 595 } // release lock
559 596
560 if (output_callback_copy.is_null())
561 return;
562
563 for (size_t i = 0; 597 for (size_t i = 0;
564 i < previous_logged_events.size(); 598 i < previous_logged_events.size();
565 i += kTraceEventBatchSize) { 599 i += kTraceEventBatchSize) {
566 scoped_refptr<RefCountedString> json_events_str_ptr = 600 scoped_refptr<RefCountedString> json_events_str_ptr =
567 new RefCountedString(); 601 new RefCountedString();
568 TraceEvent::AppendEventsAsJSON(previous_logged_events, 602 TraceEvent::AppendEventsAsJSON(previous_logged_events,
569 i, 603 i,
570 kTraceEventBatchSize, 604 kTraceEventBatchSize,
571 &(json_events_str_ptr->data())); 605 &(json_events_str_ptr->data()));
572 output_callback_copy.Run(json_events_str_ptr); 606 cb.Run(json_events_str_ptr);
573 } 607 }
574 } 608 }
575 609
576 int TraceLog::AddTraceEvent(char phase, 610 int TraceLog::AddTraceEvent(char phase,
577 const unsigned char* category_enabled, 611 const unsigned char* category_enabled,
578 const char* name, 612 const char* name,
579 unsigned long long id, 613 unsigned long long id,
580 int num_args, 614 int num_args,
581 const char** arg_names, 615 const char** arg_names,
582 const unsigned char* arg_types, 616 const unsigned char* arg_types,
583 const unsigned long long* arg_values, 617 const unsigned long long* arg_values,
584 int threshold_begin_id, 618 int threshold_begin_id,
585 long long threshold, 619 long long threshold,
586 unsigned char flags) { 620 unsigned char flags) {
587 DCHECK(name); 621 DCHECK(name);
588 TimeTicks now = TimeTicks::NowFromSystemTraceTime(); 622 TimeTicks now = TimeTicks::NowFromSystemTraceTime();
589 BufferFullCallback buffer_full_callback_copy; 623 NotificationHelper notifier(this);
590 int ret_begin_id = -1; 624 int ret_begin_id = -1;
591 { 625 {
592 AutoLock lock(lock_); 626 AutoLock lock(lock_);
593 if (!*category_enabled) 627 if (!*category_enabled)
594 return -1; 628 return -1;
595 if (logged_events_.size() >= kTraceEventBufferSize) 629 if (logged_events_.size() >= kTraceEventBufferSize)
596 return -1; 630 return -1;
597 631
598 int thread_id = static_cast<int>(PlatformThread::CurrentId()); 632 int thread_id = static_cast<int>(PlatformThread::CurrentId());
599 633
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 if (flags & TRACE_EVENT_FLAG_MANGLE_ID) 679 if (flags & TRACE_EVENT_FLAG_MANGLE_ID)
646 id ^= process_id_hash_; 680 id ^= process_id_hash_;
647 681
648 ret_begin_id = static_cast<int>(logged_events_.size()); 682 ret_begin_id = static_cast<int>(logged_events_.size());
649 logged_events_.push_back( 683 logged_events_.push_back(
650 TraceEvent(thread_id, 684 TraceEvent(thread_id,
651 now, phase, category_enabled, name, id, 685 now, phase, category_enabled, name, id,
652 num_args, arg_names, arg_types, arg_values, 686 num_args, arg_names, arg_types, arg_values,
653 flags)); 687 flags));
654 688
655 if (logged_events_.size() == kTraceEventBufferSize) { 689 if (logged_events_.size() == kTraceEventBufferSize)
656 buffer_full_callback_copy = buffer_full_callback_; 690 notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL);
691
692 if (watch_category_ == category_enabled && watch_event_name_ == name &&
693 --watch_count_ == 0) {
694 notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
695 // Clear watch state now so that only the one notification occurs.
696 watch_category_ = NULL;
697 watch_event_name_ = "";
657 } 698 }
658 } // release lock 699 } // release lock
659 700
660 if (!buffer_full_callback_copy.is_null()) 701 notifier.SendNotificationIfAny();
661 buffer_full_callback_copy.Run();
662 702
663 return ret_begin_id; 703 return ret_begin_id;
664 } 704 }
665 705
666 void TraceLog::AddTraceEventEtw(char phase, 706 void TraceLog::AddTraceEventEtw(char phase,
667 const char* name, 707 const char* name,
668 const void* id, 708 const void* id,
669 const char* extra) { 709 const char* extra) {
670 #if defined(OS_WIN) 710 #if defined(OS_WIN)
671 TraceEventETWProvider::Trace(name, phase, id, extra); 711 TraceEventETWProvider::Trace(name, phase, id, extra);
672 #endif 712 #endif
673 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, 713 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
674 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); 714 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
675 } 715 }
676 716
677 void TraceLog::AddTraceEventEtw(char phase, 717 void TraceLog::AddTraceEventEtw(char phase,
678 const char* name, 718 const char* name,
679 const void* id, 719 const void* id,
680 const std::string& extra) 720 const std::string& extra)
681 { 721 {
682 #if defined(OS_WIN) 722 #if defined(OS_WIN)
683 TraceEventETWProvider::Trace(name, phase, id, extra); 723 TraceEventETWProvider::Trace(name, phase, id, extra);
684 #endif 724 #endif
685 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, 725 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
686 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); 726 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
687 } 727 }
688 728
729 void TraceLog::SetWatchEvent(const char* category_name,
730 const char* event_name,
731 int num_occurrences) {
732 DCHECK(num_occurrences > 0);
733 const unsigned char* category = GetCategoryEnabled(category_name);
734 NotificationHelper notifier(this);
735 {
736 AutoLock lock(lock_);
737 watch_category_ = category;
738 watch_event_name_ = event_name;
739 watch_count_ = num_occurrences;
740
741 // First, search existing events for watch event because we want to catch it
742 // even if it has already occurred.
743 for (size_t i = 0u; i < logged_events_.size(); ++i) {
744 if (category == logged_events_[i].category_enabled() &&
745 strcmp(event_name, logged_events_[i].name()) == 0 &&
746 --watch_count_ == 0) {
747 notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
748 // Clear watch state now so that only the one notification occurs.
749 watch_category_ = NULL;
750 watch_event_name_ = "";
751 break;
752 }
753 }
754 } // release lock
755
756 notifier.SendNotificationIfAny();
757 }
758
759 void TraceLog::CancelWatchEvent() {
760 AutoLock lock(lock_);
761 watch_category_ = NULL;
762 watch_event_name_ = "";
763 watch_count_ = 0;
764 }
765
689 void TraceLog::AddClockSyncMetadataEvents() { 766 void TraceLog::AddClockSyncMetadataEvents() {
690 #if defined(OS_ANDROID) 767 #if defined(OS_ANDROID)
691 // Since Android does not support sched_setaffinity, we cannot establish clock 768 // Since Android does not support sched_setaffinity, we cannot establish clock
692 // sync unless the scheduler clock is set to global. If the trace_clock file 769 // sync unless the scheduler clock is set to global. If the trace_clock file
693 // can't be read, we will assume the kernel doesn't support tracing and do 770 // can't be read, we will assume the kernel doesn't support tracing and do
694 // nothing. 771 // nothing.
695 std::string clock_mode; 772 std::string clock_mode;
696 if (!file_util::ReadFileToString( 773 if (!file_util::ReadFileToString(
697 FilePath("/sys/kernel/debug/tracing/trace_clock"), 774 FilePath("/sys/kernel/debug/tracing/trace_clock"),
698 &clock_mode)) 775 &clock_mode))
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
760 // Create a FNV hash from the process ID for XORing. 837 // Create a FNV hash from the process ID for XORing.
761 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. 838 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details.
762 unsigned long long offset_basis = 14695981039346656037ull; 839 unsigned long long offset_basis = 14695981039346656037ull;
763 unsigned long long fnv_prime = 1099511628211ull; 840 unsigned long long fnv_prime = 1099511628211ull;
764 unsigned long long pid = static_cast<unsigned long long>(process_id_); 841 unsigned long long pid = static_cast<unsigned long long>(process_id_);
765 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; 842 process_id_hash_ = (offset_basis ^ pid) * fnv_prime;
766 } 843 }
767 844
768 } // namespace debug 845 } // namespace debug
769 } // namespace base 846 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698