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/test/trace_event_analyzer.h" | 5 #include "base/test/trace_event_analyzer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <math.h> | 8 #include <math.h> |
| 9 #include <set> |
9 | 10 |
10 #include "base/json/json_reader.h" | 11 #include "base/json/json_reader.h" |
11 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
12 #include "base/values.h" | 13 #include "base/values.h" |
13 | 14 |
14 namespace trace_analyzer { | 15 namespace trace_analyzer { |
15 | 16 |
16 // TraceEvent | 17 // TraceEvent |
17 | 18 |
18 TraceEvent::TraceEvent() | 19 TraceEvent::TraceEvent() |
(...skipping 18 matching lines...) Expand all Loading... |
37 base::DictionaryValue* args = NULL; | 38 base::DictionaryValue* args = NULL; |
38 | 39 |
39 if (!dictionary->GetString("ph", &phase_str)) { | 40 if (!dictionary->GetString("ph", &phase_str)) { |
40 LOG(ERROR) << "ph is missing from TraceEvent JSON"; | 41 LOG(ERROR) << "ph is missing from TraceEvent JSON"; |
41 return false; | 42 return false; |
42 } | 43 } |
43 | 44 |
44 phase = *phase_str.data(); | 45 phase = *phase_str.data(); |
45 | 46 |
46 bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA); | 47 bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA); |
47 bool require_id = (phase == TRACE_EVENT_PHASE_START || | 48 bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN || |
48 phase == TRACE_EVENT_PHASE_FINISH); | 49 phase == TRACE_EVENT_PHASE_ASYNC_STEP || |
| 50 phase == TRACE_EVENT_PHASE_ASYNC_END); |
49 | 51 |
50 if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) { | 52 if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) { |
51 LOG(ERROR) << "pid is missing from TraceEvent JSON"; | 53 LOG(ERROR) << "pid is missing from TraceEvent JSON"; |
52 return false; | 54 return false; |
53 } | 55 } |
54 if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) { | 56 if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) { |
55 LOG(ERROR) << "tid is missing from TraceEvent JSON"; | 57 LOG(ERROR) << "tid is missing from TraceEvent JSON"; |
56 return false; | 58 return false; |
57 } | 59 } |
58 if (require_origin && !dictionary->GetDouble("ts", ×tamp)) { | 60 if (require_origin && !dictionary->GetDouble("ts", ×tamp)) { |
59 LOG(ERROR) << "ts is missing from TraceEvent JSON"; | 61 LOG(ERROR) << "ts is missing from TraceEvent JSON"; |
60 return false; | 62 return false; |
61 } | 63 } |
62 if (!dictionary->GetString("cat", &category)) { | 64 if (!dictionary->GetString("cat", &category)) { |
63 LOG(ERROR) << "cat is missing from TraceEvent JSON"; | 65 LOG(ERROR) << "cat is missing from TraceEvent JSON"; |
64 return false; | 66 return false; |
65 } | 67 } |
66 if (!dictionary->GetString("name", &name)) { | 68 if (!dictionary->GetString("name", &name)) { |
67 LOG(ERROR) << "name is missing from TraceEvent JSON"; | 69 LOG(ERROR) << "name is missing from TraceEvent JSON"; |
68 return false; | 70 return false; |
69 } | 71 } |
70 if (!dictionary->GetDictionary("args", &args)) { | 72 if (!dictionary->GetDictionary("args", &args)) { |
71 LOG(ERROR) << "args is missing from TraceEvent JSON"; | 73 LOG(ERROR) << "args is missing from TraceEvent JSON"; |
72 return false; | 74 return false; |
73 } | 75 } |
74 if (require_id && !dictionary->GetString("id", &id)) { | 76 if (require_id && !dictionary->GetString("id", &id)) { |
75 LOG(ERROR) << "id is missing from START/FINISH TraceEvent JSON"; | 77 LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON"; |
76 return false; | 78 return false; |
77 } | 79 } |
78 | 80 |
79 // For each argument, copy the type and create a trace_analyzer::TraceValue. | 81 // For each argument, copy the type and create a trace_analyzer::TraceValue. |
80 base::DictionaryValue::key_iterator keyi = args->begin_keys(); | 82 base::DictionaryValue::key_iterator keyi = args->begin_keys(); |
81 for (; keyi != args->end_keys(); ++keyi) { | 83 for (; keyi != args->end_keys(); ++keyi) { |
82 std::string str; | 84 std::string str; |
83 bool boolean = false; | 85 bool boolean = false; |
84 int int_num = 0; | 86 int int_num = 0; |
85 double double_num = 0.0; | 87 double double_num = 0.0; |
(...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 Query begin(Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_BEGIN)); | 697 Query begin(Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_BEGIN)); |
696 Query end(Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_END)); | 698 Query end(Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_END)); |
697 Query match(Query::EventName() == Query::OtherName() && | 699 Query match(Query::EventName() == Query::OtherName() && |
698 Query::EventCategory() == Query::OtherCategory() && | 700 Query::EventCategory() == Query::OtherCategory() && |
699 Query::EventTid() == Query::OtherTid() && | 701 Query::EventTid() == Query::OtherTid() && |
700 Query::EventPid() == Query::OtherPid()); | 702 Query::EventPid() == Query::OtherPid()); |
701 | 703 |
702 AssociateEvents(begin, end, match); | 704 AssociateEvents(begin, end, match); |
703 } | 705 } |
704 | 706 |
705 void TraceAnalyzer::AssociateStartFinishEvents() { | 707 void TraceAnalyzer::AssociateAsyncBeginEndEvents() { |
706 using trace_analyzer::Query; | 708 using trace_analyzer::Query; |
707 | 709 |
708 Query begin(Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_START)); | 710 Query begin( |
709 Query end(Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_FINISH)); | 711 Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_ASYNC_BEGIN) || |
| 712 Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_ASYNC_STEP)); |
| 713 Query end(Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_ASYNC_END) || |
| 714 Query::EventPhase() == Query::Phase(TRACE_EVENT_PHASE_ASYNC_STEP)); |
710 Query match(Query::EventName() == Query::OtherName() && | 715 Query match(Query::EventName() == Query::OtherName() && |
711 Query::EventCategory() == Query::OtherCategory() && | 716 Query::EventCategory() == Query::OtherCategory() && |
712 Query::EventId() == Query::OtherId()); | 717 Query::EventId() == Query::OtherId()); |
713 | 718 |
714 AssociateEvents(begin, end, match); | 719 AssociateEvents(begin, end, match); |
715 } | 720 } |
716 | 721 |
717 void TraceAnalyzer::AssociateEvents(const Query& first, | 722 void TraceAnalyzer::AssociateEvents(const Query& first, |
718 const Query& second, | 723 const Query& second, |
719 const Query& match) { | 724 const Query& match) { |
720 DCHECK(allow_assocation_changes_) << "AssociateEvents not allowed after " | 725 DCHECK(allow_assocation_changes_) << "AssociateEvents not allowed after " |
721 "FindEvents"; | 726 "FindEvents"; |
722 | 727 |
723 // Search for matching begin/end event pairs. When a matching end is found, | 728 // Search for matching begin/end event pairs. When a matching end is found, |
724 // it is associated with the begin event. | 729 // it is associated with the begin event. |
725 std::vector<TraceEvent*> begin_stack; | 730 std::vector<TraceEvent*> begin_stack; |
726 for (size_t event_index = 0; event_index < raw_events_.size(); | 731 for (size_t event_index = 0; event_index < raw_events_.size(); |
727 ++event_index) { | 732 ++event_index) { |
728 | 733 |
729 TraceEvent& this_event = raw_events_[event_index]; | 734 TraceEvent& this_event = raw_events_[event_index]; |
730 | 735 |
731 if (first.Evaluate(this_event)) { | 736 if (second.Evaluate(this_event)) { |
732 begin_stack.push_back(&this_event); | |
733 } else if (second.Evaluate(this_event)) { | |
734 // Search stack for matching begin, starting from end. | 737 // Search stack for matching begin, starting from end. |
735 for (int stack_index = static_cast<int>(begin_stack.size()) - 1; | 738 for (int stack_index = static_cast<int>(begin_stack.size()) - 1; |
736 stack_index >= 0; --stack_index) { | 739 stack_index >= 0; --stack_index) { |
737 TraceEvent& begin_event = *begin_stack[stack_index]; | 740 TraceEvent& begin_event = *begin_stack[stack_index]; |
738 | 741 |
739 // Temporarily set other to test against the match query. | 742 // Temporarily set other to test against the match query. |
740 const TraceEvent* other_backup = begin_event.other_event; | 743 const TraceEvent* other_backup = begin_event.other_event; |
741 begin_event.other_event = &this_event; | 744 begin_event.other_event = &this_event; |
742 if (match.Evaluate(begin_event)) { | 745 if (match.Evaluate(begin_event)) { |
743 // Found a matching begin/end pair. | 746 // Found a matching begin/end pair. |
744 // Set event association: | |
745 this_event.other_event = &begin_event; | |
746 // Erase the matching begin event index from the stack. | 747 // Erase the matching begin event index from the stack. |
747 begin_stack.erase(begin_stack.begin() + stack_index); | 748 begin_stack.erase(begin_stack.begin() + stack_index); |
748 break; | 749 break; |
749 } | 750 } |
750 | 751 |
751 // Not a match, restore original other and continue. | 752 // Not a match, restore original other and continue. |
752 begin_event.other_event = other_backup; | 753 begin_event.other_event = other_backup; |
753 } | 754 } |
754 } | 755 } |
| 756 // Even if this_event is a |second| event that has matched an earlier |
| 757 // |first| event, it can still also be a |first| event and be associated |
| 758 // with a later |second| event. |
| 759 if (first.Evaluate(this_event)) { |
| 760 begin_stack.push_back(&this_event); |
| 761 } |
755 } | 762 } |
756 } | 763 } |
757 | 764 |
758 void TraceAnalyzer::MergeAssociatedEventArgs() { | 765 void TraceAnalyzer::MergeAssociatedEventArgs() { |
759 for (size_t i = 0; i < raw_events_.size(); ++i) { | 766 for (size_t i = 0; i < raw_events_.size(); ++i) { |
760 if (raw_events_[i].other_event) { | 767 // Merge all associated events with the first event. |
| 768 const TraceEvent* other = raw_events_[i].other_event; |
| 769 // Avoid looping by keeping set of encountered TraceEvents. |
| 770 std::set<const TraceEvent*> encounters; |
| 771 encounters.insert(&raw_events_[i]); |
| 772 while (other && encounters.find(other) == encounters.end()) { |
| 773 encounters.insert(other); |
761 raw_events_[i].arg_numbers.insert( | 774 raw_events_[i].arg_numbers.insert( |
762 raw_events_[i].other_event->arg_numbers.begin(), | 775 other->arg_numbers.begin(), |
763 raw_events_[i].other_event->arg_numbers.end()); | 776 other->arg_numbers.end()); |
764 raw_events_[i].arg_strings.insert( | 777 raw_events_[i].arg_strings.insert( |
765 raw_events_[i].other_event->arg_strings.begin(), | 778 other->arg_strings.begin(), |
766 raw_events_[i].other_event->arg_strings.end()); | 779 other->arg_strings.end()); |
| 780 other = other->other_event; |
767 } | 781 } |
768 } | 782 } |
769 } | 783 } |
770 | 784 |
771 size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) { | 785 size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) { |
772 allow_assocation_changes_ = false; | 786 allow_assocation_changes_ = false; |
773 output->clear(); | 787 output->clear(); |
774 return FindMatchingEvents(raw_events_, query, output); | 788 return FindMatchingEvents(raw_events_, query, output); |
775 } | 789 } |
776 | 790 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
920 size_t count = 0u; | 934 size_t count = 0u; |
921 for (size_t i = begin_position; i < end_position; ++i) { | 935 for (size_t i = begin_position; i < end_position; ++i) { |
922 if (query.Evaluate(*events.at(i))) | 936 if (query.Evaluate(*events.at(i))) |
923 ++count; | 937 ++count; |
924 } | 938 } |
925 return count; | 939 return count; |
926 } | 940 } |
927 | 941 |
928 } // namespace trace_analyzer | 942 } // namespace trace_analyzer |
929 | 943 |
OLD | NEW |