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
3 // found in the LICENSE file.
4 
5 #include "base/test/trace_event_analyzer.h"
6 
7 #include <math.h>
8 
9 #include <algorithm>
10 #include <set>
11 
12 #include "base/json/json_reader.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/pattern.h"
15 #include "base/values.h"
16 
17 namespace trace_analyzer {
18 
19 // TraceEvent
20 
TraceEvent()21 TraceEvent::TraceEvent()
22     : thread(0, 0),
23       timestamp(0),
24       duration(0),
25       phase(TRACE_EVENT_PHASE_BEGIN),
26       other_event(NULL) {
27 }
28 
~TraceEvent()29 TraceEvent::~TraceEvent() {
30 }
31 
SetFromJSON(const base::Value * event_value)32 bool TraceEvent::SetFromJSON(const base::Value* event_value) {
33   if (event_value->GetType() != base::Value::TYPE_DICTIONARY) {
34     LOG(ERROR) << "Value must be TYPE_DICTIONARY";
35     return false;
36   }
37   const base::DictionaryValue* dictionary =
38       static_cast<const base::DictionaryValue*>(event_value);
39 
40   std::string phase_str;
41   const base::DictionaryValue* args = NULL;
42 
43   if (!dictionary->GetString("ph", &phase_str)) {
44     LOG(ERROR) << "ph is missing from TraceEvent JSON";
45     return false;
46   }
47 
48   phase = *phase_str.data();
49 
50   bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
51   bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
52   bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
53                      phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
54                      phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
55                      phase == TRACE_EVENT_PHASE_ASYNC_END);
56 
57   if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
58     LOG(ERROR) << "pid is missing from TraceEvent JSON";
59     return false;
60   }
61   if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) {
62     LOG(ERROR) << "tid is missing from TraceEvent JSON";
63     return false;
64   }
65   if (require_origin && !dictionary->GetDouble("ts", &timestamp)) {
66     LOG(ERROR) << "ts is missing from TraceEvent JSON";
67     return false;
68   }
69   if (may_have_duration) {
70     dictionary->GetDouble("dur", &duration);
71   }
72   if (!dictionary->GetString("cat", &category)) {
73     LOG(ERROR) << "cat is missing from TraceEvent JSON";
74     return false;
75   }
76   if (!dictionary->GetString("name", &name)) {
77     LOG(ERROR) << "name is missing from TraceEvent JSON";
78     return false;
79   }
80   if (!dictionary->GetDictionary("args", &args)) {
81     LOG(ERROR) << "args is missing from TraceEvent JSON";
82     return false;
83   }
84   if (require_id && !dictionary->GetString("id", &id)) {
85     LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
86     return false;
87   }
88 
89   // For each argument, copy the type and create a trace_analyzer::TraceValue.
90   for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd();
91        it.Advance()) {
92     std::string str;
93     bool boolean = false;
94     int int_num = 0;
95     double double_num = 0.0;
96     if (it.value().GetAsString(&str)) {
97       arg_strings[it.key()] = str;
98     } else if (it.value().GetAsInteger(&int_num)) {
99       arg_numbers[it.key()] = static_cast<double>(int_num);
100     } else if (it.value().GetAsBoolean(&boolean)) {
101       arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0);
102     } else if (it.value().GetAsDouble(&double_num)) {
103       arg_numbers[it.key()] = double_num;
104     } else {
105       LOG(WARNING) << "Value type of argument is not supported: " <<
106           static_cast<int>(it.value().GetType());
107       continue;  // Skip non-supported arguments.
108     }
109   }
110 
111   return true;
112 }
113 
GetAbsTimeToOtherEvent() const114 double TraceEvent::GetAbsTimeToOtherEvent() const {
115   return fabs(other_event->timestamp - timestamp);
116 }
117 
GetArgAsString(const std::string & name,std::string * arg) const118 bool TraceEvent::GetArgAsString(const std::string& name,
119                                 std::string* arg) const {
120   std::map<std::string, std::string>::const_iterator i = arg_strings.find(name);
121   if (i != arg_strings.end()) {
122     *arg = i->second;
123     return true;
124   }
125   return false;
126 }
127 
GetArgAsNumber(const std::string & name,double * arg) const128 bool TraceEvent::GetArgAsNumber(const std::string& name,
129                                 double* arg) const {
130   std::map<std::string, double>::const_iterator i = arg_numbers.find(name);
131   if (i != arg_numbers.end()) {
132     *arg = i->second;
133     return true;
134   }
135   return false;
136 }
137 
HasStringArg(const std::string & name) const138 bool TraceEvent::HasStringArg(const std::string& name) const {
139   return (arg_strings.find(name) != arg_strings.end());
140 }
141 
HasNumberArg(const std::string & name) const142 bool TraceEvent::HasNumberArg(const std::string& name) const {
143   return (arg_numbers.find(name) != arg_numbers.end());
144 }
145 
GetKnownArgAsString(const std::string & name) const146 std::string TraceEvent::GetKnownArgAsString(const std::string& name) const {
147   std::string arg_string;
148   bool result = GetArgAsString(name, &arg_string);
149   DCHECK(result);
150   return arg_string;
151 }
152 
GetKnownArgAsDouble(const std::string & name) const153 double TraceEvent::GetKnownArgAsDouble(const std::string& name) const {
154   double arg_double = 0;
155   bool result = GetArgAsNumber(name, &arg_double);
156   DCHECK(result);
157   return arg_double;
158 }
159 
GetKnownArgAsInt(const std::string & name) const160 int TraceEvent::GetKnownArgAsInt(const std::string& name) const {
161   double arg_double = 0;
162   bool result = GetArgAsNumber(name, &arg_double);
163   DCHECK(result);
164   return static_cast<int>(arg_double);
165 }
166 
GetKnownArgAsBool(const std::string & name) const167 bool TraceEvent::GetKnownArgAsBool(const std::string& name) const {
168   double arg_double = 0;
169   bool result = GetArgAsNumber(name, &arg_double);
170   DCHECK(result);
171   return (arg_double != 0.0);
172 }
173 
174 // QueryNode
175 
QueryNode(const Query & query)176 QueryNode::QueryNode(const Query& query) : query_(query) {
177 }
178 
~QueryNode()179 QueryNode::~QueryNode() {
180 }
181 
182 // Query
183 
Query(TraceEventMember member)184 Query::Query(TraceEventMember member)
185     : type_(QUERY_EVENT_MEMBER),
186       operator_(OP_INVALID),
187       member_(member),
188       number_(0),
189       is_pattern_(false) {
190 }
191 
Query(TraceEventMember member,const std::string & arg_name)192 Query::Query(TraceEventMember member, const std::string& arg_name)
193     : type_(QUERY_EVENT_MEMBER),
194       operator_(OP_INVALID),
195       member_(member),
196       number_(0),
197       string_(arg_name),
198       is_pattern_(false) {
199 }
200 
Query(const Query & query)201 Query::Query(const Query& query)
202     : type_(query.type_),
203       operator_(query.operator_),
204       left_(query.left_),
205       right_(query.right_),
206       member_(query.member_),
207       number_(query.number_),
208       string_(query.string_),
209       is_pattern_(query.is_pattern_) {
210 }
211 
~Query()212 Query::~Query() {
213 }
214 
String(const std::string & str)215 Query Query::String(const std::string& str) {
216   return Query(str);
217 }
218 
Double(double num)219 Query Query::Double(double num) {
220   return Query(num);
221 }
222 
Int(int32_t num)223 Query Query::Int(int32_t num) {
224   return Query(static_cast<double>(num));
225 }
226 
Uint(uint32_t num)227 Query Query::Uint(uint32_t num) {
228   return Query(static_cast<double>(num));
229 }
230 
Bool(bool boolean)231 Query Query::Bool(bool boolean) {
232   return Query(boolean ? 1.0 : 0.0);
233 }
234 
Phase(char phase)235 Query Query::Phase(char phase) {
236   return Query(static_cast<double>(phase));
237 }
238 
Pattern(const std::string & pattern)239 Query Query::Pattern(const std::string& pattern) {
240   Query query(pattern);
241   query.is_pattern_ = true;
242   return query;
243 }
244 
Evaluate(const TraceEvent & event) const245 bool Query::Evaluate(const TraceEvent& event) const {
246   // First check for values that can convert to bool.
247 
248   // double is true if != 0:
249   double bool_value = 0.0;
250   bool is_bool = GetAsDouble(event, &bool_value);
251   if (is_bool)
252     return (bool_value != 0.0);
253 
254   // string is true if it is non-empty:
255   std::string str_value;
256   bool is_str = GetAsString(event, &str_value);
257   if (is_str)
258     return !str_value.empty();
259 
260   DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
261       << "Invalid query: missing boolean expression";
262   DCHECK(left_.get());
263   DCHECK(right_.get() || is_unary_operator());
264 
265   if (is_comparison_operator()) {
266     DCHECK(left().is_value() && right().is_value())
267         << "Invalid query: comparison operator used between event member and "
268            "value.";
269     bool compare_result = false;
270     if (CompareAsDouble(event, &compare_result))
271       return compare_result;
272     if (CompareAsString(event, &compare_result))
273       return compare_result;
274     return false;
275   }
276   // It's a logical operator.
277   switch (operator_) {
278     case OP_AND:
279       return left().Evaluate(event) && right().Evaluate(event);
280     case OP_OR:
281       return left().Evaluate(event) || right().Evaluate(event);
282     case OP_NOT:
283       return !left().Evaluate(event);
284     default:
285       NOTREACHED();
286       return false;
287   }
288 }
289 
CompareAsDouble(const TraceEvent & event,bool * result) const290 bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const {
291   double lhs, rhs;
292   if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
293     return false;
294   switch (operator_) {
295     case OP_EQ:
296       *result = (lhs == rhs);
297       return true;
298     case OP_NE:
299       *result = (lhs != rhs);
300       return true;
301     case OP_LT:
302       *result = (lhs < rhs);
303       return true;
304     case OP_LE:
305       *result = (lhs <= rhs);
306       return true;
307     case OP_GT:
308       *result = (lhs > rhs);
309       return true;
310     case OP_GE:
311       *result = (lhs >= rhs);
312       return true;
313     default:
314       NOTREACHED();
315       return false;
316   }
317 }
318 
CompareAsString(const TraceEvent & event,bool * result) const319 bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
320   std::string lhs, rhs;
321   if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
322     return false;
323   switch (operator_) {
324     case OP_EQ:
325       if (right().is_pattern_)
326         *result = base::MatchPattern(lhs, rhs);
327       else if (left().is_pattern_)
328         *result = base::MatchPattern(rhs, lhs);
329       else
330         *result = (lhs == rhs);
331       return true;
332     case OP_NE:
333       if (right().is_pattern_)
334         *result = !base::MatchPattern(lhs, rhs);
335       else if (left().is_pattern_)
336         *result = !base::MatchPattern(rhs, lhs);
337       else
338         *result = (lhs != rhs);
339       return true;
340     case OP_LT:
341       *result = (lhs < rhs);
342       return true;
343     case OP_LE:
344       *result = (lhs <= rhs);
345       return true;
346     case OP_GT:
347       *result = (lhs > rhs);
348       return true;
349     case OP_GE:
350       *result = (lhs >= rhs);
351       return true;
352     default:
353       NOTREACHED();
354       return false;
355   }
356 }
357 
EvaluateArithmeticOperator(const TraceEvent & event,double * num) const358 bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
359                                        double* num) const {
360   DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_);
361   DCHECK(left_.get());
362   DCHECK(right_.get() || is_unary_operator());
363 
364   double lhs = 0, rhs = 0;
365   if (!left().GetAsDouble(event, &lhs))
366     return false;
367   if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
368     return false;
369 
370   switch (operator_) {
371     case OP_ADD:
372       *num = lhs + rhs;
373       return true;
374     case OP_SUB:
375       *num = lhs - rhs;
376       return true;
377     case OP_MUL:
378       *num = lhs * rhs;
379       return true;
380     case OP_DIV:
381       *num = lhs / rhs;
382       return true;
383     case OP_MOD:
384       *num = static_cast<double>(static_cast<int64_t>(lhs) %
385                                  static_cast<int64_t>(rhs));
386       return true;
387     case OP_NEGATE:
388       *num = -lhs;
389       return true;
390     default:
391       NOTREACHED();
392       return false;
393   }
394 }
395 
GetAsDouble(const TraceEvent & event,double * num) const396 bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
397   switch (type_) {
398     case QUERY_ARITHMETIC_OPERATOR:
399       return EvaluateArithmeticOperator(event, num);
400     case QUERY_EVENT_MEMBER:
401       return GetMemberValueAsDouble(event, num);
402     case QUERY_NUMBER:
403       *num = number_;
404       return true;
405     default:
406       return false;
407   }
408 }
409 
GetAsString(const TraceEvent & event,std::string * str) const410 bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
411   switch (type_) {
412     case QUERY_EVENT_MEMBER:
413       return GetMemberValueAsString(event, str);
414     case QUERY_STRING:
415       *str = string_;
416       return true;
417     default:
418       return false;
419   }
420 }
421 
GetMemberValueAsDouble(const TraceEvent & event,double * num) const422 bool Query::GetMemberValueAsDouble(const TraceEvent& event,
423                                    double* num) const {
424   DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
425 
426   // This could be a request for a member of |event| or a member of |event|'s
427   // associated event. Store the target event in the_event:
428   const TraceEvent* the_event = (member_ < OTHER_PID) ?
429       &event : event.other_event;
430 
431   // Request for member of associated event, but there is no associated event.
432   if (!the_event)
433     return false;
434 
435   switch (member_) {
436     case EVENT_PID:
437     case OTHER_PID:
438       *num = static_cast<double>(the_event->thread.process_id);
439       return true;
440     case EVENT_TID:
441     case OTHER_TID:
442       *num = static_cast<double>(the_event->thread.thread_id);
443       return true;
444     case EVENT_TIME:
445     case OTHER_TIME:
446       *num = the_event->timestamp;
447       return true;
448     case EVENT_DURATION:
449       if (!the_event->has_other_event())
450         return false;
451       *num = the_event->GetAbsTimeToOtherEvent();
452       return true;
453     case EVENT_COMPLETE_DURATION:
454       if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE)
455         return false;
456       *num = the_event->duration;
457       return true;
458     case EVENT_PHASE:
459     case OTHER_PHASE:
460       *num = static_cast<double>(the_event->phase);
461       return true;
462     case EVENT_HAS_STRING_ARG:
463     case OTHER_HAS_STRING_ARG:
464       *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0);
465       return true;
466     case EVENT_HAS_NUMBER_ARG:
467     case OTHER_HAS_NUMBER_ARG:
468       *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0);
469       return true;
470     case EVENT_ARG:
471     case OTHER_ARG: {
472       // Search for the argument name and return its value if found.
473       std::map<std::string, double>::const_iterator num_i =
474           the_event->arg_numbers.find(string_);
475       if (num_i == the_event->arg_numbers.end())
476         return false;
477       *num = num_i->second;
478       return true;
479     }
480     case EVENT_HAS_OTHER:
481       // return 1.0 (true) if the other event exists
482       *num = event.other_event ? 1.0 : 0.0;
483       return true;
484     default:
485       return false;
486   }
487 }
488 
GetMemberValueAsString(const TraceEvent & event,std::string * str) const489 bool Query::GetMemberValueAsString(const TraceEvent& event,
490                                    std::string* str) const {
491   DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
492 
493   // This could be a request for a member of |event| or a member of |event|'s
494   // associated event. Store the target event in the_event:
495   const TraceEvent* the_event = (member_ < OTHER_PID) ?
496       &event : event.other_event;
497 
498   // Request for member of associated event, but there is no associated event.
499   if (!the_event)
500     return false;
501 
502   switch (member_) {
503     case EVENT_CATEGORY:
504     case OTHER_CATEGORY:
505       *str = the_event->category;
506       return true;
507     case EVENT_NAME:
508     case OTHER_NAME:
509       *str = the_event->name;
510       return true;
511     case EVENT_ID:
512     case OTHER_ID:
513       *str = the_event->id;
514       return true;
515     case EVENT_ARG:
516     case OTHER_ARG: {
517       // Search for the argument name and return its value if found.
518       std::map<std::string, std::string>::const_iterator str_i =
519           the_event->arg_strings.find(string_);
520       if (str_i == the_event->arg_strings.end())
521         return false;
522       *str = str_i->second;
523       return true;
524     }
525     default:
526       return false;
527   }
528 }
529 
Query(const std::string & str)530 Query::Query(const std::string& str)
531     : type_(QUERY_STRING),
532       operator_(OP_INVALID),
533       member_(EVENT_INVALID),
534       number_(0),
535       string_(str),
536       is_pattern_(false) {
537 }
538 
Query(double num)539 Query::Query(double num)
540     : type_(QUERY_NUMBER),
541       operator_(OP_INVALID),
542       member_(EVENT_INVALID),
543       number_(num),
544       is_pattern_(false) {
545 }
left() const546 const Query& Query::left() const {
547   return left_->query();
548 }
549 
right() const550 const Query& Query::right() const {
551   return right_->query();
552 }
553 
operator ==(const Query & rhs) const554 Query Query::operator==(const Query& rhs) const {
555   return Query(*this, rhs, OP_EQ);
556 }
557 
operator !=(const Query & rhs) const558 Query Query::operator!=(const Query& rhs) const {
559   return Query(*this, rhs, OP_NE);
560 }
561 
operator <(const Query & rhs) const562 Query Query::operator<(const Query& rhs) const {
563   return Query(*this, rhs, OP_LT);
564 }
565 
operator <=(const Query & rhs) const566 Query Query::operator<=(const Query& rhs) const {
567   return Query(*this, rhs, OP_LE);
568 }
569 
operator >(const Query & rhs) const570 Query Query::operator>(const Query& rhs) const {
571   return Query(*this, rhs, OP_GT);
572 }
573 
operator >=(const Query & rhs) const574 Query Query::operator>=(const Query& rhs) const {
575   return Query(*this, rhs, OP_GE);
576 }
577 
operator &&(const Query & rhs) const578 Query Query::operator&&(const Query& rhs) const {
579   return Query(*this, rhs, OP_AND);
580 }
581 
operator ||(const Query & rhs) const582 Query Query::operator||(const Query& rhs) const {
583   return Query(*this, rhs, OP_OR);
584 }
585 
operator !() const586 Query Query::operator!() const {
587   return Query(*this, OP_NOT);
588 }
589 
operator +(const Query & rhs) const590 Query Query::operator+(const Query& rhs) const {
591   return Query(*this, rhs, OP_ADD);
592 }
593 
operator -(const Query & rhs) const594 Query Query::operator-(const Query& rhs) const {
595   return Query(*this, rhs, OP_SUB);
596 }
597 
operator *(const Query & rhs) const598 Query Query::operator*(const Query& rhs) const {
599   return Query(*this, rhs, OP_MUL);
600 }
601 
operator /(const Query & rhs) const602 Query Query::operator/(const Query& rhs) const {
603   return Query(*this, rhs, OP_DIV);
604 }
605 
operator %(const Query & rhs) const606 Query Query::operator%(const Query& rhs) const {
607   return Query(*this, rhs, OP_MOD);
608 }
609 
operator -() const610 Query Query::operator-() const {
611   return Query(*this, OP_NEGATE);
612 }
613 
614 
Query(const Query & left,const Query & right,Operator binary_op)615 Query::Query(const Query& left, const Query& right, Operator binary_op)
616     : operator_(binary_op),
617       left_(new QueryNode(left)),
618       right_(new QueryNode(right)),
619       member_(EVENT_INVALID),
620       number_(0) {
621   type_ = (binary_op < OP_ADD ?
622            QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
623 }
624 
Query(const Query & left,Operator unary_op)625 Query::Query(const Query& left, Operator unary_op)
626     : operator_(unary_op),
627       left_(new QueryNode(left)),
628       member_(EVENT_INVALID),
629       number_(0) {
630   type_ = (unary_op < OP_ADD ?
631            QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
632 }
633 
634 namespace {
635 
636 // Search |events| for |query| and add matches to |output|.
FindMatchingEvents(const std::vector<TraceEvent> & events,const Query & query,TraceEventVector * output,bool ignore_metadata_events)637 size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
638                           const Query& query,
639                           TraceEventVector* output,
640                           bool ignore_metadata_events) {
641   for (size_t i = 0; i < events.size(); ++i) {
642     if (ignore_metadata_events && events[i].phase == TRACE_EVENT_PHASE_METADATA)
643       continue;
644     if (query.Evaluate(events[i]))
645       output->push_back(&events[i]);
646   }
647   return output->size();
648 }
649 
ParseEventsFromJson(const std::string & json,std::vector<TraceEvent> * output)650 bool ParseEventsFromJson(const std::string& json,
651                          std::vector<TraceEvent>* output) {
652   scoped_ptr<base::Value> root = base::JSONReader::Read(json);
653 
654   base::ListValue* root_list = NULL;
655   if (!root.get() || !root->GetAsList(&root_list))
656     return false;
657 
658   for (size_t i = 0; i < root_list->GetSize(); ++i) {
659     base::Value* item = NULL;
660     if (root_list->Get(i, &item)) {
661       TraceEvent event;
662       if (event.SetFromJSON(item))
663         output->push_back(event);
664       else
665         return false;
666     }
667   }
668 
669   return true;
670 }
671 
672 }  // namespace
673 
674 // TraceAnalyzer
675 
TraceAnalyzer()676 TraceAnalyzer::TraceAnalyzer()
677     : ignore_metadata_events_(false),
678       allow_assocation_changes_(true) {}
679 
~TraceAnalyzer()680 TraceAnalyzer::~TraceAnalyzer() {
681 }
682 
683 // static
Create(const std::string & json_events)684 TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) {
685   scoped_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
686   if (analyzer->SetEvents(json_events))
687     return analyzer.release();
688   return NULL;
689 }
690 
SetEvents(const std::string & json_events)691 bool TraceAnalyzer::SetEvents(const std::string& json_events) {
692   raw_events_.clear();
693   if (!ParseEventsFromJson(json_events, &raw_events_))
694     return false;
695   std::stable_sort(raw_events_.begin(), raw_events_.end());
696   ParseMetadata();
697   return true;
698 }
699 
AssociateBeginEndEvents()700 void TraceAnalyzer::AssociateBeginEndEvents() {
701   using trace_analyzer::Query;
702 
703   Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
704   Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
705   Query match(Query::EventName() == Query::OtherName() &&
706               Query::EventCategory() == Query::OtherCategory() &&
707               Query::EventTid() == Query::OtherTid() &&
708               Query::EventPid() == Query::OtherPid());
709 
710   AssociateEvents(begin, end, match);
711 }
712 
AssociateAsyncBeginEndEvents()713 void TraceAnalyzer::AssociateAsyncBeginEndEvents() {
714   using trace_analyzer::Query;
715 
716   Query begin(
717       Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
718       Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
719       Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
720   Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
721             Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
722             Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
723   Query match(Query::EventName() == Query::OtherName() &&
724               Query::EventCategory() == Query::OtherCategory() &&
725               Query::EventId() == Query::OtherId());
726 
727   AssociateEvents(begin, end, match);
728 }
729 
AssociateEvents(const Query & first,const Query & second,const Query & match)730 void TraceAnalyzer::AssociateEvents(const Query& first,
731                                     const Query& second,
732                                     const Query& match) {
733   DCHECK(allow_assocation_changes_)
734       << "AssociateEvents not allowed after FindEvents";
735 
736   // Search for matching begin/end event pairs. When a matching end is found,
737   // it is associated with the begin event.
738   std::vector<TraceEvent*> begin_stack;
739   for (size_t event_index = 0; event_index < raw_events_.size();
740        ++event_index) {
741 
742     TraceEvent& this_event = raw_events_[event_index];
743 
744     if (second.Evaluate(this_event)) {
745       // Search stack for matching begin, starting from end.
746       for (int stack_index = static_cast<int>(begin_stack.size()) - 1;
747            stack_index >= 0; --stack_index) {
748         TraceEvent& begin_event = *begin_stack[stack_index];
749 
750         // Temporarily set other to test against the match query.
751         const TraceEvent* other_backup = begin_event.other_event;
752         begin_event.other_event = &this_event;
753         if (match.Evaluate(begin_event)) {
754           // Found a matching begin/end pair.
755           // Erase the matching begin event index from the stack.
756           begin_stack.erase(begin_stack.begin() + stack_index);
757           break;
758         }
759 
760         // Not a match, restore original other and continue.
761         begin_event.other_event = other_backup;
762       }
763     }
764     // Even if this_event is a |second| event that has matched an earlier
765     // |first| event, it can still also be a |first| event and be associated
766     // with a later |second| event.
767     if (first.Evaluate(this_event)) {
768       begin_stack.push_back(&this_event);
769     }
770   }
771 }
772 
MergeAssociatedEventArgs()773 void TraceAnalyzer::MergeAssociatedEventArgs() {
774   for (size_t i = 0; i < raw_events_.size(); ++i) {
775     // Merge all associated events with the first event.
776     const TraceEvent* other = raw_events_[i].other_event;
777     // Avoid looping by keeping set of encountered TraceEvents.
778     std::set<const TraceEvent*> encounters;
779     encounters.insert(&raw_events_[i]);
780     while (other && encounters.find(other) == encounters.end()) {
781       encounters.insert(other);
782       raw_events_[i].arg_numbers.insert(
783           other->arg_numbers.begin(),
784           other->arg_numbers.end());
785       raw_events_[i].arg_strings.insert(
786           other->arg_strings.begin(),
787           other->arg_strings.end());
788       other = other->other_event;
789     }
790   }
791 }
792 
FindEvents(const Query & query,TraceEventVector * output)793 size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) {
794   allow_assocation_changes_ = false;
795   output->clear();
796   return FindMatchingEvents(
797       raw_events_, query, output, ignore_metadata_events_);
798 }
799 
FindFirstOf(const Query & query)800 const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
801   TraceEventVector output;
802   if (FindEvents(query, &output) > 0)
803     return output.front();
804   return NULL;
805 }
806 
FindLastOf(const Query & query)807 const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
808   TraceEventVector output;
809   if (FindEvents(query, &output) > 0)
810     return output.back();
811   return NULL;
812 }
813 
GetThreadName(const TraceEvent::ProcessThreadID & thread)814 const std::string& TraceAnalyzer::GetThreadName(
815     const TraceEvent::ProcessThreadID& thread) {
816   // If thread is not found, just add and return empty string.
817   return thread_names_[thread];
818 }
819 
ParseMetadata()820 void TraceAnalyzer::ParseMetadata() {
821   for (size_t i = 0; i < raw_events_.size(); ++i) {
822     TraceEvent& this_event = raw_events_[i];
823     // Check for thread name metadata.
824     if (this_event.phase != TRACE_EVENT_PHASE_METADATA ||
825         this_event.name != "thread_name")
826       continue;
827     std::map<std::string, std::string>::const_iterator string_it =
828         this_event.arg_strings.find("name");
829     if (string_it != this_event.arg_strings.end())
830       thread_names_[this_event.thread] = string_it->second;
831   }
832 }
833 
834 // TraceEventVector utility functions.
835 
GetRateStats(const TraceEventVector & events,RateStats * stats,const RateStatsOptions * options)836 bool GetRateStats(const TraceEventVector& events,
837                   RateStats* stats,
838                   const RateStatsOptions* options) {
839   DCHECK(stats);
840   // Need at least 3 events to calculate rate stats.
841   const size_t kMinEvents = 3;
842   if (events.size() < kMinEvents) {
843     LOG(ERROR) << "Not enough events: " << events.size();
844     return false;
845   }
846 
847   std::vector<double> deltas;
848   size_t num_deltas = events.size() - 1;
849   for (size_t i = 0; i < num_deltas; ++i) {
850     double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp;
851     if (delta < 0.0) {
852       LOG(ERROR) << "Events are out of order";
853       return false;
854     }
855     deltas.push_back(delta);
856   }
857 
858   std::sort(deltas.begin(), deltas.end());
859 
860   if (options) {
861     if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
862       LOG(ERROR) << "Attempt to trim too many events";
863       return false;
864     }
865     deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
866     deltas.erase(deltas.end() - options->trim_max, deltas.end());
867   }
868 
869   num_deltas = deltas.size();
870   double delta_sum = 0.0;
871   for (size_t i = 0; i < num_deltas; ++i)
872     delta_sum += deltas[i];
873 
874   stats->min_us = *std::min_element(deltas.begin(), deltas.end());
875   stats->max_us = *std::max_element(deltas.begin(), deltas.end());
876   stats->mean_us = delta_sum / static_cast<double>(num_deltas);
877 
878   double sum_mean_offsets_squared = 0.0;
879   for (size_t i = 0; i < num_deltas; ++i) {
880     double offset = fabs(deltas[i] - stats->mean_us);
881     sum_mean_offsets_squared += offset * offset;
882   }
883   stats->standard_deviation_us =
884       sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
885 
886   return true;
887 }
888 
FindFirstOf(const TraceEventVector & events,const Query & query,size_t position,size_t * return_index)889 bool FindFirstOf(const TraceEventVector& events,
890                  const Query& query,
891                  size_t position,
892                  size_t* return_index) {
893   DCHECK(return_index);
894   for (size_t i = position; i < events.size(); ++i) {
895     if (query.Evaluate(*events[i])) {
896       *return_index = i;
897       return true;
898     }
899   }
900   return false;
901 }
902 
FindLastOf(const TraceEventVector & events,const Query & query,size_t position,size_t * return_index)903 bool FindLastOf(const TraceEventVector& events,
904                 const Query& query,
905                 size_t position,
906                 size_t* return_index) {
907   DCHECK(return_index);
908   for (size_t i = std::min(position + 1, events.size()); i != 0; --i) {
909     if (query.Evaluate(*events[i - 1])) {
910       *return_index = i - 1;
911       return true;
912     }
913   }
914   return false;
915 }
916 
FindClosest(const TraceEventVector & events,const Query & query,size_t position,size_t * return_closest,size_t * return_second_closest)917 bool FindClosest(const TraceEventVector& events,
918                  const Query& query,
919                  size_t position,
920                  size_t* return_closest,
921                  size_t* return_second_closest) {
922   DCHECK(return_closest);
923   if (events.empty() || position >= events.size())
924     return false;
925   size_t closest = events.size();
926   size_t second_closest = events.size();
927   for (size_t i = 0; i < events.size(); ++i) {
928     if (!query.Evaluate(*events.at(i)))
929       continue;
930     if (closest == events.size()) {
931       closest = i;
932       continue;
933     }
934     if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
935         fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
936       second_closest = closest;
937       closest = i;
938     } else if (second_closest == events.size()) {
939       second_closest = i;
940     }
941   }
942 
943   if (closest < events.size() &&
944       (!return_second_closest || second_closest < events.size())) {
945     *return_closest = closest;
946     if (return_second_closest)
947       *return_second_closest = second_closest;
948     return true;
949   }
950 
951   return false;
952 }
953 
CountMatches(const TraceEventVector & events,const Query & query,size_t begin_position,size_t end_position)954 size_t CountMatches(const TraceEventVector& events,
955                     const Query& query,
956                     size_t begin_position,
957                     size_t end_position) {
958   if (begin_position >= events.size())
959     return 0u;
960   end_position = (end_position < events.size()) ? end_position : events.size();
961   size_t count = 0u;
962   for (size_t i = begin_position; i < end_position; ++i) {
963     if (query.Evaluate(*events.at(i)))
964       ++count;
965   }
966   return count;
967 }
968 
969 }  // namespace trace_analyzer
970