Update V8 to version 4.7.21.
[chromium-blink-merge.git] / base / test / trace_event_analyzer.cc
blob93d7f305cc320547ad705804946381b493db25b2
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.
5 #include "base/test/trace_event_analyzer.h"
7 #include <algorithm>
8 #include <math.h>
9 #include <set>
11 #include "base/json/json_reader.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/pattern.h"
14 #include "base/values.h"
16 namespace trace_analyzer {
18 // TraceEvent
20 TraceEvent::TraceEvent()
21 : thread(0, 0),
22 timestamp(0),
23 duration(0),
24 phase(TRACE_EVENT_PHASE_BEGIN),
25 other_event(NULL) {
28 TraceEvent::~TraceEvent() {
31 bool TraceEvent::SetFromJSON(const base::Value* event_value) {
32 if (event_value->GetType() != base::Value::TYPE_DICTIONARY) {
33 LOG(ERROR) << "Value must be TYPE_DICTIONARY";
34 return false;
36 const base::DictionaryValue* dictionary =
37 static_cast<const base::DictionaryValue*>(event_value);
39 std::string phase_str;
40 const base::DictionaryValue* args = NULL;
42 if (!dictionary->GetString("ph", &phase_str)) {
43 LOG(ERROR) << "ph is missing from TraceEvent JSON";
44 return false;
47 phase = *phase_str.data();
49 bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
50 bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
51 bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
52 phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
53 phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
54 phase == TRACE_EVENT_PHASE_ASYNC_END);
56 if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
57 LOG(ERROR) << "pid is missing from TraceEvent JSON";
58 return false;
60 if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) {
61 LOG(ERROR) << "tid is missing from TraceEvent JSON";
62 return false;
64 if (require_origin && !dictionary->GetDouble("ts", &timestamp)) {
65 LOG(ERROR) << "ts is missing from TraceEvent JSON";
66 return false;
68 if (may_have_duration) {
69 dictionary->GetDouble("dur", &duration);
71 if (!dictionary->GetString("cat", &category)) {
72 LOG(ERROR) << "cat is missing from TraceEvent JSON";
73 return false;
75 if (!dictionary->GetString("name", &name)) {
76 LOG(ERROR) << "name is missing from TraceEvent JSON";
77 return false;
79 if (!dictionary->GetDictionary("args", &args)) {
80 LOG(ERROR) << "args is missing from TraceEvent JSON";
81 return false;
83 if (require_id && !dictionary->GetString("id", &id)) {
84 LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
85 return false;
88 // For each argument, copy the type and create a trace_analyzer::TraceValue.
89 for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd();
90 it.Advance()) {
91 std::string str;
92 bool boolean = false;
93 int int_num = 0;
94 double double_num = 0.0;
95 if (it.value().GetAsString(&str)) {
96 arg_strings[it.key()] = str;
97 } else if (it.value().GetAsInteger(&int_num)) {
98 arg_numbers[it.key()] = static_cast<double>(int_num);
99 } else if (it.value().GetAsBoolean(&boolean)) {
100 arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0);
101 } else if (it.value().GetAsDouble(&double_num)) {
102 arg_numbers[it.key()] = double_num;
103 } else {
104 LOG(WARNING) << "Value type of argument is not supported: " <<
105 static_cast<int>(it.value().GetType());
106 continue; // Skip non-supported arguments.
110 return true;
113 double TraceEvent::GetAbsTimeToOtherEvent() const {
114 return fabs(other_event->timestamp - timestamp);
117 bool TraceEvent::GetArgAsString(const std::string& name,
118 std::string* arg) const {
119 std::map<std::string, std::string>::const_iterator i = arg_strings.find(name);
120 if (i != arg_strings.end()) {
121 *arg = i->second;
122 return true;
124 return false;
127 bool TraceEvent::GetArgAsNumber(const std::string& name,
128 double* arg) const {
129 std::map<std::string, double>::const_iterator i = arg_numbers.find(name);
130 if (i != arg_numbers.end()) {
131 *arg = i->second;
132 return true;
134 return false;
137 bool TraceEvent::HasStringArg(const std::string& name) const {
138 return (arg_strings.find(name) != arg_strings.end());
141 bool TraceEvent::HasNumberArg(const std::string& name) const {
142 return (arg_numbers.find(name) != arg_numbers.end());
145 std::string TraceEvent::GetKnownArgAsString(const std::string& name) const {
146 std::string arg_string;
147 bool result = GetArgAsString(name, &arg_string);
148 DCHECK(result);
149 return arg_string;
152 double TraceEvent::GetKnownArgAsDouble(const std::string& name) const {
153 double arg_double = 0;
154 bool result = GetArgAsNumber(name, &arg_double);
155 DCHECK(result);
156 return arg_double;
159 int TraceEvent::GetKnownArgAsInt(const std::string& name) const {
160 double arg_double = 0;
161 bool result = GetArgAsNumber(name, &arg_double);
162 DCHECK(result);
163 return static_cast<int>(arg_double);
166 bool TraceEvent::GetKnownArgAsBool(const std::string& name) const {
167 double arg_double = 0;
168 bool result = GetArgAsNumber(name, &arg_double);
169 DCHECK(result);
170 return (arg_double != 0.0);
173 // QueryNode
175 QueryNode::QueryNode(const Query& query) : query_(query) {
178 QueryNode::~QueryNode() {
181 // Query
183 Query::Query(TraceEventMember member)
184 : type_(QUERY_EVENT_MEMBER),
185 operator_(OP_INVALID),
186 member_(member),
187 number_(0),
188 is_pattern_(false) {
191 Query::Query(TraceEventMember member, const std::string& arg_name)
192 : type_(QUERY_EVENT_MEMBER),
193 operator_(OP_INVALID),
194 member_(member),
195 number_(0),
196 string_(arg_name),
197 is_pattern_(false) {
200 Query::Query(const Query& query)
201 : type_(query.type_),
202 operator_(query.operator_),
203 left_(query.left_),
204 right_(query.right_),
205 member_(query.member_),
206 number_(query.number_),
207 string_(query.string_),
208 is_pattern_(query.is_pattern_) {
211 Query::~Query() {
214 Query Query::String(const std::string& str) {
215 return Query(str);
218 Query Query::Double(double num) {
219 return Query(num);
222 Query Query::Int(int32 num) {
223 return Query(static_cast<double>(num));
226 Query Query::Uint(uint32 num) {
227 return Query(static_cast<double>(num));
230 Query Query::Bool(bool boolean) {
231 return Query(boolean ? 1.0 : 0.0);
234 Query Query::Phase(char phase) {
235 return Query(static_cast<double>(phase));
238 Query Query::Pattern(const std::string& pattern) {
239 Query query(pattern);
240 query.is_pattern_ = true;
241 return query;
244 bool Query::Evaluate(const TraceEvent& event) const {
245 // First check for values that can convert to bool.
247 // double is true if != 0:
248 double bool_value = 0.0;
249 bool is_bool = GetAsDouble(event, &bool_value);
250 if (is_bool)
251 return (bool_value != 0.0);
253 // string is true if it is non-empty:
254 std::string str_value;
255 bool is_str = GetAsString(event, &str_value);
256 if (is_str)
257 return !str_value.empty();
259 DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
260 << "Invalid query: missing boolean expression";
261 DCHECK(left_.get());
262 DCHECK(right_.get() || is_unary_operator());
264 if (is_comparison_operator()) {
265 DCHECK(left().is_value() && right().is_value())
266 << "Invalid query: comparison operator used between event member and "
267 "value.";
268 bool compare_result = false;
269 if (CompareAsDouble(event, &compare_result))
270 return compare_result;
271 if (CompareAsString(event, &compare_result))
272 return compare_result;
273 return false;
275 // It's a logical operator.
276 switch (operator_) {
277 case OP_AND:
278 return left().Evaluate(event) && right().Evaluate(event);
279 case OP_OR:
280 return left().Evaluate(event) || right().Evaluate(event);
281 case OP_NOT:
282 return !left().Evaluate(event);
283 default:
284 NOTREACHED();
285 return false;
289 bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const {
290 double lhs, rhs;
291 if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
292 return false;
293 switch (operator_) {
294 case OP_EQ:
295 *result = (lhs == rhs);
296 return true;
297 case OP_NE:
298 *result = (lhs != rhs);
299 return true;
300 case OP_LT:
301 *result = (lhs < rhs);
302 return true;
303 case OP_LE:
304 *result = (lhs <= rhs);
305 return true;
306 case OP_GT:
307 *result = (lhs > rhs);
308 return true;
309 case OP_GE:
310 *result = (lhs >= rhs);
311 return true;
312 default:
313 NOTREACHED();
314 return false;
318 bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
319 std::string lhs, rhs;
320 if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
321 return false;
322 switch (operator_) {
323 case OP_EQ:
324 if (right().is_pattern_)
325 *result = base::MatchPattern(lhs, rhs);
326 else if (left().is_pattern_)
327 *result = base::MatchPattern(rhs, lhs);
328 else
329 *result = (lhs == rhs);
330 return true;
331 case OP_NE:
332 if (right().is_pattern_)
333 *result = !base::MatchPattern(lhs, rhs);
334 else if (left().is_pattern_)
335 *result = !base::MatchPattern(rhs, lhs);
336 else
337 *result = (lhs != rhs);
338 return true;
339 case OP_LT:
340 *result = (lhs < rhs);
341 return true;
342 case OP_LE:
343 *result = (lhs <= rhs);
344 return true;
345 case OP_GT:
346 *result = (lhs > rhs);
347 return true;
348 case OP_GE:
349 *result = (lhs >= rhs);
350 return true;
351 default:
352 NOTREACHED();
353 return false;
357 bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
358 double* num) const {
359 DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_);
360 DCHECK(left_.get());
361 DCHECK(right_.get() || is_unary_operator());
363 double lhs = 0, rhs = 0;
364 if (!left().GetAsDouble(event, &lhs))
365 return false;
366 if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
367 return false;
369 switch (operator_) {
370 case OP_ADD:
371 *num = lhs + rhs;
372 return true;
373 case OP_SUB:
374 *num = lhs - rhs;
375 return true;
376 case OP_MUL:
377 *num = lhs * rhs;
378 return true;
379 case OP_DIV:
380 *num = lhs / rhs;
381 return true;
382 case OP_MOD:
383 *num = static_cast<double>(static_cast<int64>(lhs) %
384 static_cast<int64>(rhs));
385 return true;
386 case OP_NEGATE:
387 *num = -lhs;
388 return true;
389 default:
390 NOTREACHED();
391 return false;
395 bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
396 switch (type_) {
397 case QUERY_ARITHMETIC_OPERATOR:
398 return EvaluateArithmeticOperator(event, num);
399 case QUERY_EVENT_MEMBER:
400 return GetMemberValueAsDouble(event, num);
401 case QUERY_NUMBER:
402 *num = number_;
403 return true;
404 default:
405 return false;
409 bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
410 switch (type_) {
411 case QUERY_EVENT_MEMBER:
412 return GetMemberValueAsString(event, str);
413 case QUERY_STRING:
414 *str = string_;
415 return true;
416 default:
417 return false;
421 bool Query::GetMemberValueAsDouble(const TraceEvent& event,
422 double* num) const {
423 DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
425 // This could be a request for a member of |event| or a member of |event|'s
426 // associated event. Store the target event in the_event:
427 const TraceEvent* the_event = (member_ < OTHER_PID) ?
428 &event : event.other_event;
430 // Request for member of associated event, but there is no associated event.
431 if (!the_event)
432 return false;
434 switch (member_) {
435 case EVENT_PID:
436 case OTHER_PID:
437 *num = static_cast<double>(the_event->thread.process_id);
438 return true;
439 case EVENT_TID:
440 case OTHER_TID:
441 *num = static_cast<double>(the_event->thread.thread_id);
442 return true;
443 case EVENT_TIME:
444 case OTHER_TIME:
445 *num = the_event->timestamp;
446 return true;
447 case EVENT_DURATION:
448 if (!the_event->has_other_event())
449 return false;
450 *num = the_event->GetAbsTimeToOtherEvent();
451 return true;
452 case EVENT_COMPLETE_DURATION:
453 if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE)
454 return false;
455 *num = the_event->duration;
456 return true;
457 case EVENT_PHASE:
458 case OTHER_PHASE:
459 *num = static_cast<double>(the_event->phase);
460 return true;
461 case EVENT_HAS_STRING_ARG:
462 case OTHER_HAS_STRING_ARG:
463 *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0);
464 return true;
465 case EVENT_HAS_NUMBER_ARG:
466 case OTHER_HAS_NUMBER_ARG:
467 *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0);
468 return true;
469 case EVENT_ARG:
470 case OTHER_ARG: {
471 // Search for the argument name and return its value if found.
472 std::map<std::string, double>::const_iterator num_i =
473 the_event->arg_numbers.find(string_);
474 if (num_i == the_event->arg_numbers.end())
475 return false;
476 *num = num_i->second;
477 return true;
479 case EVENT_HAS_OTHER:
480 // return 1.0 (true) if the other event exists
481 *num = event.other_event ? 1.0 : 0.0;
482 return true;
483 default:
484 return false;
488 bool Query::GetMemberValueAsString(const TraceEvent& event,
489 std::string* str) const {
490 DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
492 // This could be a request for a member of |event| or a member of |event|'s
493 // associated event. Store the target event in the_event:
494 const TraceEvent* the_event = (member_ < OTHER_PID) ?
495 &event : event.other_event;
497 // Request for member of associated event, but there is no associated event.
498 if (!the_event)
499 return false;
501 switch (member_) {
502 case EVENT_CATEGORY:
503 case OTHER_CATEGORY:
504 *str = the_event->category;
505 return true;
506 case EVENT_NAME:
507 case OTHER_NAME:
508 *str = the_event->name;
509 return true;
510 case EVENT_ID:
511 case OTHER_ID:
512 *str = the_event->id;
513 return true;
514 case EVENT_ARG:
515 case OTHER_ARG: {
516 // Search for the argument name and return its value if found.
517 std::map<std::string, std::string>::const_iterator str_i =
518 the_event->arg_strings.find(string_);
519 if (str_i == the_event->arg_strings.end())
520 return false;
521 *str = str_i->second;
522 return true;
524 default:
525 return false;
529 Query::Query(const std::string& str)
530 : type_(QUERY_STRING),
531 operator_(OP_INVALID),
532 member_(EVENT_INVALID),
533 number_(0),
534 string_(str),
535 is_pattern_(false) {
538 Query::Query(double num)
539 : type_(QUERY_NUMBER),
540 operator_(OP_INVALID),
541 member_(EVENT_INVALID),
542 number_(num),
543 is_pattern_(false) {
545 const Query& Query::left() const {
546 return left_->query();
549 const Query& Query::right() const {
550 return right_->query();
553 Query Query::operator==(const Query& rhs) const {
554 return Query(*this, rhs, OP_EQ);
557 Query Query::operator!=(const Query& rhs) const {
558 return Query(*this, rhs, OP_NE);
561 Query Query::operator<(const Query& rhs) const {
562 return Query(*this, rhs, OP_LT);
565 Query Query::operator<=(const Query& rhs) const {
566 return Query(*this, rhs, OP_LE);
569 Query Query::operator>(const Query& rhs) const {
570 return Query(*this, rhs, OP_GT);
573 Query Query::operator>=(const Query& rhs) const {
574 return Query(*this, rhs, OP_GE);
577 Query Query::operator&&(const Query& rhs) const {
578 return Query(*this, rhs, OP_AND);
581 Query Query::operator||(const Query& rhs) const {
582 return Query(*this, rhs, OP_OR);
585 Query Query::operator!() const {
586 return Query(*this, OP_NOT);
589 Query Query::operator+(const Query& rhs) const {
590 return Query(*this, rhs, OP_ADD);
593 Query Query::operator-(const Query& rhs) const {
594 return Query(*this, rhs, OP_SUB);
597 Query Query::operator*(const Query& rhs) const {
598 return Query(*this, rhs, OP_MUL);
601 Query Query::operator/(const Query& rhs) const {
602 return Query(*this, rhs, OP_DIV);
605 Query Query::operator%(const Query& rhs) const {
606 return Query(*this, rhs, OP_MOD);
609 Query Query::operator-() const {
610 return Query(*this, OP_NEGATE);
614 Query::Query(const Query& left, const Query& right, Operator binary_op)
615 : operator_(binary_op),
616 left_(new QueryNode(left)),
617 right_(new QueryNode(right)),
618 member_(EVENT_INVALID),
619 number_(0) {
620 type_ = (binary_op < OP_ADD ?
621 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
624 Query::Query(const Query& left, Operator unary_op)
625 : operator_(unary_op),
626 left_(new QueryNode(left)),
627 member_(EVENT_INVALID),
628 number_(0) {
629 type_ = (unary_op < OP_ADD ?
630 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
633 namespace {
635 // Search |events| for |query| and add matches to |output|.
636 size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
637 const Query& query,
638 TraceEventVector* output,
639 bool ignore_metadata_events) {
640 for (size_t i = 0; i < events.size(); ++i) {
641 if (ignore_metadata_events && events[i].phase == TRACE_EVENT_PHASE_METADATA)
642 continue;
643 if (query.Evaluate(events[i]))
644 output->push_back(&events[i]);
646 return output->size();
649 bool ParseEventsFromJson(const std::string& json,
650 std::vector<TraceEvent>* output) {
651 scoped_ptr<base::Value> root;
652 root.reset(base::JSONReader::DeprecatedRead(json));
654 base::ListValue* root_list = NULL;
655 if (!root.get() || !root->GetAsList(&root_list))
656 return false;
658 for (size_t i = 0; i < root_list->GetSize(); ++i) {
659 base::Value* item = NULL;
660 if (root_list->Get(i, &item)) {
661 TraceEvent event;
662 if (event.SetFromJSON(item))
663 output->push_back(event);
664 else
665 return false;
669 return true;
672 } // namespace
674 // TraceAnalyzer
676 TraceAnalyzer::TraceAnalyzer()
677 : ignore_metadata_events_(false),
678 allow_assocation_changes_(true) {}
680 TraceAnalyzer::~TraceAnalyzer() {
683 // static
684 TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) {
685 scoped_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
686 if (analyzer->SetEvents(json_events))
687 return analyzer.release();
688 return NULL;
691 bool TraceAnalyzer::SetEvents(const std::string& json_events) {
692 raw_events_.clear();
693 if (!ParseEventsFromJson(json_events, &raw_events_))
694 return false;
695 std::stable_sort(raw_events_.begin(), raw_events_.end());
696 ParseMetadata();
697 return true;
700 void TraceAnalyzer::AssociateBeginEndEvents() {
701 using trace_analyzer::Query;
703 Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
704 Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
705 Query match(Query::EventName() == Query::OtherName() &&
706 Query::EventCategory() == Query::OtherCategory() &&
707 Query::EventTid() == Query::OtherTid() &&
708 Query::EventPid() == Query::OtherPid());
710 AssociateEvents(begin, end, match);
713 void TraceAnalyzer::AssociateAsyncBeginEndEvents() {
714 using trace_analyzer::Query;
716 Query begin(
717 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
718 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
719 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
720 Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
721 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
722 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
723 Query match(Query::EventName() == Query::OtherName() &&
724 Query::EventCategory() == Query::OtherCategory() &&
725 Query::EventId() == Query::OtherId());
727 AssociateEvents(begin, end, match);
730 void TraceAnalyzer::AssociateEvents(const Query& first,
731 const Query& second,
732 const Query& match) {
733 DCHECK(allow_assocation_changes_)
734 << "AssociateEvents not allowed after FindEvents";
736 // Search for matching begin/end event pairs. When a matching end is found,
737 // it is associated with the begin event.
738 std::vector<TraceEvent*> begin_stack;
739 for (size_t event_index = 0; event_index < raw_events_.size();
740 ++event_index) {
742 TraceEvent& this_event = raw_events_[event_index];
744 if (second.Evaluate(this_event)) {
745 // Search stack for matching begin, starting from end.
746 for (int stack_index = static_cast<int>(begin_stack.size()) - 1;
747 stack_index >= 0; --stack_index) {
748 TraceEvent& begin_event = *begin_stack[stack_index];
750 // Temporarily set other to test against the match query.
751 const TraceEvent* other_backup = begin_event.other_event;
752 begin_event.other_event = &this_event;
753 if (match.Evaluate(begin_event)) {
754 // Found a matching begin/end pair.
755 // Erase the matching begin event index from the stack.
756 begin_stack.erase(begin_stack.begin() + stack_index);
757 break;
760 // Not a match, restore original other and continue.
761 begin_event.other_event = other_backup;
764 // Even if this_event is a |second| event that has matched an earlier
765 // |first| event, it can still also be a |first| event and be associated
766 // with a later |second| event.
767 if (first.Evaluate(this_event)) {
768 begin_stack.push_back(&this_event);
773 void TraceAnalyzer::MergeAssociatedEventArgs() {
774 for (size_t i = 0; i < raw_events_.size(); ++i) {
775 // Merge all associated events with the first event.
776 const TraceEvent* other = raw_events_[i].other_event;
777 // Avoid looping by keeping set of encountered TraceEvents.
778 std::set<const TraceEvent*> encounters;
779 encounters.insert(&raw_events_[i]);
780 while (other && encounters.find(other) == encounters.end()) {
781 encounters.insert(other);
782 raw_events_[i].arg_numbers.insert(
783 other->arg_numbers.begin(),
784 other->arg_numbers.end());
785 raw_events_[i].arg_strings.insert(
786 other->arg_strings.begin(),
787 other->arg_strings.end());
788 other = other->other_event;
793 size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) {
794 allow_assocation_changes_ = false;
795 output->clear();
796 return FindMatchingEvents(
797 raw_events_, query, output, ignore_metadata_events_);
800 const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
801 TraceEventVector output;
802 if (FindEvents(query, &output) > 0)
803 return output.front();
804 return NULL;
807 const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
808 TraceEventVector output;
809 if (FindEvents(query, &output) > 0)
810 return output.back();
811 return NULL;
814 const std::string& TraceAnalyzer::GetThreadName(
815 const TraceEvent::ProcessThreadID& thread) {
816 // If thread is not found, just add and return empty string.
817 return thread_names_[thread];
820 void TraceAnalyzer::ParseMetadata() {
821 for (size_t i = 0; i < raw_events_.size(); ++i) {
822 TraceEvent& this_event = raw_events_[i];
823 // Check for thread name metadata.
824 if (this_event.phase != TRACE_EVENT_PHASE_METADATA ||
825 this_event.name != "thread_name")
826 continue;
827 std::map<std::string, std::string>::const_iterator string_it =
828 this_event.arg_strings.find("name");
829 if (string_it != this_event.arg_strings.end())
830 thread_names_[this_event.thread] = string_it->second;
834 // TraceEventVector utility functions.
836 bool GetRateStats(const TraceEventVector& events,
837 RateStats* stats,
838 const RateStatsOptions* options) {
839 DCHECK(stats);
840 // Need at least 3 events to calculate rate stats.
841 const size_t kMinEvents = 3;
842 if (events.size() < kMinEvents) {
843 LOG(ERROR) << "Not enough events: " << events.size();
844 return false;
847 std::vector<double> deltas;
848 size_t num_deltas = events.size() - 1;
849 for (size_t i = 0; i < num_deltas; ++i) {
850 double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp;
851 if (delta < 0.0) {
852 LOG(ERROR) << "Events are out of order";
853 return false;
855 deltas.push_back(delta);
858 std::sort(deltas.begin(), deltas.end());
860 if (options) {
861 if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
862 LOG(ERROR) << "Attempt to trim too many events";
863 return false;
865 deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
866 deltas.erase(deltas.end() - options->trim_max, deltas.end());
869 num_deltas = deltas.size();
870 double delta_sum = 0.0;
871 for (size_t i = 0; i < num_deltas; ++i)
872 delta_sum += deltas[i];
874 stats->min_us = *std::min_element(deltas.begin(), deltas.end());
875 stats->max_us = *std::max_element(deltas.begin(), deltas.end());
876 stats->mean_us = delta_sum / static_cast<double>(num_deltas);
878 double sum_mean_offsets_squared = 0.0;
879 for (size_t i = 0; i < num_deltas; ++i) {
880 double offset = fabs(deltas[i] - stats->mean_us);
881 sum_mean_offsets_squared += offset * offset;
883 stats->standard_deviation_us =
884 sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
886 return true;
889 bool FindFirstOf(const TraceEventVector& events,
890 const Query& query,
891 size_t position,
892 size_t* return_index) {
893 DCHECK(return_index);
894 for (size_t i = position; i < events.size(); ++i) {
895 if (query.Evaluate(*events[i])) {
896 *return_index = i;
897 return true;
900 return false;
903 bool FindLastOf(const TraceEventVector& events,
904 const Query& query,
905 size_t position,
906 size_t* return_index) {
907 DCHECK(return_index);
908 for (size_t i = std::min(position + 1, events.size()); i != 0; --i) {
909 if (query.Evaluate(*events[i - 1])) {
910 *return_index = i - 1;
911 return true;
914 return false;
917 bool FindClosest(const TraceEventVector& events,
918 const Query& query,
919 size_t position,
920 size_t* return_closest,
921 size_t* return_second_closest) {
922 DCHECK(return_closest);
923 if (events.empty() || position >= events.size())
924 return false;
925 size_t closest = events.size();
926 size_t second_closest = events.size();
927 for (size_t i = 0; i < events.size(); ++i) {
928 if (!query.Evaluate(*events.at(i)))
929 continue;
930 if (closest == events.size()) {
931 closest = i;
932 continue;
934 if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
935 fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
936 second_closest = closest;
937 closest = i;
938 } else if (second_closest == events.size()) {
939 second_closest = i;
943 if (closest < events.size() &&
944 (!return_second_closest || second_closest < events.size())) {
945 *return_closest = closest;
946 if (return_second_closest)
947 *return_second_closest = second_closest;
948 return true;
951 return false;
954 size_t CountMatches(const TraceEventVector& events,
955 const Query& query,
956 size_t begin_position,
957 size_t end_position) {
958 if (begin_position >= events.size())
959 return 0u;
960 end_position = (end_position < events.size()) ? end_position : events.size();
961 size_t count = 0u;
962 for (size_t i = begin_position; i < end_position; ++i) {
963 if (query.Evaluate(*events.at(i)))
964 ++count;
966 return count;
969 } // namespace trace_analyzer