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..b97ad131c009952d153ac6c3de7f37ccb6ae6fb2 |
--- /dev/null |
+++ b/base/debug/trace_event_test_utils.h |
@@ -0,0 +1,228 @@ |
+// 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. |
+ |
+#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 { |
+ |
+namespace trace { |
+ |
+class QueryNode; |
+ |
+// Pass these values to Query to compare with the corresponding member of a |
+// TraceEvent. |
+enum TraceEventMember { |
+ EVENT_INVALID=0, |
+ 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 (BEGIN for END or END for BEGIN). |
+ EVENT_HAS_OTHER, |
+ // Use these to access the associated BEGIN/END event's members: |
+ OTHER_PID, |
+ OTHER_TID, |
+ OTHER_TIME, |
+ OTHER_PHASE, |
+ OTHER_HAS_ARG, |
+ OTHER_ARG |
+}; |
+ |
+// Use Query with TraceAnalyzer to search for specific events. |
+// Queries can be combined using boolean and comparison operators. |
+// For example: |
+// Query q = (Query(EVENT_NAME) == "my_event" && |
+// Query(OTHER_EXISTS) && |
+// Query(EVENT_DURATION) > 1000000.0/60.0); |
+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) { *this = Query(std::string(str)); } |
+ // Compare with the given number. |
+ Query(double num); |
+ Query(float num) { *this = Query(static_cast<double>(num)); } |
+ Query(int num) { *this = Query(static_cast<double>(num)); } |
+ Query(uint32 num) { *this = Query(static_cast<double>(num)); } |
+ Query(bool boolean) { *this = Query(static_cast<double>(boolean ? 1 : 0)); } |
+ Query(TraceEventPhase phase) { *this = Query(static_cast<double>(phase)); } |
+ ~Query(); |
+ |
+ // Compare with the given string pattern. Only works with == and != operators. |
+ 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)); |
+ } |
+ |
+ 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; |
+ |
+ // Return true if the given event matches this query tree. |
+ bool Evaluate(const TestTraceEvent& event) const; |
+ |
+ private: |
+ enum Operator { |
+ OP_NONE=0, |
+ OP_EQ, |
+ OP_NE, |
+ OP_LT, |
+ OP_LE, |
+ OP_GT, |
+ OP_GE, |
+ OP_AND, |
+ OP_OR, |
+ OP_NOT |
+ }; |
+ |
+ enum QueryType { |
+ QUERY_Operator, |
+ QUERY_EventMember, |
+ QUERY_Number, |
+ QUERY_String |
+ }; |
+ |
+ Query(const Query& left, const Query& right, Operator binary_op); |
+ Query(const Query& left, Operator unary_op); |
+ |
+ bool CompareAsDouble(const TestTraceEvent& event, bool* result) const; |
+ bool CompareAsString(const TestTraceEvent& event, bool* result) const; |
+ bool GetAsDouble(const TestTraceEvent& event, double* num) const; |
+ bool GetAsString(const TestTraceEvent& event, std::string* str) const; |
+ TraceValue GetMemberValue(const TestTraceEvent& event) const; |
+ bool is_value() const { return type_ != QUERY_Operator; } |
+ bool is_unary_operator() const { |
+ return type_ == QUERY_Operator && operator_ == OP_NOT; |
+ } |
+ |
+ 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. |
+// It will grow to provide trace querying capabilities as new use cases are |
+// encountered. |
+class TraceAnalyzer { |
+ public: |
+ typedef std::vector<base::debug::TestTraceEvent> EventVector; |
+ typedef std::vector<base::debug::TestTraceEvent*> EventPtrVector; |
+ typedef std::vector<const base::debug::TestTraceEvent*> ConstEventPtrVector; |
+ typedef std::map<base::debug::TestTraceEvent::PidTid, |
+ EventPtrVector> EventPtrTree; |
+ |
+ 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); |
+ |
+ const EventVector& events() { return raw_events_; } |
+ |
+ const std::string& GetThreadName(const base::debug::TestTraceEvent::PidTid& |
+ pid_tid); |
+ |
+ // Find all events that match query: |
+ 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: |
+ // After collecting all events, this will collapse BEGIN/END pairs and |
+ // create a tree for stacked BEGIN/END pairs, separated by thread id. For |
+ // BEGIN/END pairs that span multiple pids or tids, the collapsed event will |
+ // be placed in the map under default key PidTid() (pid=0, tid=0). |
+ void AssociateAllEvents(); |
+ void AssociateEvents(EventPtrVector& events_input, |
+ EventPtrVector& orphans_output); |
+ |
+ 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_ |