Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: base/debug/trace_event_test_utils.h

Issue 7981004: add classes trace_analyzer::Query and TraceAnalyzer to make it easy to search through trace data (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: moved TestTraceEvent Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
nduca 2011/10/11 20:33:37 trace_event_analyzer.h move tests of the analyzer
jbates 2011/10/12 22:35:20 Done.
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.
nduca 2011/10/11 20:33:37 Advertise the namespace that these are all in? I h
jbates 2011/10/12 22:35:20 Done.
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);
nduca 2011/10/11 20:33:37 What happens if it fails to parse? Maybe a TraceAn
jbates 2011/10/12 22:35:20 This should be okay, because the parse would only
10 // ConstEventPtrVector events;
nduca 2011/10/11 20:33:37 A blurb explaining the basic idea of trace analysi
jbates 2011/10/12 22:35:20 Done.
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,
nduca 2011/10/11 20:33:37 Recapping our verbal discussion, I think should ta
jbates 2011/10/12 22:35:20 Sounds good. On second look though, the trace_even
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);
nduca 2011/10/11 20:33:37 This trace wont' even parse in the trace_event_vie
jbates 2011/10/12 22:35:20 Fixed the example to use TRACE_EVENT_INSTANT, whic
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);
nduca 2011/10/11 20:33:37 Based on the first example, I was hoping we'd see
jbates 2011/10/12 22:35:20 You're right, it should have been there... Done.
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 <map>
43
44 #include "base/debug/trace_event.h"
45
46 namespace base {
47 class Value;
48
49 namespace debug {
50
51 namespace trace {
52 class QueryNode;
53 }
54
55 // TestTraceEvent is a more convenient form of the TraceEvent class to make
56 // tracing-based tests easier to write.
57 struct TestTraceEvent {
nduca 2011/10/11 20:33:37 I'm confused about base::trace vs base::debug::tra
jbates 2011/10/12 22:35:20 I've been thinking it would be great to move traci
58 // PidTid contains a Process ID and Thread ID.
59 struct PidTid {
60 PidTid() : pid(0), tid(0) {}
61 PidTid(int pid, int tid) : pid(pid), tid(tid) {}
62 bool operator< (PidTid rhs) const {
63 if (pid != rhs.pid)
64 return pid < rhs.pid;
65 return tid < rhs.tid;
66 }
67 int pid;
68 int tid;
69 };
70
71 TestTraceEvent();
72 TestTraceEvent(const base::Value* event_value);
73 ~TestTraceEvent();
74
75 // Convert JSON string to array of TestTraceEvent.
76 // |output| is appended with the parsed events.
77 static bool ParseEventsFromJson(const std::string& json,
nduca 2011/10/11 20:33:37 Makes more sense on traceanalyzer?
jbates 2011/10/12 22:35:20 This is only dependent on TestTraceEvent, so I thi
78 std::vector<TestTraceEvent>* output);
79
80 bool operator< (const TestTraceEvent& rhs) const {
81 return timestamp < rhs.timestamp;
82 }
83
84 // Returns duration if it's available.
nduca 2011/10/11 20:33:37 Add a bool has_other_event() const; Modify commen
jbates 2011/10/12 22:35:20 Done.
85 bool GetDuration(double* duration) const;
86
87 // Return the argument value if it exists.
88 bool IsArg(const std::string& name) const;
nduca 2011/10/11 20:33:37 HasArg
jbates 2011/10/12 22:35:20 Removed it - it wasn't used anywhere :)
89 // Return the argument value if it exists and it is a string.
90 bool GetArgAsString(const std::string& name, std::string* arg) const;
91 // Return the argument value if it exists and it is a number.
92 bool GetArgAsNumber(const std::string& name, double* arg) const;
93
94 // Called by TraceAnalyzer to associate this event with another event.
nduca 2011/10/11 20:33:37 Use friending so that this isn't visible?
jbates 2011/10/12 22:35:20 Also removed, it was unnecessary.
95 void set_other_event(const TestTraceEvent* event) {
96 other_event = event;
97 }
98
99 // Process ID and Thread ID.
nduca 2011/10/11 20:33:37 Are these really supposed to be public? Makes me a
jbates 2011/10/12 22:35:20 This is for tests, so I think it's best to keep it
100 PidTid pid_tid;
101 // Time since epoch in microseconds.
102 // Stored as double to match its JSON representation.
103 double timestamp;
104 TraceEventPhase phase;
105 std::string category;
106 std::string name;
107 // All numbers and bool values from TraceEvent args are cast to double.
108 // bool becomes 1.0 (true) or 0.0 (false).
109 std::map<std::string, double> arg_numbers;
110 std::map<std::string, std::string> arg_strings;
111 // The other event associated with this event (or NULL).
112 const TestTraceEvent* other_event;
113 };
114
115 // By using the trace namespace, tests can use short terms like "Query".
116 namespace trace {
117
118 // Pass these values to Query to compare with the corresponding member of a
119 // TestTraceEvent.
120 enum TraceEventMember {
121 EVENT_INVALID,
122 // Use these to access the event members:
123 EVENT_PID,
124 EVENT_TID,
125 // Return the timestamp of the event in microseconds since epoch.
126 EVENT_TIME,
127 // Return the duration of an event in seconds.
128 // Only works for events with associated BEGIN/END: Query(OTHER_EXISTS).
129 EVENT_DURATION,
130 EVENT_PHASE,
131 EVENT_CATEGORY,
132 EVENT_NAME,
133 EVENT_HAS_ARG,
134 EVENT_ARG,
135 // Return true if associated event exists.
136 // (Typically BEGIN for END or END for BEGIN).
137 EVENT_HAS_OTHER,
138 // Use these to access the associated event's members:
139 OTHER_PID,
140 OTHER_TID,
141 OTHER_TIME,
142 OTHER_PHASE,
143 OTHER_CATEGORY,
144 OTHER_NAME,
145 OTHER_HAS_ARG,
146 OTHER_ARG
147 };
148
149 class Query {
150 public:
151 // Compare with the given member.
152 Query(TraceEventMember member);
153
154 // Compare with the given member argument value.
155 Query(TraceEventMember member, const std::string& arg_name);
156
157 // Compare with the given string.
158 Query(const std::string& str);
159 Query(const char* str);
160
161 // Compare with the given number.
162 Query(double num);
163 Query(float num);
164 Query(int num);
165 Query(uint32 num);
166
167 // Compare with the given bool.
168 Query(bool boolean);
169
170 // Compare with the given phase.
171 Query(TraceEventPhase phase);
172
173 Query(const Query& query);
174
175 ~Query();
176
177 // Compare with the given string pattern. Only works with == and != operators.
178 // Example: Query(EVENT_NAME) == Query::Pattern("bla_*")
179 static Query Pattern(const std::string& pattern);
180
181 // Common queries:
182
183 // Find BEGIN events that have a corresponding END event.
184 static Query MatchBeginWithEnd() {
185 return (Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN) &&
186 Query(EVENT_HAS_OTHER);
187 }
188
189 // Find END events that have a corresponding BEGIN event.
190 static Query MatchEndWithBegin() {
191 return (Query(EVENT_PHASE) == TRACE_EVENT_PHASE_END) &&
192 Query(EVENT_HAS_OTHER);
193 }
194
195 // Find BEGIN events of given |name| which also have associated END events.
196 static Query MatchBeginName(const std::string& name) {
197 return (Query(EVENT_NAME) == name) && MatchBeginWithEnd();
198 }
199
200 // Match given Process ID and Thread ID.
201 static Query MatchPidTid(base::debug::TestTraceEvent::PidTid pid_tid) {
202 return (Query(EVENT_PID) == pid_tid.pid) &&
203 (Query(EVENT_TID) == pid_tid.tid);
204 }
205
206 // Match BEGIN/END event pair that spans multiple threads.
207 static Query MatchCrossPidTid() {
208 return (Query(EVENT_PID) != Query(OTHER_PID)) ||
209 (Query(EVENT_TID) != Query(OTHER_TID));
210 }
211
212 // Boolean operators:
213 Query operator==(const Query& rhs) const;
214 Query operator!=(const Query& rhs) const;
215 Query operator< (const Query& rhs) const;
216 Query operator<=(const Query& rhs) const;
217 Query operator> (const Query& rhs) const;
218 Query operator>=(const Query& rhs) const;
219 Query operator&&(const Query& rhs) const;
220 Query operator||(const Query& rhs) const;
221 Query operator! () const;
222
223 // Arithmetic operators:
224 Query operator+(const Query& rhs) const;
225 Query operator-(const Query& rhs) const;
226 Query operator*(const Query& rhs) const;
227 Query operator/(const Query& rhs) const;
228 Query operator%(const Query& rhs) const;
229 Query operator-() const;
230
231 // Return true if the given event matches this query tree.
232 // This is a recursive method that walks the query tree.
233 bool Evaluate(const TestTraceEvent& event) const;
234
235 private:
236 enum Operator {
237 OP_INVALID,
238 // Boolean operators:
239 OP_EQ,
240 OP_NE,
241 OP_LT,
242 OP_LE,
243 OP_GT,
244 OP_GE,
245 OP_AND,
246 OP_OR,
247 OP_NOT,
248 // Arithmetic operators:
249 OP_ADD,
250 OP_SUB,
251 OP_MUL,
252 OP_DIV,
253 OP_MOD,
254 OP_NEGATE
255 };
256
257 enum QueryType {
258 QUERY_BOOLEAN_OPERATOR,
259 QUERY_ARITHMETIC_OPERATOR,
260 QUERY_EVENT_MEMBER,
261 QUERY_NUMBER,
262 QUERY_STRING
263 };
264
265 // Construct a boolean Query that returns (left <binary_op> right).
266 Query(const Query& left, const Query& right, Operator binary_op);
267
268 // Construct a boolean Query that returns (<binary_op> left).
269 Query(const Query& left, Operator unary_op);
270
271 // Try to compare left_ against right_ based on operator_.
272 // If either left or right does not convert to double, false is returned.
273 // Otherwise, true is returned and |result| is set to the comparison result.
274 bool CompareAsDouble(const TestTraceEvent& event, bool* result) const;
275
276 // Try to compare left_ against right_ based on operator_.
277 // If either left or right does not convert to string, false is returned.
278 // Otherwise, true is returned and |result| is set to the comparison result.
279 bool CompareAsString(const TestTraceEvent& event, bool* result) const;
280
281 // Attempt to convert this Query to a double. On success, true is returned
282 // and the double value is stored in |num|.
283 bool GetAsDouble(const TestTraceEvent& event, double* num) const;
284
285 // Attempt to convert this Query to a string. On success, true is returned
286 // and the string value is stored in |str|.
287 bool GetAsString(const TestTraceEvent& event, std::string* str) const;
288
289 // Evaluate this Query as an arithmetic operator on left_ and right_.
290 bool EvaluateArithmeticOperator(const TestTraceEvent& event,
291 double* num) const;
292
293 // For QUERY_EVENT_MEMBER Query: attempt to get the value of the Query.
294 // The TraceValue will either be TRACE_TYPE_DOUBLE, TRACE_TYPE_STRING,
295 // or if requested member does not exist, it will be TRACE_TYPE_UNDEFINED.
296 TraceValue GetMemberValue(const TestTraceEvent& event) const;
297
298 // Does this Query represent a value?
299 bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
300
301 bool is_unary_operator() const {
302 return operator_ == OP_NOT || operator_ == OP_NEGATE;
303 }
304
305 const Query& left() const;
306 const Query& right() const;
307
308 QueryType type_;
309 Operator operator_;
310 scoped_refptr<QueryNode> left_;
311 scoped_refptr<QueryNode> right_;
312 TraceEventMember member_;
313 double number_;
314 std::string string_;
315 bool is_pattern_;
316 };
317
318 // QueryNode allows Query to store a ref-counted query tree.
319 class QueryNode : public RefCounted<QueryNode> {
320 public:
321 QueryNode(const Query& query);
322 const Query& query() const { return query_; }
323
324 private:
325 friend class RefCounted<QueryNode>;
326 ~QueryNode();
327
328 Query query_;
329 };
330
331 } // namespace trace
332
333 // TraceAnalyzer is designed to make tracing-based tests easier to write.
334 class TraceAnalyzer {
335 public:
336 typedef std::vector<base::debug::TestTraceEvent> EventVector;
337 typedef std::vector<const base::debug::TestTraceEvent*> ConstEventPtrVector;
338
339 TraceAnalyzer();
340 TraceAnalyzer(const std::string& json_events);
341 TraceAnalyzer(const EventVector& events);
342 ~TraceAnalyzer();
343
344 // Replace all events with |json_events|.
345 void SetEvents(const std::string& json_events);
nduca 2011/10/11 20:33:37 Why this rather than creating another analyzer?
jbates 2011/10/12 22:35:20 The code is about the same either way - may as wel
346 // Replace all events with |events|.
347 void SetEvents(const EventVector& events);
348
349 // SetEvents calls this internally to match up typical begin/end pairs of
350 // events. This allows Query(OTHER_*) to access the associated event and
351 // enables Query(EVENT_DURATION).
352 // By default, an end event will match the most recent begin event with the
353 // same name, category, process ID and thread ID.
354 void SetDefaultAssociations();
nduca 2011/10/11 20:33:37 Confused what this does. Does an end-user writing
jbates 2011/10/12 22:35:20 For now I think it makes sense to keep it availabl
355
356 // Clear existing event associations.
357 void ClearAssociations();
nduca 2011/10/11 20:33:37 Same here... what does this do? Is the idea here t
jbates 2011/10/12 22:35:20 Correct -- AssociateEvents can be called multiple
358
359 // By default, matching begin and end events are associated with each other as
360 // described in SetDefaultAssociations.
361 // AssociateEvents can be used to customize begin/end event associations.
362 // The only assumption is that end events occur after begin events.
363 //
364 // |begin| - Eligible begin events match this query.
365 // |end| - Eligible end events match this query.
366 // |match| - This query is run on the begin event. The OTHER event members
367 // will point to an eligible end event. The query should evaluate to
368 // true if the begin/end pair is a match.
369 //
370 // When a match is found, the pair will be associated by having their
371 // other_event member point to each other. Non-matching events are left with
372 // their existing assocations, so you may also want to call ClearAssociations.
373 void AssociateEvents(const trace::Query& begin,
374 const trace::Query& end,
375 const trace::Query& match);
376
nduca 2011/10/11 20:33:37 If we had B/E only work on threads, always using
jbates 2011/10/12 22:35:20 It might, but as we discussed, I'd like to start s
377 const EventVector& events() { return raw_events_; }
378
379 const std::string& GetThreadName(const base::debug::TestTraceEvent::PidTid&
380 pid_tid);
381
382 // Find all events that match query and replace output vector.
383 size_t FindEvents(const trace::Query& query,
384 ConstEventPtrVector* output) const;
385
386 // Helper method: find first event that matches query
387 const base::debug::TestTraceEvent* FindEvent(
388 const trace::Query& query) const;
389
390 private:
391 // Read metadata (thread names, etc) from events.
392 void ParseMetadata();
393
394 std::map<base::debug::TestTraceEvent::PidTid, std::string> thread_names_;
395 EventVector raw_events_;
396 };
397
398 } // namespace debug
399 } // namespace base
400
401 #endif // BASE_DEBUG_TRACE_EVENT_TEST_UTILS_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698