OLD | NEW |
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/leak_annotations.h" |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 } | 341 } |
342 | 342 |
343 // static | 343 // static |
344 TraceLog* TraceLog::GetInstance() { | 344 TraceLog* TraceLog::GetInstance() { |
345 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get(); | 345 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get(); |
346 } | 346 } |
347 | 347 |
348 TraceLog::TraceLog() | 348 TraceLog::TraceLog() |
349 : enabled_(false), | 349 : enabled_(false), |
350 dispatching_to_observer_list_(false), | 350 dispatching_to_observer_list_(false), |
| 351 next_fake_thread_id_(-1), |
351 watch_category_(NULL) { | 352 watch_category_(NULL) { |
352 // Trace is enabled or disabled on one thread while other threads are | 353 // Trace is enabled or disabled on one thread while other threads are |
353 // accessing the enabled flag. We don't care whether edge-case events are | 354 // accessing the enabled flag. We don't care whether edge-case events are |
354 // traced or not, so we allow races on the enabled flag to keep the trace | 355 // traced or not, so we allow races on the enabled flag to keep the trace |
355 // macros fast. | 356 // macros fast. |
356 // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots: | 357 // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots: |
357 // ANNOTATE_BENIGN_RACE_SIZED(g_category_enabled, sizeof(g_category_enabled), | 358 // ANNOTATE_BENIGN_RACE_SIZED(g_category_enabled, sizeof(g_category_enabled), |
358 // "trace_event category enabled"); | 359 // "trace_event category enabled"); |
359 for (int i = 0; i < TRACE_EVENT_MAX_CATEGORIES; ++i) { | 360 for (int i = 0; i < TRACE_EVENT_MAX_CATEGORIES; ++i) { |
360 ANNOTATE_BENIGN_RACE(&g_category_enabled[i], | 361 ANNOTATE_BENIGN_RACE(&g_category_enabled[i], |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
587 scoped_refptr<RefCountedString> json_events_str_ptr = | 588 scoped_refptr<RefCountedString> json_events_str_ptr = |
588 new RefCountedString(); | 589 new RefCountedString(); |
589 TraceEvent::AppendEventsAsJSON(previous_logged_events, | 590 TraceEvent::AppendEventsAsJSON(previous_logged_events, |
590 i, | 591 i, |
591 kTraceEventBatchSize, | 592 kTraceEventBatchSize, |
592 &(json_events_str_ptr->data())); | 593 &(json_events_str_ptr->data())); |
593 cb.Run(json_events_str_ptr); | 594 cb.Run(json_events_str_ptr); |
594 } | 595 } |
595 } | 596 } |
596 | 597 |
| 598 int TraceLog::AddTraceRawEvent(char phase, |
| 599 const unsigned char* category_enabled, |
| 600 const char* thread_name, |
| 601 const char* name, |
| 602 int64 timestamp, |
| 603 unsigned long long id, |
| 604 int num_args, |
| 605 const char** arg_names, |
| 606 const unsigned char* arg_types, |
| 607 const unsigned long long* arg_values, |
| 608 int threshold_begin_id, |
| 609 long long threshold, |
| 610 unsigned char flags) { |
| 611 DCHECK(thread_name); |
| 612 DCHECK(name); |
| 613 TimeTicks now = TimeTicks::FromInternalValue(timestamp); |
| 614 NotificationHelper notifier(this); |
| 615 int ret_begin_id = -1; |
| 616 { |
| 617 AutoLock lock(lock_); |
| 618 if (!*category_enabled) |
| 619 return -1; |
| 620 if (logged_events_.size() >= kTraceEventBufferSize) |
| 621 return -1; |
| 622 |
| 623 int thread_id; |
| 624 base::hash_map<std::string, int>::iterator existing_id = |
| 625 fake_thread_names_.find(thread_name); |
| 626 if (existing_id == fake_thread_names_.end()) { |
| 627 // This is a new thread name, add a new id. |
| 628 thread_id = next_fake_thread_id_; |
| 629 next_fake_thread_id_--; |
| 630 |
| 631 fake_thread_names_[thread_name] = thread_id; |
| 632 thread_names_[thread_id] = thread_name; |
| 633 } else { |
| 634 thread_id = existing_id->second; |
| 635 } |
| 636 |
| 637 ret_begin_id = AddTraceEventInternal(notifier, now, phase, category_enabled, |
| 638 thread_id, name, id, num_args, |
| 639 arg_names, arg_types, arg_values, |
| 640 threshold_begin_id, threshold, flags); |
| 641 } // release lock |
| 642 |
| 643 notifier.SendNotificationIfAny(); |
| 644 |
| 645 return ret_begin_id; |
| 646 } |
| 647 |
597 int TraceLog::AddTraceEvent(char phase, | 648 int TraceLog::AddTraceEvent(char phase, |
598 const unsigned char* category_enabled, | 649 const unsigned char* category_enabled, |
599 const char* name, | 650 const char* name, |
600 unsigned long long id, | 651 unsigned long long id, |
601 int num_args, | 652 int num_args, |
602 const char** arg_names, | 653 const char** arg_names, |
603 const unsigned char* arg_types, | 654 const unsigned char* arg_types, |
604 const unsigned long long* arg_values, | 655 const unsigned long long* arg_values, |
605 int threshold_begin_id, | 656 int threshold_begin_id, |
606 long long threshold, | 657 long long threshold, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 bool found = std::find(existing_names.begin(), | 696 bool found = std::find(existing_names.begin(), |
646 existing_names.end(), | 697 existing_names.end(), |
647 new_name) != existing_names.end(); | 698 new_name) != existing_names.end(); |
648 if (!found) { | 699 if (!found) { |
649 existing_name->second.push_back(','); | 700 existing_name->second.push_back(','); |
650 existing_name->second.append(new_name); | 701 existing_name->second.append(new_name); |
651 } | 702 } |
652 } | 703 } |
653 } | 704 } |
654 | 705 |
655 if (threshold_begin_id > -1) { | 706 ret_begin_id = AddTraceEventInternal(notifier, now, phase, category_enabled, |
656 DCHECK(phase == TRACE_EVENT_PHASE_END); | 707 thread_id, name, id, num_args, |
657 size_t begin_i = static_cast<size_t>(threshold_begin_id); | 708 arg_names, arg_types, arg_values, |
658 // Return now if there has been a flush since the begin event was posted. | 709 threshold_begin_id, threshold, flags); |
659 if (begin_i >= logged_events_.size()) | |
660 return -1; | |
661 // Determine whether to drop the begin/end pair. | |
662 TimeDelta elapsed = now - logged_events_[begin_i].timestamp(); | |
663 if (elapsed < TimeDelta::FromMicroseconds(threshold)) { | |
664 // Remove begin event and do not add end event. | |
665 // This will be expensive if there have been other events in the | |
666 // mean time (should be rare). | |
667 logged_events_.erase(logged_events_.begin() + begin_i); | |
668 return -1; | |
669 } | |
670 } | |
671 | |
672 if (flags & TRACE_EVENT_FLAG_MANGLE_ID) | |
673 id ^= process_id_hash_; | |
674 | |
675 ret_begin_id = static_cast<int>(logged_events_.size()); | |
676 logged_events_.push_back( | |
677 TraceEvent(thread_id, | |
678 now, phase, category_enabled, name, id, | |
679 num_args, arg_names, arg_types, arg_values, | |
680 flags)); | |
681 | |
682 if (logged_events_.size() == kTraceEventBufferSize) | |
683 notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL); | |
684 | |
685 if (watch_category_ == category_enabled && watch_event_name_ == name) | |
686 notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION); | |
687 } // release lock | 710 } // release lock |
688 | 711 |
689 notifier.SendNotificationIfAny(); | 712 notifier.SendNotificationIfAny(); |
690 | 713 |
691 return ret_begin_id; | 714 return ret_begin_id; |
692 } | 715 } |
| 716 |
| 717 int TraceLog::AddTraceEventInternal(NotificationHelper& notifier, |
| 718 TimeTicks timestamp, |
| 719 char phase, |
| 720 const unsigned char* category_enabled, |
| 721 int thread_id, |
| 722 const char* name, |
| 723 unsigned long long id, |
| 724 int num_args, |
| 725 const char** arg_names, |
| 726 const unsigned char* arg_types, |
| 727 const unsigned long long* arg_values, |
| 728 int threshold_begin_id, |
| 729 long long threshold, |
| 730 unsigned char flags) { |
| 731 if (threshold_begin_id > -1) { |
| 732 DCHECK(phase == TRACE_EVENT_PHASE_END); |
| 733 size_t begin_i = static_cast<size_t>(threshold_begin_id); |
| 734 // Return now if there has been a flush since the begin event was posted. |
| 735 if (begin_i >= logged_events_.size()) |
| 736 return -1; |
| 737 // Determine whether to drop the begin/end pair. |
| 738 TimeDelta elapsed = timestamp - logged_events_[begin_i].timestamp(); |
| 739 if (elapsed < TimeDelta::FromMicroseconds(threshold)) { |
| 740 // Remove begin event and do not add end event. |
| 741 // This will be expensive if there have been other events in the |
| 742 // mean time (should be rare). |
| 743 logged_events_.erase(logged_events_.begin() + begin_i); |
| 744 return -1; |
| 745 } |
| 746 } |
| 747 |
| 748 if (flags & TRACE_EVENT_FLAG_MANGLE_ID) |
| 749 id ^= process_id_hash_; |
| 750 |
| 751 int ret_begin_id = static_cast<int>(logged_events_.size()); |
| 752 logged_events_.push_back( |
| 753 TraceEvent(thread_id, |
| 754 timestamp, phase, category_enabled, name, id, |
| 755 num_args, arg_names, arg_types, arg_values, |
| 756 flags)); |
| 757 |
| 758 if (logged_events_.size() == kTraceEventBufferSize) |
| 759 notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL); |
| 760 |
| 761 if (watch_category_ == category_enabled && watch_event_name_ == name) |
| 762 notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION); |
| 763 |
| 764 return ret_begin_id; |
| 765 } |
693 | 766 |
694 void TraceLog::AddTraceEventEtw(char phase, | 767 void TraceLog::AddTraceEventEtw(char phase, |
695 const char* name, | 768 const char* name, |
696 const void* id, | 769 const void* id, |
697 const char* extra) { | 770 const char* extra) { |
698 #if defined(OS_WIN) | 771 #if defined(OS_WIN) |
699 TraceEventETWProvider::Trace(name, phase, id, extra); | 772 TraceEventETWProvider::Trace(name, phase, id, extra); |
700 #endif | 773 #endif |
701 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, | 774 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, |
702 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); | 775 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
784 // Create a FNV hash from the process ID for XORing. | 857 // Create a FNV hash from the process ID for XORing. |
785 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. | 858 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. |
786 unsigned long long offset_basis = 14695981039346656037ull; | 859 unsigned long long offset_basis = 14695981039346656037ull; |
787 unsigned long long fnv_prime = 1099511628211ull; | 860 unsigned long long fnv_prime = 1099511628211ull; |
788 unsigned long long pid = static_cast<unsigned long long>(process_id_); | 861 unsigned long long pid = static_cast<unsigned long long>(process_id_); |
789 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; | 862 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; |
790 } | 863 } |
791 | 864 |
792 } // namespace debug | 865 } // namespace debug |
793 } // namespace base | 866 } // namespace base |
OLD | NEW |