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 // Use trace_analyzer::Query and trace_analyzer::TraceAnalyzer to search for 6 // specific trace events that were generated by the trace_event.h API. 7 // 8 // Basic procedure: 9 // - Get trace events JSON string from base::trace_event::TraceLog. 10 // - Create TraceAnalyzer with JSON string. 11 // - Call TraceAnalyzer::AssociateBeginEndEvents (optional). 12 // - Call TraceAnalyzer::AssociateEvents (zero or more times). 13 // - Call TraceAnalyzer::FindEvents with queries to find specific events. 14 // 15 // A Query is a boolean expression tree that evaluates to true or false for a 16 // given trace event. Queries can be combined into a tree using boolean, 17 // arithmetic and comparison operators that refer to data of an individual trace 18 // event. 19 // 20 // The events are returned as trace_analyzer::TraceEvent objects. 21 // TraceEvent contains a single trace event's data, as well as a pointer to 22 // a related trace event. The related trace event is typically the matching end 23 // of a begin event or the matching begin of an end event. 24 // 25 // The following examples use this basic setup code to construct TraceAnalyzer 26 // with the json trace string retrieved from TraceLog and construct an event 27 // vector for retrieving events: 28 // 29 // TraceAnalyzer analyzer(json_events); 30 // TraceEventVector events; 31 // 32 // EXAMPLE 1: Find events named "my_event". 33 // 34 // analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events); 35 // 36 // EXAMPLE 2: Find begin events named "my_event" with duration > 1 second. 37 // 38 // Query q = (Query(EVENT_NAME) == Query::String("my_event") && 39 // Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) && 40 // Query(EVENT_DURATION) > Query::Double(1000000.0)); 41 // analyzer.FindEvents(q, &events); 42 // 43 // EXAMPLE 3: Associating event pairs across threads. 44 // 45 // If the test needs to analyze something that starts and ends on different 46 // threads, the test needs to use INSTANT events. The typical procedure is to 47 // specify the same unique ID as a TRACE_EVENT argument on both the start and 48 // finish INSTANT events. Then use the following procedure to associate those 49 // events. 50 // 51 // Step 1: instrument code with custom begin/end trace events. 52 // [Thread 1 tracing code] 53 // TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3); 54 // [Thread 2 tracing code] 55 // TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3); 56 // 57 // Step 2: associate these custom begin/end pairs. 58 // Query begin(Query(EVENT_NAME) == Query::String("timing1_begin")); 59 // Query end(Query(EVENT_NAME) == Query::String("timing1_end")); 60 // Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id")); 61 // analyzer.AssociateEvents(begin, end, match); 62 // 63 // Step 3: search for "timing1_begin" events with existing other event. 64 // Query q = (Query(EVENT_NAME) == Query::String("timing1_begin") && 65 // Query(EVENT_HAS_OTHER)); 66 // analyzer.FindEvents(q, &events); 67 // 68 // Step 4: analyze events, such as checking durations. 69 // for (size_t i = 0; i < events.size(); ++i) { 70 // double duration; 71 // EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration)); 72 // EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second. 73 // } 74 75 76 #ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_ 77 #define BASE_TEST_TRACE_EVENT_ANALYZER_H_ 78 79 #include <stddef.h> 80 #include <stdint.h> 81 82 #include <map> 83 84 #include "base/macros.h" 85 #include "base/memory/ref_counted.h" 86 #include "base/trace_event/trace_event.h" 87 88 namespace base { 89 class Value; 90 } 91 92 namespace trace_analyzer { 93 class QueryNode; 94 95 // trace_analyzer::TraceEvent is a more convenient form of the 96 // base::trace_event::TraceEvent class to make tracing-based tests easier to 97 // write. 98 struct TraceEvent { 99 // ProcessThreadID contains a Process ID and Thread ID. 100 struct ProcessThreadID { 101 ProcessThreadID() : process_id(0), thread_id(0) {} 102 ProcessThreadID(int process_id, int thread_id) 103 : process_id(process_id), thread_id(thread_id) {} 104 bool operator< (const ProcessThreadID& rhs) const { 105 if (process_id != rhs.process_id) 106 return process_id < rhs.process_id; 107 return thread_id < rhs.thread_id; 108 } 109 int process_id; 110 int thread_id; 111 }; 112 113 TraceEvent(); 114 TraceEvent(TraceEvent&& other); 115 ~TraceEvent(); 116 117 bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT; 118 119 bool operator< (const TraceEvent& rhs) const { 120 return timestamp < rhs.timestamp; 121 } 122 123 TraceEvent& operator=(TraceEvent&& rhs); 124 125 bool has_other_event() const { return other_event; } 126 127 // Returns absolute duration in microseconds between this event and other 128 // event. Must have already verified that other_event exists by 129 // Query(EVENT_HAS_OTHER) or by calling has_other_event(). 130 double GetAbsTimeToOtherEvent() const; 131 132 // Return the argument value if it exists and it is a string. 133 bool GetArgAsString(const std::string& name, std::string* arg) const; 134 // Return the argument value if it exists and it is a number. 135 bool GetArgAsNumber(const std::string& name, double* arg) const; 136 // Return the argument value if it exists. 137 bool GetArgAsValue(const std::string& name, 138 std::unique_ptr<base::Value>* arg) const; 139 140 // Check if argument exists and is string. 141 bool HasStringArg(const std::string& name) const; 142 // Check if argument exists and is number (double, int or bool). 143 bool HasNumberArg(const std::string& name) const; 144 // Check if argument exists. 145 bool HasArg(const std::string& name) const; 146 147 // Get known existing arguments as specific types. 148 // Useful when you have already queried the argument with 149 // Query(HAS_NUMBER_ARG) or Query(HAS_STRING_ARG). 150 std::string GetKnownArgAsString(const std::string& name) const; 151 double GetKnownArgAsDouble(const std::string& name) const; 152 int GetKnownArgAsInt(const std::string& name) const; 153 bool GetKnownArgAsBool(const std::string& name) const; 154 std::unique_ptr<base::Value> GetKnownArgAsValue( 155 const std::string& name) const; 156 157 // Process ID and Thread ID. 158 ProcessThreadID thread; 159 160 // Time since epoch in microseconds. 161 // Stored as double to match its JSON representation. 162 double timestamp; 163 double duration; 164 char phase; 165 std::string category; 166 std::string name; 167 std::string id; 168 169 // All numbers and bool values from TraceEvent args are cast to double. 170 // bool becomes 1.0 (true) or 0.0 (false). 171 std::map<std::string, double> arg_numbers; 172 std::map<std::string, std::string> arg_strings; 173 std::map<std::string, std::unique_ptr<base::Value>> arg_values; 174 175 // The other event associated with this event (or NULL). 176 const TraceEvent* other_event; 177 178 // A back-link for |other_event|. That is, if other_event is not null, then 179 // |event->other_event->prev_event == event| is always true. 180 const TraceEvent* prev_event; 181 }; 182 183 typedef std::vector<const TraceEvent*> TraceEventVector; 184 185 class Query { 186 public: 187 Query(const Query& query); 188 189 ~Query(); 190 191 //////////////////////////////////////////////////////////////// 192 // Query literal values 193 194 // Compare with the given string. 195 static Query String(const std::string& str); 196 197 // Compare with the given number. 198 static Query Double(double num); 199 static Query Int(int32_t num); 200 static Query Uint(uint32_t num); 201 202 // Compare with the given bool. 203 static Query Bool(bool boolean); 204 205 // Compare with the given phase. 206 static Query Phase(char phase); 207 208 // Compare with the given string pattern. Only works with == and != operators. 209 // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*") 210 static Query Pattern(const std::string& pattern); 211 212 //////////////////////////////////////////////////////////////// 213 // Query event members 214 215 static Query EventPid() { return Query(EVENT_PID); } 216 217 static Query EventTid() { return Query(EVENT_TID); } 218 219 // Return the timestamp of the event in microseconds since epoch. 220 static Query EventTime() { return Query(EVENT_TIME); } 221 222 // Return the absolute time between event and other event in microseconds. 223 // Only works if Query::EventHasOther() == true. 224 static Query EventDuration() { return Query(EVENT_DURATION); } 225 226 // Return the duration of a COMPLETE event. 227 static Query EventCompleteDuration() { 228 return Query(EVENT_COMPLETE_DURATION); 229 } 230 231 static Query EventPhase() { return Query(EVENT_PHASE); } 232 233 static Query EventCategory() { return Query(EVENT_CATEGORY); } 234 235 static Query EventName() { return Query(EVENT_NAME); } 236 237 static Query EventId() { return Query(EVENT_ID); } 238 239 static Query EventPidIs(int process_id) { 240 return Query(EVENT_PID) == Query::Int(process_id); 241 } 242 243 static Query EventTidIs(int thread_id) { 244 return Query(EVENT_TID) == Query::Int(thread_id); 245 } 246 247 static Query EventThreadIs(const TraceEvent::ProcessThreadID& thread) { 248 return EventPidIs(thread.process_id) && EventTidIs(thread.thread_id); 249 } 250 251 static Query EventTimeIs(double timestamp) { 252 return Query(EVENT_TIME) == Query::Double(timestamp); 253 } 254 255 static Query EventDurationIs(double duration) { 256 return Query(EVENT_DURATION) == Query::Double(duration); 257 } 258 259 static Query EventPhaseIs(char phase) { 260 return Query(EVENT_PHASE) == Query::Phase(phase); 261 } 262 263 static Query EventCategoryIs(const std::string& category) { 264 return Query(EVENT_CATEGORY) == Query::String(category); 265 } 266 267 static Query EventNameIs(const std::string& name) { 268 return Query(EVENT_NAME) == Query::String(name); 269 } 270 271 static Query EventIdIs(const std::string& id) { 272 return Query(EVENT_ID) == Query::String(id); 273 } 274 275 // Evaluates to true if arg exists and is a string. 276 static Query EventHasStringArg(const std::string& arg_name) { 277 return Query(EVENT_HAS_STRING_ARG, arg_name); 278 } 279 280 // Evaluates to true if arg exists and is a number. 281 // Number arguments include types double, int and bool. 282 static Query EventHasNumberArg(const std::string& arg_name) { 283 return Query(EVENT_HAS_NUMBER_ARG, arg_name); 284 } 285 286 // Evaluates to arg value (string or number). 287 static Query EventArg(const std::string& arg_name) { 288 return Query(EVENT_ARG, arg_name); 289 } 290 291 // Return true if associated event exists. 292 static Query EventHasOther() { return Query(EVENT_HAS_OTHER); } 293 294 // Access the associated other_event's members: 295 296 static Query OtherPid() { return Query(OTHER_PID); } 297 298 static Query OtherTid() { return Query(OTHER_TID); } 299 300 static Query OtherTime() { return Query(OTHER_TIME); } 301 302 static Query OtherPhase() { return Query(OTHER_PHASE); } 303 304 static Query OtherCategory() { return Query(OTHER_CATEGORY); } 305 306 static Query OtherName() { return Query(OTHER_NAME); } 307 308 static Query OtherId() { return Query(OTHER_ID); } 309 310 static Query OtherPidIs(int process_id) { 311 return Query(OTHER_PID) == Query::Int(process_id); 312 } 313 314 static Query OtherTidIs(int thread_id) { 315 return Query(OTHER_TID) == Query::Int(thread_id); 316 } 317 318 static Query OtherThreadIs(const TraceEvent::ProcessThreadID& thread) { 319 return OtherPidIs(thread.process_id) && OtherTidIs(thread.thread_id); 320 } 321 322 static Query OtherTimeIs(double timestamp) { 323 return Query(OTHER_TIME) == Query::Double(timestamp); 324 } 325 326 static Query OtherPhaseIs(char phase) { 327 return Query(OTHER_PHASE) == Query::Phase(phase); 328 } 329 330 static Query OtherCategoryIs(const std::string& category) { 331 return Query(OTHER_CATEGORY) == Query::String(category); 332 } 333 334 static Query OtherNameIs(const std::string& name) { 335 return Query(OTHER_NAME) == Query::String(name); 336 } 337 338 static Query OtherIdIs(const std::string& id) { 339 return Query(OTHER_ID) == Query::String(id); 340 } 341 342 // Evaluates to true if arg exists and is a string. 343 static Query OtherHasStringArg(const std::string& arg_name) { 344 return Query(OTHER_HAS_STRING_ARG, arg_name); 345 } 346 347 // Evaluates to true if arg exists and is a number. 348 // Number arguments include types double, int and bool. 349 static Query OtherHasNumberArg(const std::string& arg_name) { 350 return Query(OTHER_HAS_NUMBER_ARG, arg_name); 351 } 352 353 // Evaluates to arg value (string or number). 354 static Query OtherArg(const std::string& arg_name) { 355 return Query(OTHER_ARG, arg_name); 356 } 357 358 // Access the associated prev_event's members: 359 360 static Query PrevPid() { return Query(PREV_PID); } 361 362 static Query PrevTid() { return Query(PREV_TID); } 363 364 static Query PrevTime() { return Query(PREV_TIME); } 365 366 static Query PrevPhase() { return Query(PREV_PHASE); } 367 368 static Query PrevCategory() { return Query(PREV_CATEGORY); } 369 370 static Query PrevName() { return Query(PREV_NAME); } 371 372 static Query PrevId() { return Query(PREV_ID); } 373 374 static Query PrevPidIs(int process_id) { 375 return Query(PREV_PID) == Query::Int(process_id); 376 } 377 378 static Query PrevTidIs(int thread_id) { 379 return Query(PREV_TID) == Query::Int(thread_id); 380 } 381 382 static Query PrevThreadIs(const TraceEvent::ProcessThreadID& thread) { 383 return PrevPidIs(thread.process_id) && PrevTidIs(thread.thread_id); 384 } 385 386 static Query PrevTimeIs(double timestamp) { 387 return Query(PREV_TIME) == Query::Double(timestamp); 388 } 389 390 static Query PrevPhaseIs(char phase) { 391 return Query(PREV_PHASE) == Query::Phase(phase); 392 } 393 394 static Query PrevCategoryIs(const std::string& category) { 395 return Query(PREV_CATEGORY) == Query::String(category); 396 } 397 398 static Query PrevNameIs(const std::string& name) { 399 return Query(PREV_NAME) == Query::String(name); 400 } 401 402 static Query PrevIdIs(const std::string& id) { 403 return Query(PREV_ID) == Query::String(id); 404 } 405 406 // Evaluates to true if arg exists and is a string. 407 static Query PrevHasStringArg(const std::string& arg_name) { 408 return Query(PREV_HAS_STRING_ARG, arg_name); 409 } 410 411 // Evaluates to true if arg exists and is a number. 412 // Number arguments include types double, int and bool. 413 static Query PrevHasNumberArg(const std::string& arg_name) { 414 return Query(PREV_HAS_NUMBER_ARG, arg_name); 415 } 416 417 // Evaluates to arg value (string or number). 418 static Query PrevArg(const std::string& arg_name) { 419 return Query(PREV_ARG, arg_name); 420 } 421 422 //////////////////////////////////////////////////////////////// 423 // Common queries: 424 425 // Find BEGIN events that have a corresponding END event. 426 static Query MatchBeginWithEnd() { 427 return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN)) && 428 Query(EVENT_HAS_OTHER); 429 } 430 431 // Find COMPLETE events. 432 static Query MatchComplete() { 433 return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_COMPLETE)); 434 } 435 436 // Find ASYNC_BEGIN events that have a corresponding ASYNC_END event. 437 static Query MatchAsyncBeginWithNext() { 438 return (Query(EVENT_PHASE) == 439 Query::Phase(TRACE_EVENT_PHASE_ASYNC_BEGIN)) && 440 Query(EVENT_HAS_OTHER); 441 } 442 443 // Find BEGIN events of given |name| which also have associated END events. 444 static Query MatchBeginName(const std::string& name) { 445 return (Query(EVENT_NAME) == Query(name)) && MatchBeginWithEnd(); 446 } 447 448 // Find COMPLETE events of given |name|. 449 static Query MatchCompleteName(const std::string& name) { 450 return (Query(EVENT_NAME) == Query(name)) && MatchComplete(); 451 } 452 453 // Match given Process ID and Thread ID. 454 static Query MatchThread(const TraceEvent::ProcessThreadID& thread) { 455 return (Query(EVENT_PID) == Query::Int(thread.process_id)) && 456 (Query(EVENT_TID) == Query::Int(thread.thread_id)); 457 } 458 459 // Match event pair that spans multiple threads. 460 static Query MatchCrossThread() { 461 return (Query(EVENT_PID) != Query(OTHER_PID)) || 462 (Query(EVENT_TID) != Query(OTHER_TID)); 463 } 464 465 //////////////////////////////////////////////////////////////// 466 // Operators: 467 468 // Boolean operators: 469 Query operator==(const Query& rhs) const; 470 Query operator!=(const Query& rhs) const; 471 Query operator< (const Query& rhs) const; 472 Query operator<=(const Query& rhs) const; 473 Query operator> (const Query& rhs) const; 474 Query operator>=(const Query& rhs) const; 475 Query operator&&(const Query& rhs) const; 476 Query operator||(const Query& rhs) const; 477 Query operator!() const; 478 479 // Arithmetic operators: 480 // Following operators are applied to double arguments: 481 Query operator+(const Query& rhs) const; 482 Query operator-(const Query& rhs) const; 483 Query operator*(const Query& rhs) const; 484 Query operator/(const Query& rhs) const; 485 Query operator-() const; 486 // Mod operates on int64_t args (doubles are casted to int64_t beforehand): 487 Query operator%(const Query& rhs) const; 488 489 // Return true if the given event matches this query tree. 490 // This is a recursive method that walks the query tree. 491 bool Evaluate(const TraceEvent& event) const; 492 493 private: 494 enum TraceEventMember { 495 EVENT_INVALID, 496 EVENT_PID, 497 EVENT_TID, 498 EVENT_TIME, 499 EVENT_DURATION, 500 EVENT_COMPLETE_DURATION, 501 EVENT_PHASE, 502 EVENT_CATEGORY, 503 EVENT_NAME, 504 EVENT_ID, 505 EVENT_HAS_STRING_ARG, 506 EVENT_HAS_NUMBER_ARG, 507 EVENT_ARG, 508 EVENT_HAS_OTHER, 509 EVENT_HAS_PREV, 510 511 OTHER_PID, 512 OTHER_TID, 513 OTHER_TIME, 514 OTHER_PHASE, 515 OTHER_CATEGORY, 516 OTHER_NAME, 517 OTHER_ID, 518 OTHER_HAS_STRING_ARG, 519 OTHER_HAS_NUMBER_ARG, 520 OTHER_ARG, 521 522 PREV_PID, 523 PREV_TID, 524 PREV_TIME, 525 PREV_PHASE, 526 PREV_CATEGORY, 527 PREV_NAME, 528 PREV_ID, 529 PREV_HAS_STRING_ARG, 530 PREV_HAS_NUMBER_ARG, 531 PREV_ARG, 532 533 OTHER_FIRST_MEMBER = OTHER_PID, 534 OTHER_LAST_MEMBER = OTHER_ARG, 535 536 PREV_FIRST_MEMBER = PREV_PID, 537 PREV_LAST_MEMBER = PREV_ARG, 538 }; 539 540 enum Operator { 541 OP_INVALID, 542 // Boolean operators: 543 OP_EQ, 544 OP_NE, 545 OP_LT, 546 OP_LE, 547 OP_GT, 548 OP_GE, 549 OP_AND, 550 OP_OR, 551 OP_NOT, 552 // Arithmetic operators: 553 OP_ADD, 554 OP_SUB, 555 OP_MUL, 556 OP_DIV, 557 OP_MOD, 558 OP_NEGATE 559 }; 560 561 enum QueryType { 562 QUERY_BOOLEAN_OPERATOR, 563 QUERY_ARITHMETIC_OPERATOR, 564 QUERY_EVENT_MEMBER, 565 QUERY_NUMBER, 566 QUERY_STRING 567 }; 568 569 // Compare with the given member. 570 explicit Query(TraceEventMember member); 571 572 // Compare with the given member argument value. 573 Query(TraceEventMember member, const std::string& arg_name); 574 575 // Compare with the given string. 576 explicit Query(const std::string& str); 577 578 // Compare with the given number. 579 explicit Query(double num); 580 581 // Construct a boolean Query that returns (left <binary_op> right). 582 Query(const Query& left, const Query& right, Operator binary_op); 583 584 // Construct a boolean Query that returns (<binary_op> left). 585 Query(const Query& left, Operator unary_op); 586 587 // Try to compare left_ against right_ based on operator_. 588 // If either left or right does not convert to double, false is returned. 589 // Otherwise, true is returned and |result| is set to the comparison result. 590 bool CompareAsDouble(const TraceEvent& event, bool* result) const; 591 592 // Try to compare left_ against right_ based on operator_. 593 // If either left or right does not convert to string, false is returned. 594 // Otherwise, true is returned and |result| is set to the comparison result. 595 bool CompareAsString(const TraceEvent& event, bool* result) const; 596 597 // Attempt to convert this Query to a double. On success, true is returned 598 // and the double value is stored in |num|. 599 bool GetAsDouble(const TraceEvent& event, double* num) const; 600 601 // Attempt to convert this Query to a string. On success, true is returned 602 // and the string value is stored in |str|. 603 bool GetAsString(const TraceEvent& event, std::string* str) const; 604 605 // Evaluate this Query as an arithmetic operator on left_ and right_. 606 bool EvaluateArithmeticOperator(const TraceEvent& event, 607 double* num) const; 608 609 // For QUERY_EVENT_MEMBER Query: attempt to get the double value of the Query. 610 bool GetMemberValueAsDouble(const TraceEvent& event, double* num) const; 611 612 // For QUERY_EVENT_MEMBER Query: attempt to get the string value of the Query. 613 bool GetMemberValueAsString(const TraceEvent& event, std::string* num) const; 614 615 // Does this Query represent a value? 616 bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; } 617 618 bool is_unary_operator() const { 619 return operator_ == OP_NOT || operator_ == OP_NEGATE; 620 } 621 622 bool is_comparison_operator() const { 623 return operator_ != OP_INVALID && operator_ < OP_AND; 624 } 625 626 static const TraceEvent* SelectTargetEvent(const TraceEvent* ev, 627 TraceEventMember member); 628 629 const Query& left() const; 630 const Query& right() const; 631 632 QueryType type_; 633 Operator operator_; 634 scoped_refptr<QueryNode> left_; 635 scoped_refptr<QueryNode> right_; 636 TraceEventMember member_; 637 double number_; 638 std::string string_; 639 bool is_pattern_; 640 }; 641 642 // Implementation detail: 643 // QueryNode allows Query to store a ref-counted query tree. 644 class QueryNode : public base::RefCounted<QueryNode> { 645 public: 646 explicit QueryNode(const Query& query); 647 const Query& query() const { return query_; } 648 649 private: 650 friend class base::RefCounted<QueryNode>; 651 ~QueryNode(); 652 653 Query query_; 654 }; 655 656 // TraceAnalyzer helps tests search for trace events. 657 class TraceAnalyzer { 658 public: 659 ~TraceAnalyzer(); 660 661 // Use trace events from JSON string generated by tracing API. 662 // Returns non-NULL if the JSON is successfully parsed. 663 static TraceAnalyzer* Create(const std::string& json_events) 664 WARN_UNUSED_RESULT; 665 666 void SetIgnoreMetadataEvents(bool ignore) { 667 ignore_metadata_events_ = ignore; 668 } 669 670 // Associate BEGIN and END events with each other. This allows Query(OTHER_*) 671 // to access the associated event and enables Query(EVENT_DURATION). 672 // An end event will match the most recent begin event with the same name, 673 // category, process ID and thread ID. This matches what is shown in 674 // about:tracing. After association, the BEGIN event will point to the 675 // matching END event, but the END event will not point to the BEGIN event. 676 void AssociateBeginEndEvents(); 677 678 // Associate ASYNC_BEGIN, ASYNC_STEP and ASYNC_END events with each other. 679 // An ASYNC_END event will match the most recent ASYNC_BEGIN or ASYNC_STEP 680 // event with the same name, category, and ID. This creates a singly linked 681 // list of ASYNC_BEGIN->ASYNC_STEP...->ASYNC_END. 682 // |match_pid| - If true, will only match async events which are running 683 // under the same process ID, otherwise will allow linking 684 // async events from different processes. 685 void AssociateAsyncBeginEndEvents(bool match_pid = true); 686 687 // AssociateEvents can be used to customize event associations by setting the 688 // other_event member of TraceEvent. This should be used to associate two 689 // INSTANT events. 690 // 691 // The assumptions are: 692 // - |first| events occur before |second| events. 693 // - the closest matching |second| event is the correct match. 694 // 695 // |first| - Eligible |first| events match this query. 696 // |second| - Eligible |second| events match this query. 697 // |match| - This query is run on the |first| event. The OTHER_* EventMember 698 // queries will point to an eligible |second| event. The query 699 // should evaluate to true if the |first|/|second| pair is a match. 700 // 701 // When a match is found, the pair will be associated by having the first 702 // event's other_event member point to the other. AssociateEvents does not 703 // clear previous associations, so it is possible to associate multiple pairs 704 // of events by calling AssociateEvents more than once with different queries. 705 // 706 // NOTE: AssociateEvents will overwrite existing other_event associations if 707 // the queries pass for events that already had a previous association. 708 // 709 // After calling any Find* method, it is not allowed to call AssociateEvents 710 // again. 711 void AssociateEvents(const Query& first, 712 const Query& second, 713 const Query& match); 714 715 // For each event, copy its arguments to the other_event argument map. If 716 // argument name already exists, it will not be overwritten. 717 void MergeAssociatedEventArgs(); 718 719 // Find all events that match query and replace output vector. 720 size_t FindEvents(const Query& query, TraceEventVector* output); 721 722 // Find first event that matches query or NULL if not found. 723 const TraceEvent* FindFirstOf(const Query& query); 724 725 // Find last event that matches query or NULL if not found. 726 const TraceEvent* FindLastOf(const Query& query); 727 728 const std::string& GetThreadName(const TraceEvent::ProcessThreadID& thread); 729 730 private: 731 TraceAnalyzer(); 732 733 bool SetEvents(const std::string& json_events) WARN_UNUSED_RESULT; 734 735 // Read metadata (thread names, etc) from events. 736 void ParseMetadata(); 737 738 std::map<TraceEvent::ProcessThreadID, std::string> thread_names_; 739 std::vector<TraceEvent> raw_events_; 740 bool ignore_metadata_events_; 741 bool allow_assocation_changes_; 742 743 DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer); 744 }; 745 746 // Utility functions for TraceEventVector. 747 748 struct RateStats { 749 double min_us; 750 double max_us; 751 double mean_us; 752 double standard_deviation_us; 753 }; 754 755 struct RateStatsOptions { 756 RateStatsOptions() : trim_min(0u), trim_max(0u) {} 757 // After the times between events are sorted, the number of specified elements 758 // will be trimmed before calculating the RateStats. This is useful in cases 759 // where extreme outliers are tolerable and should not skew the overall 760 // average. 761 size_t trim_min; // Trim this many minimum times. 762 size_t trim_max; // Trim this many maximum times. 763 }; 764 765 // Calculate min/max/mean and standard deviation from the times between 766 // adjacent events. 767 bool GetRateStats(const TraceEventVector& events, 768 RateStats* stats, 769 const RateStatsOptions* options); 770 771 // Starting from |position|, find the first event that matches |query|. 772 // Returns true if found, false otherwise. 773 bool FindFirstOf(const TraceEventVector& events, 774 const Query& query, 775 size_t position, 776 size_t* return_index); 777 778 // Starting from |position|, find the last event that matches |query|. 779 // Returns true if found, false otherwise. 780 bool FindLastOf(const TraceEventVector& events, 781 const Query& query, 782 size_t position, 783 size_t* return_index); 784 785 // Find the closest events to |position| in time that match |query|. 786 // return_second_closest may be NULL. Closeness is determined by comparing 787 // with the event timestamp. 788 // Returns true if found, false otherwise. If both return parameters are 789 // requested, both must be found for a successful result. 790 bool FindClosest(const TraceEventVector& events, 791 const Query& query, 792 size_t position, 793 size_t* return_closest, 794 size_t* return_second_closest); 795 796 // Count matches, inclusive of |begin_position|, exclusive of |end_position|. 797 size_t CountMatches(const TraceEventVector& events, 798 const Query& query, 799 size_t begin_position, 800 size_t end_position); 801 802 // Count all matches. 803 static inline size_t CountMatches(const TraceEventVector& events, 804 const Query& query) { 805 return CountMatches(events, query, 0u, events.size()); 806 } 807 808 } // namespace trace_analyzer 809 810 #endif // BASE_TEST_TRACE_EVENT_ANALYZER_H_ 811