1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/test/trace_event_analyzer.h" 6 7 #include <algorithm> 8 #include <math.h> 9 #include <set> 10 11 #include "base/json/json_reader.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/values.h" 14 15 namespace trace_analyzer { 16 17 // TraceEvent 18 19 TraceEvent::TraceEvent() 20 : thread(0, 0), 21 timestamp(0), 22 phase(TRACE_EVENT_PHASE_BEGIN), 23 other_event(NULL) { 24 } 25 26 TraceEvent::~TraceEvent() { 27 } 28 29 bool TraceEvent::SetFromJSON(const base::Value* event_value) { 30 if (event_value->GetType() != base::Value::TYPE_DICTIONARY) { 31 LOG(ERROR) << "Value must be TYPE_DICTIONARY"; 32 return false; 33 } 34 const base::DictionaryValue* dictionary = 35 static_cast<const base::DictionaryValue*>(event_value); 36 37 std::string phase_str; 38 const base::DictionaryValue* args = NULL; 39 40 if (!dictionary->GetString("ph", &phase_str)) { 41 LOG(ERROR) << "ph is missing from TraceEvent JSON"; 42 return false; 43 } 44 45 phase = *phase_str.data(); 46 47 bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA); 48 bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN || 49 phase == TRACE_EVENT_PHASE_ASYNC_STEP || 50 phase == TRACE_EVENT_PHASE_ASYNC_END); 51 52 if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) { 53 LOG(ERROR) << "pid is missing from TraceEvent JSON"; 54 return false; 55 } 56 if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) { 57 LOG(ERROR) << "tid is missing from TraceEvent JSON"; 58 return false; 59 } 60 if (require_origin && !dictionary->GetDouble("ts", ×tamp)) { 61 LOG(ERROR) << "ts is missing from TraceEvent JSON"; 62 return false; 63 } 64 if (!dictionary->GetString("cat", &category)) { 65 LOG(ERROR) << "cat is missing from TraceEvent JSON"; 66 return false; 67 } 68 if (!dictionary->GetString("name", &name)) { 69 LOG(ERROR) << "name is missing from TraceEvent JSON"; 70 return false; 71 } 72 if (!dictionary->GetDictionary("args", &args)) { 73 LOG(ERROR) << "args is missing from TraceEvent JSON"; 74 return false; 75 } 76 if (require_id && !dictionary->GetString("id", &id)) { 77 LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON"; 78 return false; 79 } 80 81 // For each argument, copy the type and create a trace_analyzer::TraceValue. 82 for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd(); 83 it.Advance()) { 84 std::string str; 85 bool boolean = false; 86 int int_num = 0; 87 double double_num = 0.0; 88 if (it.value().GetAsString(&str)) 89 arg_strings[it.key()] = str; 90 else if (it.value().GetAsInteger(&int_num)) 91 arg_numbers[it.key()] = static_cast<double>(int_num); 92 else if (it.value().GetAsBoolean(&boolean)) 93 arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0); 94 else if (it.value().GetAsDouble(&double_num)) 95 arg_numbers[it.key()] = double_num; 96 else { 97 LOG(ERROR) << "Value type of argument is not supported: " << 98 static_cast<int>(it.value().GetType()); 99 return false; // Invalid trace event JSON format. 100 } 101 } 102 103 return true; 104 } 105 106 double TraceEvent::GetAbsTimeToOtherEvent() const { 107 return fabs(other_event->timestamp - timestamp); 108 } 109 110 bool TraceEvent::GetArgAsString(const std::string& name, 111 std::string* arg) const { 112 std::map<std::string, std::string>::const_iterator i = arg_strings.find(name); 113 if (i != arg_strings.end()) { 114 *arg = i->second; 115 return true; 116 } 117 return false; 118 } 119 120 bool TraceEvent::GetArgAsNumber(const std::string& name, 121 double* arg) const { 122 std::map<std::string, double>::const_iterator i = arg_numbers.find(name); 123 if (i != arg_numbers.end()) { 124 *arg = i->second; 125 return true; 126 } 127 return false; 128 } 129 130 bool TraceEvent::HasStringArg(const std::string& name) const { 131 return (arg_strings.find(name) != arg_strings.end()); 132 } 133 134 bool TraceEvent::HasNumberArg(const std::string& name) const { 135 return (arg_numbers.find(name) != arg_numbers.end()); 136 } 137 138 std::string TraceEvent::GetKnownArgAsString(const std::string& name) const { 139 std::string arg_string; 140 if (GetArgAsString(name, &arg_string)) 141 return arg_string; 142 NOTREACHED(); 143 return std::string(); 144 } 145 146 double TraceEvent::GetKnownArgAsDouble(const std::string& name) const { 147 double arg_double; 148 if (GetArgAsNumber(name, &arg_double)) 149 return arg_double; 150 NOTREACHED(); 151 return 0; 152 } 153 154 int TraceEvent::GetKnownArgAsInt(const std::string& name) const { 155 double arg_double; 156 if (GetArgAsNumber(name, &arg_double)) 157 return static_cast<int>(arg_double); 158 NOTREACHED(); 159 return 0; 160 } 161 162 bool TraceEvent::GetKnownArgAsBool(const std::string& name) const { 163 double arg_double; 164 if (GetArgAsNumber(name, &arg_double)) 165 return (arg_double != 0.0); 166 NOTREACHED(); 167 return false; 168 } 169 170 // QueryNode 171 172 QueryNode::QueryNode(const Query& query) : query_(query) { 173 } 174 175 QueryNode::~QueryNode() { 176 } 177 178 // Query 179 180 Query::Query(TraceEventMember member) 181 : type_(QUERY_EVENT_MEMBER), 182 operator_(OP_INVALID), 183 member_(member), 184 number_(0), 185 is_pattern_(false) { 186 } 187 188 Query::Query(TraceEventMember member, const std::string& arg_name) 189 : type_(QUERY_EVENT_MEMBER), 190 operator_(OP_INVALID), 191 member_(member), 192 number_(0), 193 string_(arg_name), 194 is_pattern_(false) { 195 } 196 197 Query::Query(const Query& query) 198 : type_(query.type_), 199 operator_(query.operator_), 200 left_(query.left_), 201 right_(query.right_), 202 member_(query.member_), 203 number_(query.number_), 204 string_(query.string_), 205 is_pattern_(query.is_pattern_) { 206 } 207 208 Query::~Query() { 209 } 210 211 Query Query::String(const std::string& str) { 212 return Query(str); 213 } 214 215 Query Query::Double(double num) { 216 return Query(num); 217 } 218 219 Query Query::Int(int32 num) { 220 return Query(static_cast<double>(num)); 221 } 222 223 Query Query::Uint(uint32 num) { 224 return Query(static_cast<double>(num)); 225 } 226 227 Query Query::Bool(bool boolean) { 228 return Query(boolean ? 1.0 : 0.0); 229 } 230 231 Query Query::Phase(char phase) { 232 return Query(static_cast<double>(phase)); 233 } 234 235 Query Query::Pattern(const std::string& pattern) { 236 Query query(pattern); 237 query.is_pattern_ = true; 238 return query; 239 } 240 241 bool Query::Evaluate(const TraceEvent& event) const { 242 // First check for values that can convert to bool. 243 244 // double is true if != 0: 245 double bool_value = 0.0; 246 bool is_bool = GetAsDouble(event, &bool_value); 247 if (is_bool) 248 return (bool_value != 0.0); 249 250 // string is true if it is non-empty: 251 std::string str_value; 252 bool is_str = GetAsString(event, &str_value); 253 if (is_str) 254 return !str_value.empty(); 255 256 DCHECK(type_ == QUERY_BOOLEAN_OPERATOR) 257 << "Invalid query: missing boolean expression"; 258 DCHECK(left_.get() && (right_.get() || is_unary_operator())); 259 260 if (is_comparison_operator()) { 261 DCHECK(left().is_value() && right().is_value()) 262 << "Invalid query: comparison operator used between event member and " 263 "value."; 264 bool compare_result = false; 265 if (CompareAsDouble(event, &compare_result)) 266 return compare_result; 267 else if (CompareAsString(event, &compare_result)) 268 return compare_result; 269 return false; 270 } 271 // It's a logical operator. 272 switch (operator_) { 273 case OP_AND: 274 return left().Evaluate(event) && right().Evaluate(event); 275 case OP_OR: 276 return left().Evaluate(event) || right().Evaluate(event); 277 case OP_NOT: 278 return !left().Evaluate(event); 279 default: 280 NOTREACHED(); 281 } 282 283 NOTREACHED(); 284 return false; 285 } 286 287 bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const { 288 double lhs, rhs; 289 if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs)) 290 return false; 291 switch (operator_) { 292 case OP_EQ: 293 *result = (lhs == rhs); 294 return true; 295 case OP_NE: 296 *result = (lhs != rhs); 297 return true; 298 case OP_LT: 299 *result = (lhs < rhs); 300 return true; 301 case OP_LE: 302 *result = (lhs <= rhs); 303 return true; 304 case OP_GT: 305 *result = (lhs > rhs); 306 return true; 307 case OP_GE: 308 *result = (lhs >= rhs); 309 return true; 310 default: 311 NOTREACHED(); 312 return false; 313 } 314 return true; 315 } 316 317 bool Query::CompareAsString(const TraceEvent& event, bool* result) const { 318 std::string lhs, rhs; 319 if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs)) 320 return false; 321 switch (operator_) { 322 case OP_EQ: 323 if (right().is_pattern_) 324 *result = MatchPattern(lhs, rhs); 325 else if (left().is_pattern_) 326 *result = MatchPattern(rhs, lhs); 327 else 328 *result = (lhs == rhs); 329 return true; 330 case OP_NE: 331 if (right().is_pattern_) 332 *result = !MatchPattern(lhs, rhs); 333 else if (left().is_pattern_) 334 *result = !MatchPattern(rhs, lhs); 335 else 336 *result = (lhs != rhs); 337 return true; 338 case OP_LT: 339 *result = (lhs < rhs); 340 return true; 341 case OP_LE: 342 *result = (lhs <= rhs); 343 return true; 344 case OP_GT: 345 *result = (lhs > rhs); 346 return true; 347 case OP_GE: 348 *result = (lhs >= rhs); 349 return true; 350 default: 351 NOTREACHED(); 352 return false; 353 } 354 return true; 355 } 356 357 bool Query::EvaluateArithmeticOperator(const TraceEvent& event, 358 double* num) const { 359 DCHECK(type_ == QUERY_ARITHMETIC_OPERATOR); 360 DCHECK(left_.get() && (right_.get() || is_unary_operator())); 361 362 double lhs = 0, rhs = 0; 363 if (!left().GetAsDouble(event, &lhs)) 364 return false; 365 if (!is_unary_operator() && !right().GetAsDouble(event, &rhs)) 366 return false; 367 368 switch (operator_) { 369 case OP_ADD: 370 *num = lhs + rhs; 371 return true; 372 case OP_SUB: 373 *num = lhs - rhs; 374 return true; 375 case OP_MUL: 376 *num = lhs * rhs; 377 return true; 378 case OP_DIV: 379 *num = lhs / rhs; 380 return true; 381 case OP_MOD: 382 *num = static_cast<double>(static_cast<int64>(lhs) % 383 static_cast<int64>(rhs)); 384 return true; 385 case OP_NEGATE: 386 *num = -lhs; 387 return true; 388 default: 389 NOTREACHED(); 390 return false; 391 } 392 } 393 394 bool Query::GetAsDouble(const TraceEvent& event, double* num) const { 395 switch (type_) { 396 case QUERY_ARITHMETIC_OPERATOR: 397 return EvaluateArithmeticOperator(event, num); 398 case QUERY_EVENT_MEMBER: 399 return GetMemberValueAsDouble(event, num); 400 case QUERY_NUMBER: 401 *num = number_; 402 return true; 403 default: 404 return false; 405 } 406 } 407 408 bool Query::GetAsString(const TraceEvent& event, std::string* str) const { 409 switch (type_) { 410 case QUERY_EVENT_MEMBER: 411 return GetMemberValueAsString(event, str); 412 case QUERY_STRING: 413 *str = string_; 414 return true; 415 default: 416 return false; 417 } 418 } 419 420 bool Query::GetMemberValueAsDouble(const TraceEvent& event, 421 double* num) const { 422 DCHECK(type_ == QUERY_EVENT_MEMBER); 423 424 // This could be a request for a member of |event| or a member of |event|'s 425 // associated event. Store the target event in the_event: 426 const TraceEvent* the_event = (member_ < OTHER_PID) ? 427 &event : event.other_event; 428 429 // Request for member of associated event, but there is no associated event. 430 if (!the_event) 431 return false; 432 433 switch (member_) { 434 case EVENT_PID: 435 case OTHER_PID: 436 *num = static_cast<double>(the_event->thread.process_id); 437 return true; 438 case EVENT_TID: 439 case OTHER_TID: 440 *num = static_cast<double>(the_event->thread.thread_id); 441 return true; 442 case EVENT_TIME: 443 case OTHER_TIME: 444 *num = the_event->timestamp; 445 return true; 446 case EVENT_DURATION: 447 if (the_event->has_other_event()) { 448 *num = the_event->GetAbsTimeToOtherEvent(); 449 return true; 450 } 451 return false; 452 case EVENT_PHASE: 453 case OTHER_PHASE: 454 *num = static_cast<double>(the_event->phase); 455 return true; 456 case EVENT_HAS_STRING_ARG: 457 case OTHER_HAS_STRING_ARG: 458 *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0); 459 return true; 460 case EVENT_HAS_NUMBER_ARG: 461 case OTHER_HAS_NUMBER_ARG: 462 *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0); 463 return true; 464 case EVENT_ARG: 465 case OTHER_ARG: { 466 // Search for the argument name and return its value if found. 467 std::map<std::string, double>::const_iterator num_i = 468 the_event->arg_numbers.find(string_); 469 if (num_i == the_event->arg_numbers.end()) 470 return false; 471 *num = num_i->second; 472 return true; 473 } 474 case EVENT_HAS_OTHER: 475 // return 1.0 (true) if the other event exists 476 *num = event.other_event ? 1.0 : 0.0; 477 return true; 478 default: 479 return false; 480 } 481 } 482 483 bool Query::GetMemberValueAsString(const TraceEvent& event, 484 std::string* str) const { 485 DCHECK(type_ == QUERY_EVENT_MEMBER); 486 487 // This could be a request for a member of |event| or a member of |event|'s 488 // associated event. Store the target event in the_event: 489 const TraceEvent* the_event = (member_ < OTHER_PID) ? 490 &event : event.other_event; 491 492 // Request for member of associated event, but there is no associated event. 493 if (!the_event) 494 return false; 495 496 switch (member_) { 497 case EVENT_CATEGORY: 498 case OTHER_CATEGORY: 499 *str = the_event->category; 500 return true; 501 case EVENT_NAME: 502 case OTHER_NAME: 503 *str = the_event->name; 504 return true; 505 case EVENT_ID: 506 case OTHER_ID: 507 *str = the_event->id; 508 return true; 509 case EVENT_ARG: 510 case OTHER_ARG: { 511 // Search for the argument name and return its value if found. 512 std::map<std::string, std::string>::const_iterator str_i = 513 the_event->arg_strings.find(string_); 514 if (str_i == the_event->arg_strings.end()) 515 return false; 516 *str = str_i->second; 517 return true; 518 } 519 default: 520 return false; 521 } 522 } 523 524 Query::Query(const std::string& str) 525 : type_(QUERY_STRING), 526 operator_(OP_INVALID), 527 member_(EVENT_INVALID), 528 number_(0), 529 string_(str), 530 is_pattern_(false) { 531 } 532 533 Query::Query(double num) 534 : type_(QUERY_NUMBER), 535 operator_(OP_INVALID), 536 member_(EVENT_INVALID), 537 number_(num), 538 is_pattern_(false) { 539 } 540 const Query& Query::left() const { 541 return left_->query(); 542 } 543 544 const Query& Query::right() const { 545 return right_->query(); 546 } 547 548 Query Query::operator==(const Query& rhs) const { 549 return Query(*this, rhs, OP_EQ); 550 } 551 552 Query Query::operator!=(const Query& rhs) const { 553 return Query(*this, rhs, OP_NE); 554 } 555 556 Query Query::operator<(const Query& rhs) const { 557 return Query(*this, rhs, OP_LT); 558 } 559 560 Query Query::operator<=(const Query& rhs) const { 561 return Query(*this, rhs, OP_LE); 562 } 563 564 Query Query::operator>(const Query& rhs) const { 565 return Query(*this, rhs, OP_GT); 566 } 567 568 Query Query::operator>=(const Query& rhs) const { 569 return Query(*this, rhs, OP_GE); 570 } 571 572 Query Query::operator&&(const Query& rhs) const { 573 return Query(*this, rhs, OP_AND); 574 } 575 576 Query Query::operator||(const Query& rhs) const { 577 return Query(*this, rhs, OP_OR); 578 } 579 580 Query Query::operator!() const { 581 return Query(*this, OP_NOT); 582 } 583 584 Query Query::operator+(const Query& rhs) const { 585 return Query(*this, rhs, OP_ADD); 586 } 587 588 Query Query::operator-(const Query& rhs) const { 589 return Query(*this, rhs, OP_SUB); 590 } 591 592 Query Query::operator*(const Query& rhs) const { 593 return Query(*this, rhs, OP_MUL); 594 } 595 596 Query Query::operator/(const Query& rhs) const { 597 return Query(*this, rhs, OP_DIV); 598 } 599 600 Query Query::operator%(const Query& rhs) const { 601 return Query(*this, rhs, OP_MOD); 602 } 603 604 Query Query::operator-() const { 605 return Query(*this, OP_NEGATE); 606 } 607 608 609 Query::Query(const Query& left, const Query& right, Operator binary_op) 610 : operator_(binary_op), 611 left_(new QueryNode(left)), 612 right_(new QueryNode(right)), 613 member_(EVENT_INVALID), 614 number_(0) { 615 type_ = (binary_op < OP_ADD ? 616 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR); 617 } 618 619 Query::Query(const Query& left, Operator unary_op) 620 : operator_(unary_op), 621 left_(new QueryNode(left)), 622 member_(EVENT_INVALID), 623 number_(0) { 624 type_ = (unary_op < OP_ADD ? 625 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR); 626 } 627 628 namespace { 629 630 // Search |events| for |query| and add matches to |output|. 631 size_t FindMatchingEvents(const std::vector<TraceEvent>& events, 632 const Query& query, 633 TraceEventVector* output) { 634 for (size_t i = 0; i < events.size(); ++i) { 635 if (query.Evaluate(events[i])) 636 output->push_back(&events[i]); 637 } 638 return output->size(); 639 } 640 641 bool ParseEventsFromJson(const std::string& json, 642 std::vector<TraceEvent>* output) { 643 scoped_ptr<base::Value> root; 644 root.reset(base::JSONReader::Read(json)); 645 646 base::ListValue* root_list = NULL; 647 if (!root.get() || !root->GetAsList(&root_list)) 648 return false; 649 650 for (size_t i = 0; i < root_list->GetSize(); ++i) { 651 base::Value* item = NULL; 652 if (root_list->Get(i, &item)) { 653 TraceEvent event; 654 if (event.SetFromJSON(item)) 655 output->push_back(event); 656 else 657 return false; 658 } 659 } 660 661 return true; 662 } 663 664 } // namespace 665 666 // TraceAnalyzer 667 668 TraceAnalyzer::TraceAnalyzer() : allow_assocation_changes_(true) { 669 } 670 671 TraceAnalyzer::~TraceAnalyzer() { 672 } 673 674 // static 675 TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) { 676 scoped_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer()); 677 if (analyzer->SetEvents(json_events)) 678 return analyzer.release(); 679 return NULL; 680 } 681 682 bool TraceAnalyzer::SetEvents(const std::string& json_events) { 683 raw_events_.clear(); 684 if (!ParseEventsFromJson(json_events, &raw_events_)) 685 return false; 686 std::stable_sort(raw_events_.begin(), raw_events_.end()); 687 ParseMetadata(); 688 return true; 689 } 690 691 void TraceAnalyzer::AssociateBeginEndEvents() { 692 using trace_analyzer::Query; 693 694 Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN)); 695 Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END)); 696 Query match(Query::EventName() == Query::OtherName() && 697 Query::EventCategory() == Query::OtherCategory() && 698 Query::EventTid() == Query::OtherTid() && 699 Query::EventPid() == Query::OtherPid()); 700 701 AssociateEvents(begin, end, match); 702 } 703 704 void TraceAnalyzer::AssociateAsyncBeginEndEvents() { 705 using trace_analyzer::Query; 706 707 Query begin( 708 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) || 709 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP)); 710 Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) || 711 Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP)); 712 Query match(Query::EventName() == Query::OtherName() && 713 Query::EventCategory() == Query::OtherCategory() && 714 Query::EventId() == Query::OtherId()); 715 716 AssociateEvents(begin, end, match); 717 } 718 719 void TraceAnalyzer::AssociateEvents(const Query& first, 720 const Query& second, 721 const Query& match) { 722 DCHECK(allow_assocation_changes_) << "AssociateEvents not allowed after " 723 "FindEvents"; 724 725 // Search for matching begin/end event pairs. When a matching end is found, 726 // it is associated with the begin event. 727 std::vector<TraceEvent*> begin_stack; 728 for (size_t event_index = 0; event_index < raw_events_.size(); 729 ++event_index) { 730 731 TraceEvent& this_event = raw_events_[event_index]; 732 733 if (second.Evaluate(this_event)) { 734 // Search stack for matching begin, starting from end. 735 for (int stack_index = static_cast<int>(begin_stack.size()) - 1; 736 stack_index >= 0; --stack_index) { 737 TraceEvent& begin_event = *begin_stack[stack_index]; 738 739 // Temporarily set other to test against the match query. 740 const TraceEvent* other_backup = begin_event.other_event; 741 begin_event.other_event = &this_event; 742 if (match.Evaluate(begin_event)) { 743 // Found a matching begin/end pair. 744 // Erase the matching begin event index from the stack. 745 begin_stack.erase(begin_stack.begin() + stack_index); 746 break; 747 } 748 749 // Not a match, restore original other and continue. 750 begin_event.other_event = other_backup; 751 } 752 } 753 // Even if this_event is a |second| event that has matched an earlier 754 // |first| event, it can still also be a |first| event and be associated 755 // with a later |second| event. 756 if (first.Evaluate(this_event)) { 757 begin_stack.push_back(&this_event); 758 } 759 } 760 } 761 762 void TraceAnalyzer::MergeAssociatedEventArgs() { 763 for (size_t i = 0; i < raw_events_.size(); ++i) { 764 // Merge all associated events with the first event. 765 const TraceEvent* other = raw_events_[i].other_event; 766 // Avoid looping by keeping set of encountered TraceEvents. 767 std::set<const TraceEvent*> encounters; 768 encounters.insert(&raw_events_[i]); 769 while (other && encounters.find(other) == encounters.end()) { 770 encounters.insert(other); 771 raw_events_[i].arg_numbers.insert( 772 other->arg_numbers.begin(), 773 other->arg_numbers.end()); 774 raw_events_[i].arg_strings.insert( 775 other->arg_strings.begin(), 776 other->arg_strings.end()); 777 other = other->other_event; 778 } 779 } 780 } 781 782 size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) { 783 allow_assocation_changes_ = false; 784 output->clear(); 785 return FindMatchingEvents(raw_events_, query, output); 786 } 787 788 const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) { 789 TraceEventVector output; 790 if (FindEvents(query, &output) > 0) 791 return output.front(); 792 return NULL; 793 } 794 795 const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) { 796 TraceEventVector output; 797 if (FindEvents(query, &output) > 0) 798 return output.back(); 799 return NULL; 800 } 801 802 const std::string& TraceAnalyzer::GetThreadName( 803 const TraceEvent::ProcessThreadID& thread) { 804 // If thread is not found, just add and return empty string. 805 return thread_names_[thread]; 806 } 807 808 void TraceAnalyzer::ParseMetadata() { 809 for (size_t i = 0; i < raw_events_.size(); ++i) { 810 TraceEvent& this_event = raw_events_[i]; 811 // Check for thread name metadata. 812 if (this_event.phase != TRACE_EVENT_PHASE_METADATA || 813 this_event.name != "thread_name") 814 continue; 815 std::map<std::string, std::string>::const_iterator string_it = 816 this_event.arg_strings.find("name"); 817 if (string_it != this_event.arg_strings.end()) 818 thread_names_[this_event.thread] = string_it->second; 819 } 820 } 821 822 // TraceEventVector utility functions. 823 824 bool GetRateStats(const TraceEventVector& events, 825 RateStats* stats, 826 const RateStatsOptions* options) { 827 CHECK(stats); 828 // Need at least 3 events to calculate rate stats. 829 const size_t kMinEvents = 3; 830 if (events.size() < kMinEvents) { 831 LOG(ERROR) << "Not enough events: " << events.size(); 832 return false; 833 } 834 835 std::vector<double> deltas; 836 size_t num_deltas = events.size() - 1; 837 for (size_t i = 0; i < num_deltas; ++i) { 838 double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp; 839 if (delta < 0.0) { 840 LOG(ERROR) << "Events are out of order"; 841 return false; 842 } 843 deltas.push_back(delta); 844 } 845 846 std::sort(deltas.begin(), deltas.end()); 847 848 if (options) { 849 if (options->trim_min + options->trim_max > events.size() - kMinEvents) { 850 LOG(ERROR) << "Attempt to trim too many events"; 851 return false; 852 } 853 deltas.erase(deltas.begin(), deltas.begin() + options->trim_min); 854 deltas.erase(deltas.end() - options->trim_max, deltas.end()); 855 } 856 857 num_deltas = deltas.size(); 858 double delta_sum = 0.0; 859 for (size_t i = 0; i < num_deltas; ++i) 860 delta_sum += deltas[i]; 861 862 stats->min_us = *std::min_element(deltas.begin(), deltas.end()); 863 stats->max_us = *std::max_element(deltas.begin(), deltas.end()); 864 stats->mean_us = delta_sum / static_cast<double>(num_deltas); 865 866 double sum_mean_offsets_squared = 0.0; 867 for (size_t i = 0; i < num_deltas; ++i) { 868 double offset = fabs(deltas[i] - stats->mean_us); 869 sum_mean_offsets_squared += offset * offset; 870 } 871 stats->standard_deviation_us = 872 sum_mean_offsets_squared / static_cast<double>(num_deltas - 1); 873 874 return true; 875 } 876 877 bool FindFirstOf(const TraceEventVector& events, 878 const Query& query, 879 size_t position, 880 size_t* return_index) { 881 CHECK(return_index); 882 for (size_t i = position; i < events.size(); ++i) { 883 if (query.Evaluate(*events.at(i))) { 884 *return_index = i; 885 return true; 886 } 887 } 888 return false; 889 } 890 891 bool FindLastOf(const TraceEventVector& events, 892 const Query& query, 893 size_t position, 894 size_t* return_index) { 895 CHECK(return_index); 896 if (events.empty()) 897 return false; 898 position = (position < events.size()) ? position : events.size() - 1; 899 for (;;) { 900 if (query.Evaluate(*events.at(position))) { 901 *return_index = position; 902 return true; 903 } 904 if (position == 0) 905 return false; 906 --position; 907 } 908 return false; 909 } 910 911 bool FindClosest(const TraceEventVector& events, 912 const Query& query, 913 size_t position, 914 size_t* return_closest, 915 size_t* return_second_closest) { 916 CHECK(return_closest); 917 if (events.empty() || position >= events.size()) 918 return false; 919 size_t closest = events.size(); 920 size_t second_closest = events.size(); 921 for (size_t i = 0; i < events.size(); ++i) { 922 if (!query.Evaluate(*events.at(i))) 923 continue; 924 if (closest == events.size()) { 925 closest = i; 926 continue; 927 } 928 if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) < 929 fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) { 930 second_closest = closest; 931 closest = i; 932 } else if (second_closest == events.size()) { 933 second_closest = i; 934 } 935 } 936 937 if (closest < events.size() && 938 (!return_second_closest || second_closest < events.size())) { 939 *return_closest = closest; 940 if (return_second_closest) 941 *return_second_closest = second_closest; 942 return true; 943 } 944 945 return false; 946 } 947 948 size_t CountMatches(const TraceEventVector& events, 949 const Query& query, 950 size_t begin_position, 951 size_t end_position) { 952 if (begin_position >= events.size()) 953 return 0u; 954 end_position = (end_position < events.size()) ? end_position : events.size(); 955 size_t count = 0u; 956 for (size_t i = begin_position; i < end_position; ++i) { 957 if (query.Evaluate(*events.at(i))) 958 ++count; 959 } 960 return count; 961 } 962 963 } // namespace trace_analyzer 964