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 <set> 11 12 #include "base/json/json_reader.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/strings/pattern.h" 15 #include "base/values.h" 16 17 namespace trace_analyzer { 18 19 // TraceEvent 20 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() { 30 } 31 32 bool TraceEvent::SetFromJSON(const base::Value* event_value) { 33 if (event_value->GetType() != base::Value::TYPE_DICTIONARY) { 34 LOG(ERROR) << "Value must be TYPE_DICTIONARY"; 35 return false; 36 } 37 const base::DictionaryValue* dictionary = 38 static_cast<const base::DictionaryValue*>(event_value); 39 40 std::string phase_str; 41 const base::DictionaryValue* args = NULL; 42 43 if (!dictionary->GetString("ph", &phase_str)) { 44 LOG(ERROR) << "ph is missing from TraceEvent JSON"; 45 return false; 46 } 47 48 phase = *phase_str.data(); 49 50 bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE); 51 bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA); 52 bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN || 53 phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO || 54 phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST || 55 phase == TRACE_EVENT_PHASE_ASYNC_END); 56 57 if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) { 58 LOG(ERROR) << "pid is missing from TraceEvent JSON"; 59 return false; 60 } 61 if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) { 62 LOG(ERROR) << "tid is missing from TraceEvent JSON"; 63 return false; 64 } 65 if (require_origin && !dictionary->GetDouble("ts", ×tamp)) { 66 LOG(ERROR) << "ts is missing from TraceEvent JSON"; 67 return false; 68 } 69 if (may_have_duration) { 70 dictionary->GetDouble("dur", &duration); 71 } 72 if (!dictionary->GetString("cat", &category)) { 73 LOG(ERROR) << "cat is missing from TraceEvent JSON"; 74 return false; 75 } 76 if (!dictionary->GetString("name", &name)) { 77 LOG(ERROR) << "name is missing from TraceEvent JSON"; 78 return false; 79 } 80 if (!dictionary->GetDictionary("args", &args)) { 81 LOG(ERROR) << "args is missing from TraceEvent JSON"; 82 return false; 83 } 84 if (require_id && !dictionary->GetString("id", &id)) { 85 LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON"; 86 return false; 87 } 88 89 // For each argument, copy the type and create a trace_analyzer::TraceValue. 90 for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd(); 91 it.Advance()) { 92 std::string str; 93 bool boolean = false; 94 int int_num = 0; 95 double double_num = 0.0; 96 if (it.value().GetAsString(&str)) { 97 arg_strings[it.key()] = str; 98 } else if (it.value().GetAsInteger(&int_num)) { 99 arg_numbers[it.key()] = static_cast<double>(int_num); 100 } else if (it.value().GetAsBoolean(&boolean)) { 101 arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0); 102 } else if (it.value().GetAsDouble(&double_num)) { 103 arg_numbers[it.key()] = double_num; 104 } else { 105 LOG(WARNING) << "Value type of argument is not supported: " << 106 static_cast<int>(it.value().GetType()); 107 continue; // Skip non-supported arguments. 108 } 109 } 110 111 return true; 112 } 113 114 double TraceEvent::GetAbsTimeToOtherEvent() const { 115 return fabs(other_event->timestamp - timestamp); 116 } 117 118 bool TraceEvent::GetArgAsString(const std::string& name, 119 std::string* arg) const { 120 std::map<std::string, std::string>::const_iterator i = arg_strings.find(name); 121 if (i != arg_strings.end()) { 122 *arg = i->second; 123 return true; 124 } 125 return false; 126 } 127 128 bool TraceEvent::GetArgAsNumber(const std::string& name, 129 double* arg) const { 130 std::map<std::string, double>::const_iterator i = arg_numbers.find(name); 131 if (i != arg_numbers.end()) { 132 *arg = i->second; 133 return true; 134 } 135 return false; 136 } 137 138 bool TraceEvent::HasStringArg(const std::string& name) const { 139 return (arg_strings.find(name) != arg_strings.end()); 140 } 141 142 bool TraceEvent::HasNumberArg(const std::string& name) const { 143 return (arg_numbers.find(name) != arg_numbers.end()); 144 } 145 146 std::string TraceEvent::GetKnownArgAsString(const std::string& name) const { 147 std::string arg_string; 148 bool result = GetArgAsString(name, &arg_string); 149 DCHECK(result); 150 return arg_string; 151 } 152 153 double TraceEvent::GetKnownArgAsDouble(const std::string& name) const { 154 double arg_double = 0; 155 bool result = GetArgAsNumber(name, &arg_double); 156 DCHECK(result); 157 return arg_double; 158 } 159 160 int TraceEvent::GetKnownArgAsInt(const std::string& name) const { 161 double arg_double = 0; 162 bool result = GetArgAsNumber(name, &arg_double); 163 DCHECK(result); 164 return static_cast<int>(arg_double); 165 } 166 167 bool TraceEvent::GetKnownArgAsBool(const std::string& name) const { 168 double arg_double = 0; 169 bool result = GetArgAsNumber(name, &arg_double); 170 DCHECK(result); 171 return (arg_double != 0.0); 172 } 173 174 // QueryNode 175 176 QueryNode::QueryNode(const Query& query) : query_(query) { 177 } 178 179 QueryNode::~QueryNode() { 180 } 181 182 // Query 183 184 Query::Query(TraceEventMember member) 185 : type_(QUERY_EVENT_MEMBER), 186 operator_(OP_INVALID), 187 member_(member), 188 number_(0), 189 is_pattern_(false) { 190 } 191 192 Query::Query(TraceEventMember member, const std::string& arg_name) 193 : type_(QUERY_EVENT_MEMBER), 194 operator_(OP_INVALID), 195 member_(member), 196 number_(0), 197 string_(arg_name), 198 is_pattern_(false) { 199 } 200 201 Query::Query(const Query& query) 202 : type_(query.type_), 203 operator_(query.operator_), 204 left_(query.left_), 205 right_(query.right_), 206 member_(query.member_), 207 number_(query.number_), 208 string_(query.string_), 209 is_pattern_(query.is_pattern_) { 210 } 211 212 Query::~Query() { 213 } 214 215 Query Query::String(const std::string& str) { 216 return Query(str); 217 } 218 219 Query Query::Double(double num) { 220 return Query(num); 221 } 222 223 Query Query::Int(int32_t num) { 224 return Query(static_cast<double>(num)); 225 } 226 227 Query Query::Uint(uint32_t num) { 228 return Query(static_cast<double>(num)); 229 } 230 231 Query Query::Bool(bool boolean) { 232 return Query(boolean ? 1.0 : 0.0); 233 } 234 235 Query Query::Phase(char phase) { 236 return Query(static_cast<double>(phase)); 237 } 238 239 Query Query::Pattern(const std::string& pattern) { 240 Query query(pattern); 241 query.is_pattern_ = true; 242 return query; 243 } 244 245 bool Query::Evaluate(const TraceEvent& event) const { 246 // First check for values that can convert to bool. 247 248 // double is true if != 0: 249 double bool_value = 0.0; 250 bool is_bool = GetAsDouble(event, &bool_value); 251 if (is_bool) 252 return (bool_value != 0.0); 253 254 // string is true if it is non-empty: 255 std::string str_value; 256 bool is_str = GetAsString(event, &str_value); 257 if (is_str) 258 return !str_value.empty(); 259 260 DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_) 261 << "Invalid query: missing boolean expression"; 262 DCHECK(left_.get()); 263 DCHECK(right_.get() || is_unary_operator()); 264 265 if (is_comparison_operator()) { 266 DCHECK(left().is_value() && right().is_value()) 267 << "Invalid query: comparison operator used between event member and " 268 "value."; 269 bool compare_result = false; 270 if (CompareAsDouble(event, &compare_result)) 271 return compare_result; 272 if (CompareAsString(event, &compare_result)) 273 return compare_result; 274 return false; 275 } 276 // It's a logical operator. 277 switch (operator_) { 278 case OP_AND: 279 return left().Evaluate(event) && right().Evaluate(event); 280 case OP_OR: 281 return left().Evaluate(event) || right().Evaluate(event); 282 case OP_NOT: 283 return !left().Evaluate(event); 284 default: 285 NOTREACHED(); 286 return false; 287 } 288 } 289 290 bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const { 291 double lhs, rhs; 292 if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs)) 293 return false; 294 switch (operator_) { 295 case OP_EQ: 296 *result = (lhs == rhs); 297 return true; 298 case OP_NE: 299 *result = (lhs != rhs); 300 return true; 301 case OP_LT: 302 *result = (lhs < rhs); 303 return true; 304 case OP_LE: 305 *result = (lhs <= rhs); 306 return true; 307 case OP_GT: 308 *result = (lhs > rhs); 309 return true; 310 case OP_GE: 311 *result = (lhs >= rhs); 312 return true; 313 default: 314 NOTREACHED(); 315 return false; 316 } 317 } 318 319 bool Query::CompareAsString(const TraceEvent& event, bool* result) const { 320 std::string lhs, rhs; 321 if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs)) 322 return false; 323 switch (operator_) { 324 case OP_EQ: 325 if (right().is_pattern_) 326 *result = base::MatchPattern(lhs, rhs); 327 else if (left().is_pattern_) 328 *result = base::MatchPattern(rhs, lhs); 329 else 330 *result = (lhs == rhs); 331 return true; 332 case OP_NE: 333 if (right().is_pattern_) 334 *result = !base::MatchPattern(lhs, rhs); 335 else if (left().is_pattern_) 336 *result = !base::MatchPattern(rhs, lhs); 337 else 338 *result = (lhs != rhs); 339 return true; 340 case OP_LT: 341 *result = (lhs < rhs); 342 return true; 343 case OP_LE: 344 *result = (lhs <= rhs); 345 return true; 346 case OP_GT: 347 *result = (lhs > rhs); 348 return true; 349 case OP_GE: 350 *result = (lhs >= rhs); 351 return true; 352 default: 353 NOTREACHED(); 354 return false; 355 } 356 } 357 358 bool Query::EvaluateArithmeticOperator(const TraceEvent& event, 359 double* num) const { 360 DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_); 361 DCHECK(left_.get()); 362 DCHECK(right_.get() || is_unary_operator()); 363 364 double lhs = 0, rhs = 0; 365 if (!left().GetAsDouble(event, &lhs)) 366 return false; 367 if (!is_unary_operator() && !right().GetAsDouble(event, &rhs)) 368 return false; 369 370 switch (operator_) { 371 case OP_ADD: 372 *num = lhs + rhs; 373 return true; 374 case OP_SUB: 375 *num = lhs - rhs; 376 return true; 377 case OP_MUL: 378 *num = lhs * rhs; 379 return true; 380 case OP_DIV: 381 *num = lhs / rhs; 382 return true; 383 case OP_MOD: 384 *num = static_cast<double>(static_cast<int64_t>(lhs) % 385 static_cast<int64_t>(rhs)); 386 return true; 387 case OP_NEGATE: 388 *num = -lhs; 389 return true; 390 default: 391 NOTREACHED(); 392 return false; 393 } 394 } 395 396 bool Query::GetAsDouble(const TraceEvent& event, double* num) const { 397 switch (type_) { 398 case QUERY_ARITHMETIC_OPERATOR: 399 return EvaluateArithmeticOperator(event, num); 400 case QUERY_EVENT_MEMBER: 401 return GetMemberValueAsDouble(event, num); 402 case QUERY_NUMBER: 403 *num = number_; 404 return true; 405 default: 406 return false; 407 } 408 } 409 410 bool Query::GetAsString(const TraceEvent& event, std::string* str) const { 411 switch (type_) { 412 case QUERY_EVENT_MEMBER: 413 return GetMemberValueAsString(event, str); 414 case QUERY_STRING: 415 *str = string_; 416 return true; 417 default: 418 return false; 419 } 420 } 421 422 bool Query::GetMemberValueAsDouble(const TraceEvent& event, 423 double* num) const { 424 DCHECK_EQ(QUERY_EVENT_MEMBER, type_); 425 426 // This could be a request for a member of |event| or a member of |event|'s 427 // associated event. Store the target event in the_event: 428 const TraceEvent* the_event = (member_ < OTHER_PID) ? 429 &event : event.other_event; 430 431 // Request for member of associated event, but there is no associated event. 432 if (!the_event) 433 return false; 434 435 switch (member_) { 436 case EVENT_PID: 437 case OTHER_PID: 438 *num = static_cast<double>(the_event->thread.process_id); 439 return true; 440 case EVENT_TID: 441 case OTHER_TID: 442 *num = static_cast<double>(the_event->thread.thread_id); 443 return true; 444 case EVENT_TIME: 445 case OTHER_TIME: 446 *num = the_event->timestamp; 447 return true; 448 case EVENT_DURATION: 449 if (!the_event->has_other_event()) 450 return false; 451 *num = the_event->GetAbsTimeToOtherEvent(); 452 return true; 453 case EVENT_COMPLETE_DURATION: 454 if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE) 455 return false; 456 *num = the_event->duration; 457 return true; 458 case EVENT_PHASE: 459 case OTHER_PHASE: 460 *num = static_cast<double>(the_event->phase); 461 return true; 462 case EVENT_HAS_STRING_ARG: 463 case OTHER_HAS_STRING_ARG: 464 *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0); 465 return true; 466 case EVENT_HAS_NUMBER_ARG: 467 case OTHER_HAS_NUMBER_ARG: 468 *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0); 469 return true; 470 case EVENT_ARG: 471 case OTHER_ARG: { 472 // Search for the argument name and return its value if found. 473 std::map<std::string, double>::const_iterator num_i = 474 the_event->arg_numbers.find(string_); 475 if (num_i == the_event->arg_numbers.end()) 476 return false; 477 *num = num_i->second; 478 return true; 479 } 480 case EVENT_HAS_OTHER: 481 // return 1.0 (true) if the other event exists 482 *num = event.other_event ? 1.0 : 0.0; 483 return true; 484 default: 485 return false; 486 } 487 } 488 489 bool Query::GetMemberValueAsString(const TraceEvent& event, 490 std::string* str) const { 491 DCHECK_EQ(QUERY_EVENT_MEMBER, type_); 492 493 // This could be a request for a member of |event| or a member of |event|'s 494 // associated event. Store the target event in the_event: 495 const TraceEvent* the_event = (member_ < OTHER_PID) ? 496 &event : event.other_event; 497 498 // Request for member of associated event, but there is no associated event. 499 if (!the_event) 500 return false; 501 502 switch (member_) { 503 case EVENT_CATEGORY: 504 case OTHER_CATEGORY: 505 *str = the_event->category; 506 return true; 507 case EVENT_NAME: 508 case OTHER_NAME: 509 *str = the_event->name; 510 return true; 511 case EVENT_ID: 512 case OTHER_ID: 513 *str = the_event->id; 514 return true; 515 case EVENT_ARG: 516 case OTHER_ARG: { 517 // Search for the argument name and return its value if found. 518 std::map<std::string, std::string>::const_iterator str_i = 519 the_event->arg_strings.find(string_); 520 if (str_i == the_event->arg_strings.end()) 521 return false; 522 *str = str_i->second; 523 return true; 524 } 525 default: 526 return false; 527 } 528 } 529 530 Query::Query(const std::string& str) 531 : type_(QUERY_STRING), 532 operator_(OP_INVALID), 533 member_(EVENT_INVALID), 534 number_(0), 535 string_(str), 536 is_pattern_(false) { 537 } 538 539 Query::Query(double num) 540 : type_(QUERY_NUMBER), 541 operator_(OP_INVALID), 542 member_(EVENT_INVALID), 543 number_(num), 544 is_pattern_(false) { 545 } 546 const Query& Query::left() const { 547 return left_->query(); 548 } 549 550 const Query& Query::right() const { 551 return right_->query(); 552 } 553 554 Query Query::operator==(const Query& rhs) const { 555 return Query(*this, rhs, OP_EQ); 556 } 557 558 Query Query::operator!=(const Query& rhs) const { 559 return Query(*this, rhs, OP_NE); 560 } 561 562 Query Query::operator<(const Query& rhs) const { 563 return Query(*this, rhs, OP_LT); 564 } 565 566 Query Query::operator<=(const Query& rhs) const { 567 return Query(*this, rhs, OP_LE); 568 } 569 570 Query Query::operator>(const Query& rhs) const { 571 return Query(*this, rhs, OP_GT); 572 } 573 574 Query Query::operator>=(const Query& rhs) const { 575 return Query(*this, rhs, OP_GE); 576 } 577 578 Query Query::operator&&(const Query& rhs) const { 579 return Query(*this, rhs, OP_AND); 580 } 581 582 Query Query::operator||(const Query& rhs) const { 583 return Query(*this, rhs, OP_OR); 584 } 585 586 Query Query::operator!() const { 587 return Query(*this, OP_NOT); 588 } 589 590 Query Query::operator+(const Query& rhs) const { 591 return Query(*this, rhs, OP_ADD); 592 } 593 594 Query Query::operator-(const Query& rhs) const { 595 return Query(*this, rhs, OP_SUB); 596 } 597 598 Query Query::operator*(const Query& rhs) const { 599 return Query(*this, rhs, OP_MUL); 600 } 601 602 Query Query::operator/(const Query& rhs) const { 603 return Query(*this, rhs, OP_DIV); 604 } 605 606 Query Query::operator%(const Query& rhs) const { 607 return Query(*this, rhs, OP_MOD); 608 } 609 610 Query Query::operator-() const { 611 return Query(*this, OP_NEGATE); 612 } 613 614 615 Query::Query(const Query& left, const Query& right, Operator binary_op) 616 : operator_(binary_op), 617 left_(new QueryNode(left)), 618 right_(new QueryNode(right)), 619 member_(EVENT_INVALID), 620 number_(0) { 621 type_ = (binary_op < OP_ADD ? 622 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR); 623 } 624 625 Query::Query(const Query& left, Operator unary_op) 626 : operator_(unary_op), 627 left_(new QueryNode(left)), 628 member_(EVENT_INVALID), 629 number_(0) { 630 type_ = (unary_op < OP_ADD ? 631 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR); 632 } 633 634 namespace { 635 636 // Search |events| for |query| and add matches to |output|. 637 size_t FindMatchingEvents(const std::vector<TraceEvent>& events, 638 const Query& query, 639 TraceEventVector* output, 640 bool ignore_metadata_events) { 641 for (size_t i = 0; i < events.size(); ++i) { 642 if (ignore_metadata_events && events[i].phase == TRACE_EVENT_PHASE_METADATA) 643 continue; 644 if (query.Evaluate(events[i])) 645 output->push_back(&events[i]); 646 } 647 return output->size(); 648 } 649 650 bool ParseEventsFromJson(const std::string& json, 651 std::vector<TraceEvent>* output) { 652 scoped_ptr<base::Value> root = base::JSONReader::Read(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 970