| Index: base/debug/trace_event_test_utils.h
|
| diff --git a/base/debug/trace_event_test_utils.h b/base/debug/trace_event_test_utils.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c4efb486d6014040fca70c37b8ae8ed212ffcb9f
|
| --- /dev/null
|
| +++ b/base/debug/trace_event_test_utils.h
|
| @@ -0,0 +1,335 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Use trace::Query with TraceAnalyzer to search for specific trace events.
|
| +// Queries can be combined using boolean and comparison operators.
|
| +//
|
| +// Construct TraceAnalyzer with the json trace string retrieved from TraceLog:
|
| +// TraceAnalyzer analyzer(json_events);
|
| +// ConstEventPtrVector events;
|
| +//
|
| +// To find begin events called "my_event" with duration > 1 second:
|
| +// Query q = (Query(EVENT_NAME) == "my_event" &&
|
| +// Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN &&
|
| +// Query(EVENT_DURATION) > 1000000.0);
|
| +// analyzer.FindEvents(q, &events);
|
| +//
|
| +// By default, only begin/end events on the same thread will ever be associated.
|
| +// If the test needs to analyze events that begin and end on different threads,
|
| +// it can specify custom assocations. The typical procedure is to include a
|
| +// unique ID as one of the TRACE_EVENT arguments that only matches a single
|
| +// begin/end pair across all Chrome processes and threads.
|
| +//
|
| +// For example:
|
| +// [Thread 1]
|
| +// TRACE_EVENT_BEGIN1("test_latency", "timing1", "id", 3);
|
| +// [Later, on Thread 2]
|
| +// TRACE_EVENT_END1("test_latency", "timing1", "id", 3);
|
| +// Then, to associate these begin/end pairs:
|
| +// Query begin(Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN);
|
| +// Query end(Query(EVENT_PHASE) == TRACE_EVENT_PHASE_END);
|
| +// Query match(Query(EVENT_NAME) == Query(OTHER_NAME) &&
|
| +// Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id"));
|
| +// analyzer.AssociateEvents(begin, end, match);
|
| +// Then you can search for "timing1" events and evaluate their durations.
|
| +
|
| +
|
| +#ifndef BASE_DEBUG_TRACE_EVENT_TEST_UTILS_H_
|
| +#define BASE_DEBUG_TRACE_EVENT_TEST_UTILS_H_
|
| +#pragma once
|
| +
|
| +#include "base/debug/trace_event.h"
|
| +
|
| +namespace base {
|
| +namespace debug {
|
| +
|
| +// By using the trace namespace, tests can use short terms like "Query".
|
| +namespace trace {
|
| +
|
| +class QueryNode;
|
| +
|
| +// Pass these values to Query to compare with the corresponding member of a
|
| +// TestTraceEvent.
|
| +enum TraceEventMember {
|
| + EVENT_INVALID,
|
| + // Use these to access the event members:
|
| + EVENT_PID,
|
| + EVENT_TID,
|
| + // Return the timestamp of the event in microseconds since epoch.
|
| + EVENT_TIME,
|
| + // Return the duration of an event in seconds.
|
| + // Only works for events with associated BEGIN/END: Query(OTHER_EXISTS).
|
| + EVENT_DURATION,
|
| + EVENT_PHASE,
|
| + EVENT_CATEGORY,
|
| + EVENT_NAME,
|
| + EVENT_HAS_ARG,
|
| + EVENT_ARG,
|
| + // Return true if associated event exists.
|
| + // (Typically BEGIN for END or END for BEGIN).
|
| + EVENT_HAS_OTHER,
|
| + // Use these to access the associated event's members:
|
| + OTHER_PID,
|
| + OTHER_TID,
|
| + OTHER_TIME,
|
| + OTHER_PHASE,
|
| + OTHER_CATEGORY,
|
| + OTHER_NAME,
|
| + OTHER_HAS_ARG,
|
| + OTHER_ARG
|
| +};
|
| +
|
| +class Query {
|
| + public:
|
| + // Compare with the given member.
|
| + Query(TraceEventMember member);
|
| +
|
| + // Compare with the given member argument value.
|
| + Query(TraceEventMember member, const std::string& arg_name);
|
| +
|
| + // Compare with the given string.
|
| + Query(const std::string& str);
|
| + Query(const char* str);
|
| +
|
| + // Compare with the given number.
|
| + Query(double num);
|
| + Query(float num);
|
| + Query(int num);
|
| + Query(uint32 num);
|
| +
|
| + // Compare with the given bool.
|
| + Query(bool boolean);
|
| +
|
| + // Compare with the given phase.
|
| + Query(TraceEventPhase phase);
|
| +
|
| + Query(const Query& query);
|
| +
|
| + ~Query();
|
| +
|
| + // Compare with the given string pattern. Only works with == and != operators.
|
| + // Example: Query(EVENT_NAME) == Query::Pattern("bla_*")
|
| + static Query Pattern(const std::string& pattern);
|
| +
|
| + // Common queries:
|
| +
|
| + // Find BEGIN events that have a corresponding END event.
|
| + static Query MatchBeginWithEnd() {
|
| + return (Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN) &&
|
| + Query(EVENT_HAS_OTHER);
|
| + }
|
| +
|
| + // Find END events that have a corresponding BEGIN event.
|
| + static Query MatchEndWithBegin() {
|
| + return (Query(EVENT_PHASE) == TRACE_EVENT_PHASE_END) &&
|
| + Query(EVENT_HAS_OTHER);
|
| + }
|
| +
|
| + // Find BEGIN events of given |name| which also have associated END events.
|
| + static Query MatchBeginName(const std::string& name) {
|
| + return (Query(EVENT_NAME) == name) && MatchBeginWithEnd();
|
| + }
|
| +
|
| + // Match given Process ID and Thread ID.
|
| + static Query MatchPidTid(base::debug::TestTraceEvent::PidTid pid_tid) {
|
| + return (Query(EVENT_PID) == pid_tid.pid) &&
|
| + (Query(EVENT_TID) == pid_tid.tid);
|
| + }
|
| +
|
| + // Match BEGIN/END event pair that spans multiple threads.
|
| + static Query MatchCrossPidTid() {
|
| + return (Query(EVENT_PID) != Query(OTHER_PID)) ||
|
| + (Query(EVENT_TID) != Query(OTHER_TID));
|
| + }
|
| +
|
| + // Boolean operators:
|
| + Query operator==(const Query& rhs) const;
|
| + Query operator!=(const Query& rhs) const;
|
| + Query operator< (const Query& rhs) const;
|
| + Query operator<=(const Query& rhs) const;
|
| + Query operator> (const Query& rhs) const;
|
| + Query operator>=(const Query& rhs) const;
|
| + Query operator&&(const Query& rhs) const;
|
| + Query operator||(const Query& rhs) const;
|
| + Query operator! () const;
|
| +
|
| + // Arithmetic operators:
|
| + Query operator+(const Query& rhs) const;
|
| + Query operator-(const Query& rhs) const;
|
| + Query operator*(const Query& rhs) const;
|
| + Query operator/(const Query& rhs) const;
|
| + Query operator%(const Query& rhs) const;
|
| + Query operator-() const;
|
| +
|
| + // Return true if the given event matches this query tree.
|
| + // This is a recursive method that walks the query tree.
|
| + bool Evaluate(const TestTraceEvent& event) const;
|
| +
|
| + private:
|
| + enum Operator {
|
| + OP_INVALID,
|
| + // Boolean operators:
|
| + OP_EQ,
|
| + OP_NE,
|
| + OP_LT,
|
| + OP_LE,
|
| + OP_GT,
|
| + OP_GE,
|
| + OP_AND,
|
| + OP_OR,
|
| + OP_NOT,
|
| + // Arithmetic operators:
|
| + OP_ADD,
|
| + OP_SUB,
|
| + OP_MUL,
|
| + OP_DIV,
|
| + OP_MOD,
|
| + OP_NEGATE
|
| + };
|
| +
|
| + enum QueryType {
|
| + QUERY_BOOLEAN_OPERATOR,
|
| + QUERY_ARITHMETIC_OPERATOR,
|
| + QUERY_EVENT_MEMBER,
|
| + QUERY_NUMBER,
|
| + QUERY_STRING
|
| + };
|
| +
|
| + // Construct a boolean Query that returns (left <binary_op> right).
|
| + Query(const Query& left, const Query& right, Operator binary_op);
|
| +
|
| + // Construct a boolean Query that returns (<binary_op> left).
|
| + Query(const Query& left, Operator unary_op);
|
| +
|
| + // Try to compare left_ against right_ based on operator_.
|
| + // If either left or right does not convert to double, false is returned.
|
| + // Otherwise, true is returned and |result| is set to the comparison result.
|
| + bool CompareAsDouble(const TestTraceEvent& event, bool* result) const;
|
| +
|
| + // Try to compare left_ against right_ based on operator_.
|
| + // If either left or right does not convert to string, false is returned.
|
| + // Otherwise, true is returned and |result| is set to the comparison result.
|
| + bool CompareAsString(const TestTraceEvent& event, bool* result) const;
|
| +
|
| + // Attempt to convert this Query to a double. On success, true is returned
|
| + // and the double value is stored in |num|.
|
| + bool GetAsDouble(const TestTraceEvent& event, double* num) const;
|
| +
|
| + // Attempt to convert this Query to a string. On success, true is returned
|
| + // and the string value is stored in |str|.
|
| + bool GetAsString(const TestTraceEvent& event, std::string* str) const;
|
| +
|
| + // Evaluate this Query as an arithmetic operator on left_ and right_.
|
| + bool EvaluateArithmeticOperator(const TestTraceEvent& event,
|
| + double* num) const;
|
| +
|
| + // For QUERY_EVENT_MEMBER Query: attempt to get the value of the Query.
|
| + // The TraceValue will either be TRACE_TYPE_DOUBLE, TRACE_TYPE_STRING,
|
| + // or if requested member does not exist, it will be TRACE_TYPE_UNDEFINED.
|
| + TraceValue GetMemberValue(const TestTraceEvent& event) const;
|
| +
|
| + // Does this Query represent a value?
|
| + bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
|
| +
|
| + bool is_unary_operator() const {
|
| + return operator_ == OP_NOT || operator_ == OP_NEGATE;
|
| + }
|
| +
|
| + const Query& left() const;
|
| + const Query& right() const;
|
| +
|
| + QueryType type_;
|
| + Operator operator_;
|
| + scoped_refptr<QueryNode> left_;
|
| + scoped_refptr<QueryNode> right_;
|
| + TraceEventMember member_;
|
| + double number_;
|
| + std::string string_;
|
| + bool is_pattern_;
|
| +};
|
| +
|
| +// QueryNode allows Query to store a ref-counted query tree.
|
| +class QueryNode : public RefCounted<QueryNode> {
|
| + public:
|
| + QueryNode(const Query& query);
|
| + const Query& query() const { return query_; }
|
| +
|
| + private:
|
| + friend class RefCounted<QueryNode>;
|
| + ~QueryNode();
|
| +
|
| + Query query_;
|
| +};
|
| +
|
| +} // namespace trace
|
| +
|
| +// TraceAnalyzer is designed to make tracing-based tests easier to write.
|
| +class TraceAnalyzer {
|
| + public:
|
| + typedef std::vector<base::debug::TestTraceEvent> EventVector;
|
| + typedef std::vector<const base::debug::TestTraceEvent*> ConstEventPtrVector;
|
| +
|
| + TraceAnalyzer();
|
| + TraceAnalyzer(const std::string& json_events);
|
| + TraceAnalyzer(const EventVector& events);
|
| + ~TraceAnalyzer();
|
| +
|
| + // Replace all events with |json_events|.
|
| + void SetEvents(const std::string& json_events);
|
| + // Replace all events with |events|.
|
| + void SetEvents(const EventVector& events);
|
| +
|
| + // SetEvents calls this internally to match up typical begin/end pairs of
|
| + // events. This allows Query(OTHER_*) to access the associated event and
|
| + // enables Query(EVENT_DURATION).
|
| + // By default, an end event will match the most recent begin event with the
|
| + // same name, category, process ID and thread ID.
|
| + void SetDefaultAssociations();
|
| +
|
| + // Clear existing event associations.
|
| + void ClearAssociations();
|
| +
|
| + // By default, matching begin and end events are associated with each other as
|
| + // described in SetDefaultAssociations.
|
| + // AssociateEvents can be used to customize begin/end event associations.
|
| + // The only assumption is that end events occur after begin events.
|
| + //
|
| + // |begin| - Eligible begin events match this query.
|
| + // |end| - Eligible end events match this query.
|
| + // |match| - This query is run on the begin event. The OTHER event members
|
| + // will point to an eligible end event. The query should evaluate to
|
| + // true if the begin/end pair is a match.
|
| + //
|
| + // When a match is found, the pair will be associated by having their
|
| + // other_event member point to each other. Non-matching events are left with
|
| + // their existing assocations, so you may also want to call ClearAssociations.
|
| + void AssociateEvents(const trace::Query& begin,
|
| + const trace::Query& end,
|
| + const trace::Query& match);
|
| +
|
| + const EventVector& events() { return raw_events_; }
|
| +
|
| + const std::string& GetThreadName(const base::debug::TestTraceEvent::PidTid&
|
| + pid_tid);
|
| +
|
| + // Find all events that match query and replace output vector.
|
| + size_t FindEvents(const trace::Query& query,
|
| + ConstEventPtrVector* output) const;
|
| +
|
| + // Helper method: find first event that matches query
|
| + const base::debug::TestTraceEvent* FindEvent(
|
| + const trace::Query& query) const;
|
| +
|
| + private:
|
| + // Read metadata (thread names, etc) from events.
|
| + void ParseMetadata();
|
| +
|
| + std::map<base::debug::TestTraceEvent::PidTid, std::string> thread_names_;
|
| + EventVector raw_events_;
|
| +};
|
| +
|
| +} // namespace debug
|
| +} // namespace base
|
| +
|
| +#endif // BASE_DEBUG_TRACE_EVENT_TEST_UTILS_H_
|
|
|