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