Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: base/test/trace_event_analyzer.cc

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/test/trace_event_analyzer.h ('k') | base/test/trace_event_analyzer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/strings/pattern.h"
14 #include "base/values.h"
15
16 namespace trace_analyzer {
17
18 // TraceEvent
19
20 TraceEvent::TraceEvent()
21 : thread(0, 0),
22 timestamp(0),
23 duration(0),
24 phase(TRACE_EVENT_PHASE_BEGIN),
25 other_event(NULL) {
26 }
27
28 TraceEvent::~TraceEvent() {
29 }
30
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;
35 }
36 const base::DictionaryValue* dictionary =
37 static_cast<const base::DictionaryValue*>(event_value);
38
39 std::string phase_str;
40 const base::DictionaryValue* args = NULL;
41
42 if (!dictionary->GetString("ph", &phase_str)) {
43 LOG(ERROR) << "ph is missing from TraceEvent JSON";
44 return false;
45 }
46
47 phase = *phase_str.data();
48
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);
55
56 if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
57 LOG(ERROR) << "pid is missing from TraceEvent JSON";
58 return false;
59 }
60 if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) {
61 LOG(ERROR) << "tid is missing from TraceEvent JSON";
62 return false;
63 }
64 if (require_origin && !dictionary->GetDouble("ts", &timestamp)) {
65 LOG(ERROR) << "ts is missing from TraceEvent JSON";
66 return false;
67 }
68 if (may_have_duration) {
69 dictionary->GetDouble("dur", &duration);
70 }
71 if (!dictionary->GetString("cat", &category)) {
72 LOG(ERROR) << "cat is missing from TraceEvent JSON";
73 return false;
74 }
75 if (!dictionary->GetString("name", &name)) {
76 LOG(ERROR) << "name is missing from TraceEvent JSON";
77 return false;
78 }
79 if (!dictionary->GetDictionary("args", &args)) {
80 LOG(ERROR) << "args is missing from TraceEvent JSON";
81 return false;
82 }
83 if (require_id && !dictionary->GetString("id", &id)) {
84 LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
85 return false;
86 }
87
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.
107 }
108 }
109
110 return true;
111 }
112
113 double TraceEvent::GetAbsTimeToOtherEvent() const {
114 return fabs(other_event->timestamp - timestamp);
115 }
116
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;
123 }
124 return false;
125 }
126
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;
133 }
134 return false;
135 }
136
137 bool TraceEvent::HasStringArg(const std::string& name) const {
138 return (arg_strings.find(name) != arg_strings.end());
139 }
140
141 bool TraceEvent::HasNumberArg(const std::string& name) const {
142 return (arg_numbers.find(name) != arg_numbers.end());
143 }
144
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;
150 }
151
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;
157 }
158
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);
164 }
165
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);
171 }
172
173 // QueryNode
174
175 QueryNode::QueryNode(const Query& query) : query_(query) {
176 }
177
178 QueryNode::~QueryNode() {
179 }
180
181 // Query
182
183 Query::Query(TraceEventMember member)
184 : type_(QUERY_EVENT_MEMBER),
185 operator_(OP_INVALID),
186 member_(member),
187 number_(0),
188 is_pattern_(false) {
189 }
190
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) {
198 }
199
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_) {
209 }
210
211 Query::~Query() {
212 }
213
214 Query Query::String(const std::string& str) {
215 return Query(str);
216 }
217
218 Query Query::Double(double num) {
219 return Query(num);
220 }
221
222 Query Query::Int(int32 num) {
223 return Query(static_cast<double>(num));
224 }
225
226 Query Query::Uint(uint32 num) {
227 return Query(static_cast<double>(num));
228 }
229
230 Query Query::Bool(bool boolean) {
231 return Query(boolean ? 1.0 : 0.0);
232 }
233
234 Query Query::Phase(char phase) {
235 return Query(static_cast<double>(phase));
236 }
237
238 Query Query::Pattern(const std::string& pattern) {
239 Query query(pattern);
240 query.is_pattern_ = true;
241 return query;
242 }
243
244 bool Query::Evaluate(const TraceEvent& event) const {
245 // First check for values that can convert to bool.
246
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);
252
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();
258
259 DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
260 << "Invalid query: missing boolean expression";
261 DCHECK(left_.get());
262 DCHECK(right_.get() || is_unary_operator());
263
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;
274 }
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;
286 }
287 }
288
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;
315 }
316 }
317
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;
354 }
355 }
356
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());
362
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;
368
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;
392 }
393 }
394
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;
406 }
407 }
408
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;
418 }
419 }
420
421 bool Query::GetMemberValueAsDouble(const TraceEvent& event,
422 double* num) const {
423 DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
424
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;
429
430 // Request for member of associated event, but there is no associated event.
431 if (!the_event)
432 return false;
433
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;
478 }
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;
485 }
486 }
487
488 bool Query::GetMemberValueAsString(const TraceEvent& event,
489 std::string* str) const {
490 DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
491
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;
496
497 // Request for member of associated event, but there is no associated event.
498 if (!the_event)
499 return false;
500
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;
523 }
524 default:
525 return false;
526 }
527 }
528
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) {
536 }
537
538 Query::Query(double num)
539 : type_(QUERY_NUMBER),
540 operator_(OP_INVALID),
541 member_(EVENT_INVALID),
542 number_(num),
543 is_pattern_(false) {
544 }
545 const Query& Query::left() const {
546 return left_->query();
547 }
548
549 const Query& Query::right() const {
550 return right_->query();
551 }
552
553 Query Query::operator==(const Query& rhs) const {
554 return Query(*this, rhs, OP_EQ);
555 }
556
557 Query Query::operator!=(const Query& rhs) const {
558 return Query(*this, rhs, OP_NE);
559 }
560
561 Query Query::operator<(const Query& rhs) const {
562 return Query(*this, rhs, OP_LT);
563 }
564
565 Query Query::operator<=(const Query& rhs) const {
566 return Query(*this, rhs, OP_LE);
567 }
568
569 Query Query::operator>(const Query& rhs) const {
570 return Query(*this, rhs, OP_GT);
571 }
572
573 Query Query::operator>=(const Query& rhs) const {
574 return Query(*this, rhs, OP_GE);
575 }
576
577 Query Query::operator&&(const Query& rhs) const {
578 return Query(*this, rhs, OP_AND);
579 }
580
581 Query Query::operator||(const Query& rhs) const {
582 return Query(*this, rhs, OP_OR);
583 }
584
585 Query Query::operator!() const {
586 return Query(*this, OP_NOT);
587 }
588
589 Query Query::operator+(const Query& rhs) const {
590 return Query(*this, rhs, OP_ADD);
591 }
592
593 Query Query::operator-(const Query& rhs) const {
594 return Query(*this, rhs, OP_SUB);
595 }
596
597 Query Query::operator*(const Query& rhs) const {
598 return Query(*this, rhs, OP_MUL);
599 }
600
601 Query Query::operator/(const Query& rhs) const {
602 return Query(*this, rhs, OP_DIV);
603 }
604
605 Query Query::operator%(const Query& rhs) const {
606 return Query(*this, rhs, OP_MOD);
607 }
608
609 Query Query::operator-() const {
610 return Query(*this, OP_NEGATE);
611 }
612
613
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);
622 }
623
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);
631 }
632
633 namespace {
634
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]);
645 }
646 return output->size();
647 }
648
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));
653
654 base::ListValue* root_list = NULL;
655 if (!root.get() || !root->GetAsList(&root_list))
656 return false;
657
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;
666 }
667 }
668
669 return true;
670 }
671
672 } // namespace
673
674 // TraceAnalyzer
675
676 TraceAnalyzer::TraceAnalyzer()
677 : ignore_metadata_events_(false),
678 allow_assocation_changes_(true) {}
679
680 TraceAnalyzer::~TraceAnalyzer() {
681 }
682
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;
689 }
690
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;
698 }
699
700 void TraceAnalyzer::AssociateBeginEndEvents() {
701 using trace_analyzer::Query;
702
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());
709
710 AssociateEvents(begin, end, match);
711 }
712
713 void TraceAnalyzer::AssociateAsyncBeginEndEvents() {
714 using trace_analyzer::Query;
715
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());
726
727 AssociateEvents(begin, end, match);
728 }
729
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";
735
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) {
741
742 TraceEvent& this_event = raw_events_[event_index];
743
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];
749
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;
758 }
759
760 // Not a match, restore original other and continue.
761 begin_event.other_event = other_backup;
762 }
763 }
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);
769 }
770 }
771 }
772
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;
789 }
790 }
791 }
792
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_);
798 }
799
800 const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
801 TraceEventVector output;
802 if (FindEvents(query, &output) > 0)
803 return output.front();
804 return NULL;
805 }
806
807 const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
808 TraceEventVector output;
809 if (FindEvents(query, &output) > 0)
810 return output.back();
811 return NULL;
812 }
813
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];
818 }
819
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;
831 }
832 }
833
834 // TraceEventVector utility functions.
835
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;
845 }
846
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;
854 }
855 deltas.push_back(delta);
856 }
857
858 std::sort(deltas.begin(), deltas.end());
859
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;
864 }
865 deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
866 deltas.erase(deltas.end() - options->trim_max, deltas.end());
867 }
868
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];
873
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);
877
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;
882 }
883 stats->standard_deviation_us =
884 sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
885
886 return true;
887 }
888
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;
898 }
899 }
900 return false;
901 }
902
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;
912 }
913 }
914 return false;
915 }
916
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;
933 }
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;
940 }
941 }
942
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;
949 }
950
951 return false;
952 }
953
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;
965 }
966 return count;
967 }
968
969 } // namespace trace_analyzer
OLDNEW
« no previous file with comments | « base/test/trace_event_analyzer.h ('k') | base/test/trace_event_analyzer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698