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