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