OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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::Query with TraceAnalyzer to search for specific trace events. |
| 6 // Queries can be combined using boolean and comparison operators. |
| 7 // |
| 8 // Construct TraceAnalyzer with the json trace string retrieved from TraceLog: |
| 9 // TraceAnalyzer analyzer(json_events); |
| 10 // ConstEventPtrVector events; |
| 11 // |
| 12 // To find begin events called "my_event" with duration > 1 second: |
| 13 // Query q = (Query(EVENT_NAME) == "my_event" && |
| 14 // Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN && |
| 15 // Query(EVENT_DURATION) > 1000000.0); |
| 16 // analyzer.FindEvents(q, &events); |
| 17 // |
| 18 // By default, only begin/end events on the same thread will ever be associated. |
| 19 // If the test needs to analyze events that begin and end on different threads, |
| 20 // it can specify custom assocations. The typical procedure is to include a |
| 21 // unique ID as one of the TRACE_EVENT arguments that only matches a single |
| 22 // begin/end pair across all Chrome processes and threads. |
| 23 // |
| 24 // For example: |
| 25 // [Thread 1] |
| 26 // TRACE_EVENT_BEGIN1("test_latency", "timing1", "id", 3); |
| 27 // [Later, on Thread 2] |
| 28 // TRACE_EVENT_END1("test_latency", "timing1", "id", 3); |
| 29 // Then, to associate these begin/end pairs: |
| 30 // Query begin(Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN); |
| 31 // Query end(Query(EVENT_PHASE) == TRACE_EVENT_PHASE_END); |
| 32 // Query match(Query(EVENT_NAME) == Query(OTHER_NAME) && |
| 33 // Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id")); |
| 34 // analyzer.AssociateEvents(begin, end, match); |
| 35 // Then you can search for "timing1" events and evaluate their durations. |
| 36 |
| 37 |
| 38 #ifndef BASE_DEBUG_TRACE_EVENT_TEST_UTILS_H_ |
| 39 #define BASE_DEBUG_TRACE_EVENT_TEST_UTILS_H_ |
| 40 #pragma once |
| 41 |
| 42 #include "base/debug/trace_event.h" |
| 43 |
| 44 namespace base { |
| 45 namespace debug { |
| 46 |
| 47 // By using the trace namespace, tests can use short terms like "Query". |
| 48 namespace trace { |
| 49 |
| 50 class QueryNode; |
| 51 |
| 52 // Pass these values to Query to compare with the corresponding member of a |
| 53 // TestTraceEvent. |
| 54 enum TraceEventMember { |
| 55 EVENT_INVALID, |
| 56 // Use these to access the event members: |
| 57 EVENT_PID, |
| 58 EVENT_TID, |
| 59 // Return the timestamp of the event in microseconds since epoch. |
| 60 EVENT_TIME, |
| 61 // Return the duration of an event in seconds. |
| 62 // Only works for events with associated BEGIN/END: Query(OTHER_EXISTS). |
| 63 EVENT_DURATION, |
| 64 EVENT_PHASE, |
| 65 EVENT_CATEGORY, |
| 66 EVENT_NAME, |
| 67 EVENT_HAS_ARG, |
| 68 EVENT_ARG, |
| 69 // Return true if associated event exists. |
| 70 // (Typically BEGIN for END or END for BEGIN). |
| 71 EVENT_HAS_OTHER, |
| 72 // Use these to access the associated event's members: |
| 73 OTHER_PID, |
| 74 OTHER_TID, |
| 75 OTHER_TIME, |
| 76 OTHER_PHASE, |
| 77 OTHER_CATEGORY, |
| 78 OTHER_NAME, |
| 79 OTHER_HAS_ARG, |
| 80 OTHER_ARG |
| 81 }; |
| 82 |
| 83 class Query { |
| 84 public: |
| 85 // Compare with the given member. |
| 86 Query(TraceEventMember member); |
| 87 |
| 88 // Compare with the given member argument value. |
| 89 Query(TraceEventMember member, const std::string& arg_name); |
| 90 |
| 91 // Compare with the given string. |
| 92 Query(const std::string& str); |
| 93 Query(const char* str); |
| 94 |
| 95 // Compare with the given number. |
| 96 Query(double num); |
| 97 Query(float num); |
| 98 Query(int num); |
| 99 Query(uint32 num); |
| 100 |
| 101 // Compare with the given bool. |
| 102 Query(bool boolean); |
| 103 |
| 104 // Compare with the given phase. |
| 105 Query(TraceEventPhase phase); |
| 106 |
| 107 Query(const Query& query); |
| 108 |
| 109 ~Query(); |
| 110 |
| 111 // Compare with the given string pattern. Only works with == and != operators. |
| 112 // Example: Query(EVENT_NAME) == Query::Pattern("bla_*") |
| 113 static Query Pattern(const std::string& pattern); |
| 114 |
| 115 // Common queries: |
| 116 |
| 117 // Find BEGIN events that have a corresponding END event. |
| 118 static Query MatchBeginWithEnd() { |
| 119 return (Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN) && |
| 120 Query(EVENT_HAS_OTHER); |
| 121 } |
| 122 |
| 123 // Find END events that have a corresponding BEGIN event. |
| 124 static Query MatchEndWithBegin() { |
| 125 return (Query(EVENT_PHASE) == TRACE_EVENT_PHASE_END) && |
| 126 Query(EVENT_HAS_OTHER); |
| 127 } |
| 128 |
| 129 // Find BEGIN events of given |name| which also have associated END events. |
| 130 static Query MatchBeginName(const std::string& name) { |
| 131 return (Query(EVENT_NAME) == name) && MatchBeginWithEnd(); |
| 132 } |
| 133 |
| 134 // Match given Process ID and Thread ID. |
| 135 static Query MatchPidTid(base::debug::TestTraceEvent::PidTid pid_tid) { |
| 136 return (Query(EVENT_PID) == pid_tid.pid) && |
| 137 (Query(EVENT_TID) == pid_tid.tid); |
| 138 } |
| 139 |
| 140 // Match BEGIN/END event pair that spans multiple threads. |
| 141 static Query MatchCrossPidTid() { |
| 142 return (Query(EVENT_PID) != Query(OTHER_PID)) || |
| 143 (Query(EVENT_TID) != Query(OTHER_TID)); |
| 144 } |
| 145 |
| 146 // Boolean operators: |
| 147 Query operator==(const Query& rhs) const; |
| 148 Query operator!=(const Query& rhs) const; |
| 149 Query operator< (const Query& rhs) const; |
| 150 Query operator<=(const Query& rhs) const; |
| 151 Query operator> (const Query& rhs) const; |
| 152 Query operator>=(const Query& rhs) const; |
| 153 Query operator&&(const Query& rhs) const; |
| 154 Query operator||(const Query& rhs) const; |
| 155 Query operator! () const; |
| 156 |
| 157 // Arithmetic operators: |
| 158 Query operator+(const Query& rhs) const; |
| 159 Query operator-(const Query& rhs) const; |
| 160 Query operator*(const Query& rhs) const; |
| 161 Query operator/(const Query& rhs) const; |
| 162 Query operator%(const Query& rhs) const; |
| 163 Query operator-() const; |
| 164 |
| 165 // Return true if the given event matches this query tree. |
| 166 // This is a recursive method that walks the query tree. |
| 167 bool Evaluate(const TestTraceEvent& event) const; |
| 168 |
| 169 private: |
| 170 enum Operator { |
| 171 OP_INVALID, |
| 172 // Boolean operators: |
| 173 OP_EQ, |
| 174 OP_NE, |
| 175 OP_LT, |
| 176 OP_LE, |
| 177 OP_GT, |
| 178 OP_GE, |
| 179 OP_AND, |
| 180 OP_OR, |
| 181 OP_NOT, |
| 182 // Arithmetic operators: |
| 183 OP_ADD, |
| 184 OP_SUB, |
| 185 OP_MUL, |
| 186 OP_DIV, |
| 187 OP_MOD, |
| 188 OP_NEGATE |
| 189 }; |
| 190 |
| 191 enum QueryType { |
| 192 QUERY_BOOLEAN_OPERATOR, |
| 193 QUERY_ARITHMETIC_OPERATOR, |
| 194 QUERY_EVENT_MEMBER, |
| 195 QUERY_NUMBER, |
| 196 QUERY_STRING |
| 197 }; |
| 198 |
| 199 // Construct a boolean Query that returns (left <binary_op> right). |
| 200 Query(const Query& left, const Query& right, Operator binary_op); |
| 201 |
| 202 // Construct a boolean Query that returns (<binary_op> left). |
| 203 Query(const Query& left, Operator unary_op); |
| 204 |
| 205 // Try to compare left_ against right_ based on operator_. |
| 206 // If either left or right does not convert to double, false is returned. |
| 207 // Otherwise, true is returned and |result| is set to the comparison result. |
| 208 bool CompareAsDouble(const TestTraceEvent& event, bool* result) const; |
| 209 |
| 210 // Try to compare left_ against right_ based on operator_. |
| 211 // If either left or right does not convert to string, false is returned. |
| 212 // Otherwise, true is returned and |result| is set to the comparison result. |
| 213 bool CompareAsString(const TestTraceEvent& event, bool* result) const; |
| 214 |
| 215 // Attempt to convert this Query to a double. On success, true is returned |
| 216 // and the double value is stored in |num|. |
| 217 bool GetAsDouble(const TestTraceEvent& event, double* num) const; |
| 218 |
| 219 // Attempt to convert this Query to a string. On success, true is returned |
| 220 // and the string value is stored in |str|. |
| 221 bool GetAsString(const TestTraceEvent& event, std::string* str) const; |
| 222 |
| 223 // Evaluate this Query as an arithmetic operator on left_ and right_. |
| 224 bool EvaluateArithmeticOperator(const TestTraceEvent& event, |
| 225 double* num) const; |
| 226 |
| 227 // For QUERY_EVENT_MEMBER Query: attempt to get the value of the Query. |
| 228 // The TraceValue will either be TRACE_TYPE_DOUBLE, TRACE_TYPE_STRING, |
| 229 // or if requested member does not exist, it will be TRACE_TYPE_UNDEFINED. |
| 230 TraceValue GetMemberValue(const TestTraceEvent& event) const; |
| 231 |
| 232 // Does this Query represent a value? |
| 233 bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; } |
| 234 |
| 235 bool is_unary_operator() const { |
| 236 return operator_ == OP_NOT || operator_ == OP_NEGATE; |
| 237 } |
| 238 |
| 239 const Query& left() const; |
| 240 const Query& right() const; |
| 241 |
| 242 QueryType type_; |
| 243 Operator operator_; |
| 244 scoped_refptr<QueryNode> left_; |
| 245 scoped_refptr<QueryNode> right_; |
| 246 TraceEventMember member_; |
| 247 double number_; |
| 248 std::string string_; |
| 249 bool is_pattern_; |
| 250 }; |
| 251 |
| 252 // QueryNode allows Query to store a ref-counted query tree. |
| 253 class QueryNode : public RefCounted<QueryNode> { |
| 254 public: |
| 255 QueryNode(const Query& query); |
| 256 const Query& query() const { return query_; } |
| 257 |
| 258 private: |
| 259 friend class RefCounted<QueryNode>; |
| 260 ~QueryNode(); |
| 261 |
| 262 Query query_; |
| 263 }; |
| 264 |
| 265 } // namespace trace |
| 266 |
| 267 // TraceAnalyzer is designed to make tracing-based tests easier to write. |
| 268 class TraceAnalyzer { |
| 269 public: |
| 270 typedef std::vector<base::debug::TestTraceEvent> EventVector; |
| 271 typedef std::vector<const base::debug::TestTraceEvent*> ConstEventPtrVector; |
| 272 |
| 273 TraceAnalyzer(); |
| 274 TraceAnalyzer(const std::string& json_events); |
| 275 TraceAnalyzer(const EventVector& events); |
| 276 ~TraceAnalyzer(); |
| 277 |
| 278 // Replace all events with |json_events|. |
| 279 void SetEvents(const std::string& json_events); |
| 280 // Replace all events with |events|. |
| 281 void SetEvents(const EventVector& events); |
| 282 |
| 283 // SetEvents calls this internally to match up typical begin/end pairs of |
| 284 // events. This allows Query(OTHER_*) to access the associated event and |
| 285 // enables Query(EVENT_DURATION). |
| 286 // By default, an end event will match the most recent begin event with the |
| 287 // same name, category, process ID and thread ID. |
| 288 void SetDefaultAssociations(); |
| 289 |
| 290 // Clear existing event associations. |
| 291 void ClearAssociations(); |
| 292 |
| 293 // By default, matching begin and end events are associated with each other as |
| 294 // described in SetDefaultAssociations. |
| 295 // AssociateEvents can be used to customize begin/end event associations. |
| 296 // The only assumption is that end events occur after begin events. |
| 297 // |
| 298 // |begin| - Eligible begin events match this query. |
| 299 // |end| - Eligible end events match this query. |
| 300 // |match| - This query is run on the begin event. The OTHER event members |
| 301 // will point to an eligible end event. The query should evaluate to |
| 302 // true if the begin/end pair is a match. |
| 303 // |
| 304 // When a match is found, the pair will be associated by having their |
| 305 // other_event member point to each other. Non-matching events are left with |
| 306 // their existing assocations, so you may also want to call ClearAssociations. |
| 307 void AssociateEvents(const trace::Query& begin, |
| 308 const trace::Query& end, |
| 309 const trace::Query& match); |
| 310 |
| 311 const EventVector& events() { return raw_events_; } |
| 312 |
| 313 const std::string& GetThreadName(const base::debug::TestTraceEvent::PidTid& |
| 314 pid_tid); |
| 315 |
| 316 // Find all events that match query and replace output vector. |
| 317 size_t FindEvents(const trace::Query& query, |
| 318 ConstEventPtrVector* output) const; |
| 319 |
| 320 // Helper method: find first event that matches query |
| 321 const base::debug::TestTraceEvent* FindEvent( |
| 322 const trace::Query& query) const; |
| 323 |
| 324 private: |
| 325 // Read metadata (thread names, etc) from events. |
| 326 void ParseMetadata(); |
| 327 |
| 328 std::map<base::debug::TestTraceEvent::PidTid, std::string> thread_names_; |
| 329 EventVector raw_events_; |
| 330 }; |
| 331 |
| 332 } // namespace debug |
| 333 } // namespace base |
| 334 |
| 335 #endif // BASE_DEBUG_TRACE_EVENT_TEST_UTILS_H_ |
OLD | NEW |