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