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