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", ×tamp)) {
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