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::debug::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 <map> 80 81 #include "base/debug/trace_event.h" 82 #include "base/memory/ref_counted.h" 83 84 namespace base { 85 class Value; 86 } 87 88 namespace trace_analyzer { 89 class QueryNode; 90 91 // trace_analyzer::TraceEvent is a more convenient form of the 92 // base::debug::TraceEvent class to make tracing-based tests easier to write. 93 struct TraceEvent { 94 // ProcessThreadID contains a Process ID and Thread ID. 95 struct ProcessThreadID { 96 ProcessThreadID() : process_id(0), thread_id(0) {} 97 ProcessThreadID(int process_id, int thread_id) 98 : process_id(process_id), thread_id(thread_id) {} 99 bool operator< (const ProcessThreadID& rhs) const { 100 if (process_id != rhs.process_id) 101 return process_id < rhs.process_id; 102 return thread_id < rhs.thread_id; 103 } 104 int process_id; 105 int thread_id; 106 }; 107 108 TraceEvent(); 109 ~TraceEvent(); 110 111 bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT; 112 113 bool operator< (const TraceEvent& rhs) const { 114 return timestamp < rhs.timestamp; 115 } 116 117 bool has_other_event() const { return other_event; } 118 119 // Returns absolute duration in microseconds between this event and other 120 // event. Must have already verified that other_event exists by 121 // Query(EVENT_HAS_OTHER) or by calling has_other_event(). 122 double GetAbsTimeToOtherEvent() const; 123 124 // Return the argument value if it exists and it is a string. 125 bool GetArgAsString(const std::string& name, std::string* arg) const; 126 // Return the argument value if it exists and it is a number. 127 bool GetArgAsNumber(const std::string& name, double* arg) const; 128 129 // Check if argument exists and is string. 130 bool HasStringArg(const std::string& name) const; 131 // Check if argument exists and is number (double, int or bool). 132 bool HasNumberArg(const std::string& name) const; 133 134 // Get known existing arguments as specific types. 135 // Useful when you have already queried the argument with 136 // Query(HAS_NUMBER_ARG) or Query(HAS_STRING_ARG). 137 std::string GetKnownArgAsString(const std::string& name) const; 138 double GetKnownArgAsDouble(const std::string& name) const; 139 int GetKnownArgAsInt(const std::string& name) const; 140 bool GetKnownArgAsBool(const std::string& name) const; 141 142 // Process ID and Thread ID. 143 ProcessThreadID thread; 144 145 // Time since epoch in microseconds. 146 // Stored as double to match its JSON representation. 147 double timestamp; 148 149 double duration; 150 151 char phase; 152 153 std::string category; 154 155 std::string name; 156 157 std::string id; 158 159 // All numbers and bool values from TraceEvent args are cast to double. 160 // bool becomes 1.0 (true) or 0.0 (false). 161 std::map<std::string, double> arg_numbers; 162 163 std::map<std::string, std::string> arg_strings; 164 165 // The other event associated with this event (or NULL). 166 const TraceEvent* other_event; 167 }; 168 169 typedef std::vector<const TraceEvent*> TraceEventVector; 170 171 class Query { 172 public: 173 Query(const Query& query); 174 175 ~Query(); 176 177 //////////////////////////////////////////////////////////////// 178 // Query literal values 179 180 // Compare with the given string. 181 static Query String(const std::string& str); 182 183 // Compare with the given number. 184 static Query Double(double num); 185 static Query Int(int32 num); 186 static Query Uint(uint32 num); 187 188 // Compare with the given bool. 189 static Query Bool(bool boolean); 190 191 // Compare with the given phase. 192 static Query Phase(char phase); 193 194 // Compare with the given string pattern. Only works with == and != operators. 195 // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*") 196 static Query Pattern(const std::string& pattern); 197 198 //////////////////////////////////////////////////////////////// 199 // Query event members 200 201 static Query EventPid() { return Query(EVENT_PID); } 202 203 static Query EventTid() { return Query(EVENT_TID); } 204 205 // Return the timestamp of the event in microseconds since epoch. 206 static Query EventTime() { return Query(EVENT_TIME); } 207 208 // Return the absolute time between event and other event in microseconds. 209 // Only works if Query::EventHasOther() == true. 210 static Query EventDuration() { return Query(EVENT_DURATION); } 211 212 // Return the duration of a COMPLETE event. 213 static Query EventCompleteDuration() { 214 return Query(EVENT_COMPLETE_DURATION); 215 } 216 217 static Query EventPhase() { return Query(EVENT_PHASE); } 218 219 static Query EventCategory() { return Query(EVENT_CATEGORY); } 220 221 static Query EventName() { return Query(EVENT_NAME); } 222 223 static Query EventId() { return Query(EVENT_ID); } 224 225 static Query EventPidIs(int process_id) { 226 return Query(EVENT_PID) == Query::Int(process_id); 227 } 228 229 static Query EventTidIs(int thread_id) { 230 return Query(EVENT_TID) == Query::Int(thread_id); 231 } 232 233 static Query EventThreadIs(const TraceEvent::ProcessThreadID& thread) { 234 return EventPidIs(thread.process_id) && EventTidIs(thread.thread_id); 235 } 236 237 static Query EventTimeIs(double timestamp) { 238 return Query(EVENT_TIME) == Query::Double(timestamp); 239 } 240 241 static Query EventDurationIs(double duration) { 242 return Query(EVENT_DURATION) == Query::Double(duration); 243 } 244 245 static Query EventPhaseIs(char phase) { 246 return Query(EVENT_PHASE) == Query::Phase(phase); 247 } 248 249 static Query EventCategoryIs(const std::string& category) { 250 return Query(EVENT_CATEGORY) == Query::String(category); 251 } 252 253 static Query EventNameIs(const std::string& name) { 254 return Query(EVENT_NAME) == Query::String(name); 255 } 256 257 static Query EventIdIs(const std::string& id) { 258 return Query(EVENT_ID) == Query::String(id); 259 } 260 261 // Evaluates to true if arg exists and is a string. 262 static Query EventHasStringArg(const std::string& arg_name) { 263 return Query(EVENT_HAS_STRING_ARG, arg_name); 264 } 265 266 // Evaluates to true if arg exists and is a number. 267 // Number arguments include types double, int and bool. 268 static Query EventHasNumberArg(const std::string& arg_name) { 269 return Query(EVENT_HAS_NUMBER_ARG, arg_name); 270 } 271 272 // Evaluates to arg value (string or number). 273 static Query EventArg(const std::string& arg_name) { 274 return Query(EVENT_ARG, arg_name); 275 } 276 277 // Return true if associated event exists. 278 static Query EventHasOther() { return Query(EVENT_HAS_OTHER); } 279 280 // Access the associated other_event's members: 281 282 static Query OtherPid() { return Query(OTHER_PID); } 283 284 static Query OtherTid() { return Query(OTHER_TID); } 285 286 static Query OtherTime() { return Query(OTHER_TIME); } 287 288 static Query OtherPhase() { return Query(OTHER_PHASE); } 289 290 static Query OtherCategory() { return Query(OTHER_CATEGORY); } 291 292 static Query OtherName() { return Query(OTHER_NAME); } 293 294 static Query OtherId() { return Query(OTHER_ID); } 295 296 static Query OtherPidIs(int process_id) { 297 return Query(OTHER_PID) == Query::Int(process_id); 298 } 299 300 static Query OtherTidIs(int thread_id) { 301 return Query(OTHER_TID) == Query::Int(thread_id); 302 } 303 304 static Query OtherThreadIs(const TraceEvent::ProcessThreadID& thread) { 305 return OtherPidIs(thread.process_id) && OtherTidIs(thread.thread_id); 306 } 307 308 static Query OtherTimeIs(double timestamp) { 309 return Query(OTHER_TIME) == Query::Double(timestamp); 310 } 311 312 static Query OtherPhaseIs(char phase) { 313 return Query(OTHER_PHASE) == Query::Phase(phase); 314 } 315 316 static Query OtherCategoryIs(const std::string& category) { 317 return Query(OTHER_CATEGORY) == Query::String(category); 318 } 319 320 static Query OtherNameIs(const std::string& name) { 321 return Query(OTHER_NAME) == Query::String(name); 322 } 323 324 static Query OtherIdIs(const std::string& id) { 325 return Query(OTHER_ID) == Query::String(id); 326 } 327 328 // Evaluates to true if arg exists and is a string. 329 static Query OtherHasStringArg(const std::string& arg_name) { 330 return Query(OTHER_HAS_STRING_ARG, arg_name); 331 } 332 333 // Evaluates to true if arg exists and is a number. 334 // Number arguments include types double, int and bool. 335 static Query OtherHasNumberArg(const std::string& arg_name) { 336 return Query(OTHER_HAS_NUMBER_ARG, arg_name); 337 } 338 339 // Evaluates to arg value (string or number). 340 static Query OtherArg(const std::string& arg_name) { 341 return Query(OTHER_ARG, arg_name); 342 } 343 344 //////////////////////////////////////////////////////////////// 345 // Common queries: 346 347 // Find BEGIN events that have a corresponding END event. 348 static Query MatchBeginWithEnd() { 349 return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN)) && 350 Query(EVENT_HAS_OTHER); 351 } 352 353 // Find COMPLETE events. 354 static Query MatchComplete() { 355 return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_COMPLETE)); 356 } 357 358 // Find ASYNC_BEGIN events that have a corresponding ASYNC_END event. 359 static Query MatchAsyncBeginWithNext() { 360 return (Query(EVENT_PHASE) == 361 Query::Phase(TRACE_EVENT_PHASE_ASYNC_BEGIN)) && 362 Query(EVENT_HAS_OTHER); 363 } 364 365 // Find BEGIN events of given |name| which also have associated END events. 366 static Query MatchBeginName(const std::string& name) { 367 return (Query(EVENT_NAME) == Query(name)) && MatchBeginWithEnd(); 368 } 369 370 // Find COMPLETE events of given |name|. 371 static Query MatchCompleteName(const std::string& name) { 372 return (Query(EVENT_NAME) == Query(name)) && MatchComplete(); 373 } 374 375 // Match given Process ID and Thread ID. 376 static Query MatchThread(const TraceEvent::ProcessThreadID& thread) { 377 return (Query(EVENT_PID) == Query::Int(thread.process_id)) && 378 (Query(EVENT_TID) == Query::Int(thread.thread_id)); 379 } 380 381 // Match event pair that spans multiple threads. 382 static Query MatchCrossThread() { 383 return (Query(EVENT_PID) != Query(OTHER_PID)) || 384 (Query(EVENT_TID) != Query(OTHER_TID)); 385 } 386 387 //////////////////////////////////////////////////////////////// 388 // Operators: 389 390 // Boolean operators: 391 Query operator==(const Query& rhs) const; 392 Query operator!=(const Query& rhs) const; 393 Query operator< (const Query& rhs) const; 394 Query operator<=(const Query& rhs) const; 395 Query operator> (const Query& rhs) const; 396 Query operator>=(const Query& rhs) const; 397 Query operator&&(const Query& rhs) const; 398 Query operator||(const Query& rhs) const; 399 Query operator!() const; 400 401 // Arithmetic operators: 402 // Following operators are applied to double arguments: 403 Query operator+(const Query& rhs) const; 404 Query operator-(const Query& rhs) const; 405 Query operator*(const Query& rhs) const; 406 Query operator/(const Query& rhs) const; 407 Query operator-() const; 408 // Mod operates on int64 args (doubles are casted to int64 beforehand): 409 Query operator%(const Query& rhs) const; 410 411 // Return true if the given event matches this query tree. 412 // This is a recursive method that walks the query tree. 413 bool Evaluate(const TraceEvent& event) const; 414 415 private: 416 enum TraceEventMember { 417 EVENT_INVALID, 418 EVENT_PID, 419 EVENT_TID, 420 EVENT_TIME, 421 EVENT_DURATION, 422 EVENT_COMPLETE_DURATION, 423 EVENT_PHASE, 424 EVENT_CATEGORY, 425 EVENT_NAME, 426 EVENT_ID, 427 EVENT_HAS_STRING_ARG, 428 EVENT_HAS_NUMBER_ARG, 429 EVENT_ARG, 430 EVENT_HAS_OTHER, 431 OTHER_PID, 432 OTHER_TID, 433 OTHER_TIME, 434 OTHER_PHASE, 435 OTHER_CATEGORY, 436 OTHER_NAME, 437 OTHER_ID, 438 OTHER_HAS_STRING_ARG, 439 OTHER_HAS_NUMBER_ARG, 440 OTHER_ARG, 441 }; 442 443 enum Operator { 444 OP_INVALID, 445 // Boolean operators: 446 OP_EQ, 447 OP_NE, 448 OP_LT, 449 OP_LE, 450 OP_GT, 451 OP_GE, 452 OP_AND, 453 OP_OR, 454 OP_NOT, 455 // Arithmetic operators: 456 OP_ADD, 457 OP_SUB, 458 OP_MUL, 459 OP_DIV, 460 OP_MOD, 461 OP_NEGATE 462 }; 463 464 enum QueryType { 465 QUERY_BOOLEAN_OPERATOR, 466 QUERY_ARITHMETIC_OPERATOR, 467 QUERY_EVENT_MEMBER, 468 QUERY_NUMBER, 469 QUERY_STRING 470 }; 471 472 // Compare with the given member. 473 explicit Query(TraceEventMember member); 474 475 // Compare with the given member argument value. 476 Query(TraceEventMember member, const std::string& arg_name); 477 478 // Compare with the given string. 479 explicit Query(const std::string& str); 480 481 // Compare with the given number. 482 explicit Query(double num); 483 484 // Construct a boolean Query that returns (left <binary_op> right). 485 Query(const Query& left, const Query& right, Operator binary_op); 486 487 // Construct a boolean Query that returns (<binary_op> left). 488 Query(const Query& left, Operator unary_op); 489 490 // Try to compare left_ against right_ based on operator_. 491 // If either left or right does not convert to double, false is returned. 492 // Otherwise, true is returned and |result| is set to the comparison result. 493 bool CompareAsDouble(const TraceEvent& event, bool* result) const; 494 495 // Try to compare left_ against right_ based on operator_. 496 // If either left or right does not convert to string, false is returned. 497 // Otherwise, true is returned and |result| is set to the comparison result. 498 bool CompareAsString(const TraceEvent& event, bool* result) const; 499 500 // Attempt to convert this Query to a double. On success, true is returned 501 // and the double value is stored in |num|. 502 bool GetAsDouble(const TraceEvent& event, double* num) const; 503 504 // Attempt to convert this Query to a string. On success, true is returned 505 // and the string value is stored in |str|. 506 bool GetAsString(const TraceEvent& event, std::string* str) const; 507 508 // Evaluate this Query as an arithmetic operator on left_ and right_. 509 bool EvaluateArithmeticOperator(const TraceEvent& event, 510 double* num) const; 511 512 // For QUERY_EVENT_MEMBER Query: attempt to get the double value of the Query. 513 bool GetMemberValueAsDouble(const TraceEvent& event, double* num) const; 514 515 // For QUERY_EVENT_MEMBER Query: attempt to get the string value of the Query. 516 bool GetMemberValueAsString(const TraceEvent& event, std::string* num) const; 517 518 // Does this Query represent a value? 519 bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; } 520 521 bool is_unary_operator() const { 522 return operator_ == OP_NOT || operator_ == OP_NEGATE; 523 } 524 525 bool is_comparison_operator() const { 526 return operator_ != OP_INVALID && operator_ < OP_AND; 527 } 528 529 const Query& left() const; 530 const Query& right() const; 531 532 QueryType type_; 533 Operator operator_; 534 scoped_refptr<QueryNode> left_; 535 scoped_refptr<QueryNode> right_; 536 TraceEventMember member_; 537 double number_; 538 std::string string_; 539 bool is_pattern_; 540 }; 541 542 // Implementation detail: 543 // QueryNode allows Query to store a ref-counted query tree. 544 class QueryNode : public base::RefCounted<QueryNode> { 545 public: 546 explicit QueryNode(const Query& query); 547 const Query& query() const { return query_; } 548 549 private: 550 friend class base::RefCounted<QueryNode>; 551 ~QueryNode(); 552 553 Query query_; 554 }; 555 556 // TraceAnalyzer helps tests search for trace events. 557 class TraceAnalyzer { 558 public: 559 ~TraceAnalyzer(); 560 561 // Use trace events from JSON string generated by tracing API. 562 // Returns non-NULL if the JSON is successfully parsed. 563 static TraceAnalyzer* Create(const std::string& json_events) 564 WARN_UNUSED_RESULT; 565 566 void SetIgnoreMetadataEvents(bool ignore) { ignore_metadata_events_ = true; } 567 568 // Associate BEGIN and END events with each other. This allows Query(OTHER_*) 569 // to access the associated event and enables Query(EVENT_DURATION). 570 // An end event will match the most recent begin event with the same name, 571 // category, process ID and thread ID. This matches what is shown in 572 // about:tracing. After association, the BEGIN event will point to the 573 // matching END event, but the END event will not point to the BEGIN event. 574 void AssociateBeginEndEvents(); 575 576 // Associate ASYNC_BEGIN, ASYNC_STEP and ASYNC_END events with each other. 577 // An ASYNC_END event will match the most recent ASYNC_BEGIN or ASYNC_STEP 578 // event with the same name, category, and ID. This creates a singly linked 579 // list of ASYNC_BEGIN->ASYNC_STEP...->ASYNC_END. 580 void AssociateAsyncBeginEndEvents(); 581 582 // AssociateEvents can be used to customize event associations by setting the 583 // other_event member of TraceEvent. This should be used to associate two 584 // INSTANT events. 585 // 586 // The assumptions are: 587 // - |first| events occur before |second| events. 588 // - the closest matching |second| event is the correct match. 589 // 590 // |first| - Eligible |first| events match this query. 591 // |second| - Eligible |second| events match this query. 592 // |match| - This query is run on the |first| event. The OTHER_* EventMember 593 // queries will point to an eligible |second| event. The query 594 // should evaluate to true if the |first|/|second| pair is a match. 595 // 596 // When a match is found, the pair will be associated by having the first 597 // event's other_event member point to the other. AssociateEvents does not 598 // clear previous associations, so it is possible to associate multiple pairs 599 // of events by calling AssociateEvents more than once with different queries. 600 // 601 // NOTE: AssociateEvents will overwrite existing other_event associations if 602 // the queries pass for events that already had a previous association. 603 // 604 // After calling any Find* method, it is not allowed to call AssociateEvents 605 // again. 606 void AssociateEvents(const Query& first, 607 const Query& second, 608 const Query& match); 609 610 // For each event, copy its arguments to the other_event argument map. If 611 // argument name already exists, it will not be overwritten. 612 void MergeAssociatedEventArgs(); 613 614 // Find all events that match query and replace output vector. 615 size_t FindEvents(const Query& query, TraceEventVector* output); 616 617 // Find first event that matches query or NULL if not found. 618 const TraceEvent* FindFirstOf(const Query& query); 619 620 // Find last event that matches query or NULL if not found. 621 const TraceEvent* FindLastOf(const Query& query); 622 623 const std::string& GetThreadName(const TraceEvent::ProcessThreadID& thread); 624 625 private: 626 TraceAnalyzer(); 627 628 bool SetEvents(const std::string& json_events) WARN_UNUSED_RESULT; 629 630 // Read metadata (thread names, etc) from events. 631 void ParseMetadata(); 632 633 std::map<TraceEvent::ProcessThreadID, std::string> thread_names_; 634 std::vector<TraceEvent> raw_events_; 635 bool ignore_metadata_events_; 636 bool allow_assocation_changes_; 637 638 DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer); 639 }; 640 641 // Utility functions for TraceEventVector. 642 643 struct RateStats { 644 double min_us; 645 double max_us; 646 double mean_us; 647 double standard_deviation_us; 648 }; 649 650 struct RateStatsOptions { 651 RateStatsOptions() : trim_min(0u), trim_max(0u) {} 652 // After the times between events are sorted, the number of specified elements 653 // will be trimmed before calculating the RateStats. This is useful in cases 654 // where extreme outliers are tolerable and should not skew the overall 655 // average. 656 size_t trim_min; // Trim this many minimum times. 657 size_t trim_max; // Trim this many maximum times. 658 }; 659 660 // Calculate min/max/mean and standard deviation from the times between 661 // adjacent events. 662 bool GetRateStats(const TraceEventVector& events, 663 RateStats* stats, 664 const RateStatsOptions* options); 665 666 // Starting from |position|, find the first event that matches |query|. 667 // Returns true if found, false otherwise. 668 bool FindFirstOf(const TraceEventVector& events, 669 const Query& query, 670 size_t position, 671 size_t* return_index); 672 673 // Starting from |position|, find the last event that matches |query|. 674 // Returns true if found, false otherwise. 675 bool FindLastOf(const TraceEventVector& events, 676 const Query& query, 677 size_t position, 678 size_t* return_index); 679 680 // Find the closest events to |position| in time that match |query|. 681 // return_second_closest may be NULL. Closeness is determined by comparing 682 // with the event timestamp. 683 // Returns true if found, false otherwise. If both return parameters are 684 // requested, both must be found for a successful result. 685 bool FindClosest(const TraceEventVector& events, 686 const Query& query, 687 size_t position, 688 size_t* return_closest, 689 size_t* return_second_closest); 690 691 // Count matches, inclusive of |begin_position|, exclusive of |end_position|. 692 size_t CountMatches(const TraceEventVector& events, 693 const Query& query, 694 size_t begin_position, 695 size_t end_position); 696 697 // Count all matches. 698 static inline size_t CountMatches(const TraceEventVector& events, 699 const Query& query) { 700 return CountMatches(events, query, 0u, events.size()); 701 } 702 703 } // namespace trace_analyzer 704 705 #endif // BASE_TEST_TRACE_EVENT_ANALYZER_H_ 706