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

Side by Side Diff: base/test/trace_event_analyzer.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: reduced constructor overloading 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
« no previous file with comments | « base/debug/trace_event.cc ('k') | base/test/trace_event_analyzer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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_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 // During construction, TraceAnalyzer::SetDefaultAssociations is called to
33 // associate all matching begin/end pairs similar to how they are shown in
34 // about:tracing.
35 //
36 // EXAMPLE 1: Find events named "my_event".
37 //
38 // analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events);
39 //
40 // EXAMPLE 2: Find begin events named "my_event" with duration > 1 second.
41 //
42 // Query q = (Query(EVENT_NAME) == "my_event" &&
43 // Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN &&
44 // Query(EVENT_DURATION) > 1000000.0);
Paweł Hajdan Jr. 2011/10/26 08:38:40 nit: Does this example still work, or does it need
jbates 2011/10/26 16:55:49 Done.
45 // analyzer.FindEvents(q, &events);
46 //
47 // EXAMPLE 3: Associating event pairs across threads.
48 //
49 // If the test needs to analyze something that starts and ends on different
50 // threads, the test needs to use INSTANT events. The typical procedure is to
51 // specify the same unique ID as a TRACE_EVENT argument on both the start and
52 // finish INSTANT events. Then use the following procedure to associate those
53 // events.
54 //
55 // Step 1: instrument code with custom begin/end trace events.
56 // [Thread 1 tracing code]
57 // TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3);
58 // [Thread 2 tracing code]
59 // TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3);
60 //
61 // Step 2: associate these custom begin/end pairs.
62 // Query begin(Query(EVENT_NAME) == "timing1_begin");
63 // Query end(Query(EVENT_NAME) == "timing1_end");
64 // Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id"));
65 // analyzer.AssociateEvents(begin, end, match);
66 //
67 // Step 3: search for "timing1_begin" events with existing other event.
68 // Query q = (Query(EVENT_NAME) == "timing1_begin" && Query(EVENT_HAS_OTHER));
69 // analyzer.FindEvents(q, &events);
70 //
71 // Step 4: analyze events, such as checking durations.
72 // for (size_t i = 0; i < events.size(); ++i) {
73 // double duration;
74 // EXPECT_TRUE(events[i].GetDuration(&duration));
75 // EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second.
76 // }
77
78
79 #ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
80 #define BASE_TEST_TRACE_EVENT_ANALYZER_H_
81 #pragma once
82
83 #include <map>
84
85 #include "base/debug/trace_event.h"
86 #include "base/memory/ref_counted_memory.h"
87 #include "base/memory/scoped_ptr.h"
88
89 namespace base {
90 class Value;
91 }
92
93 namespace trace_analyzer {
94 class QueryNode;
95
96 // trace_analyzer::TraceEvent is a more convenient form of the
97 // base::debug::TraceEvent class to make tracing-based tests easier to write.
98 struct BASE_EXPORT TraceEvent {
99 // PidTid contains a Process ID and Thread ID.
100 struct PidTid {
101 PidTid() : pid(0), tid(0) {}
102 PidTid(int pid, int tid) : pid(pid), tid(tid) {}
103 bool operator< (PidTid rhs) const {
104 if (pid != rhs.pid)
105 return pid < rhs.pid;
106 return tid < rhs.tid;
107 }
108 int pid;
109 int tid;
110 };
111
112 TraceEvent();
113 ~TraceEvent();
114
115 bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
116
117 bool operator< (const TraceEvent& rhs) const {
118 return timestamp < rhs.timestamp;
119 }
120
121 bool has_other_event() const { return other_event; }
122
123 // Returns absolute duration in microseconds between this event and other
124 // event. Returns false if has_other_event() is false.
125 bool GetAbsTimeToOtherEvent(double* duration) const;
126
127 // Return the argument value if it exists and it is a string.
128 bool GetArgAsString(const std::string& name, std::string* arg) const;
129 // Return the argument value if it exists and it is a number.
130 bool GetArgAsNumber(const std::string& name, double* arg) const;
131
132 // Process ID and Thread ID.
133 PidTid pid_tid;
134
135 // Time since epoch in microseconds.
136 // Stored as double to match its JSON representation.
137 double timestamp;
138
139 base::debug::TraceEventPhase phase;
140
141 std::string category;
142
143 std::string name;
144
145 // All numbers and bool values from TraceEvent args are cast to double.
146 // bool becomes 1.0 (true) or 0.0 (false).
147 std::map<std::string, double> arg_numbers;
148
149 std::map<std::string, std::string> arg_strings;
150
151 // The other event associated with this event (or NULL).
152 const TraceEvent* other_event;
153 };
154
155 // Pass these values to Query to compare with the corresponding member of a
156 // TraceEvent.
157 enum TraceEventMember {
158 EVENT_INVALID,
159 // Use these to access the event members:
160 EVENT_PID,
161 EVENT_TID,
162 // Return the timestamp of the event in microseconds since epoch.
163 EVENT_TIME,
164 // Return the duration of an event in seconds.
165 // Only works for events with associated BEGIN/END: Query(EVENT_HAS_OTHER).
166 EVENT_DURATION,
167 EVENT_PHASE,
168 EVENT_CATEGORY,
169 EVENT_NAME,
170 EVENT_HAS_ARG,
171 EVENT_ARG,
172 // Return true if associated event exists.
173 // (Typically BEGIN for END or END for BEGIN).
174 EVENT_HAS_OTHER,
175 // Use these to access the associated event's members:
176 OTHER_PID,
177 OTHER_TID,
178 OTHER_TIME,
179 OTHER_PHASE,
180 OTHER_CATEGORY,
181 OTHER_NAME,
182 OTHER_HAS_ARG,
183 OTHER_ARG
184 };
185
186 class BASE_EXPORT Query {
187 public:
188 // Compare with the given member.
189 Query(TraceEventMember member);
190
191 // Compare with the given member argument value.
192 Query(TraceEventMember member, const std::string& arg_name);
193
194 Query(const Query& query);
195
196 ~Query();
197
198 // Compare with the given string.
199 static Query String(const std::string& str);
200
201 // Compare with the given number.
202 static Query Double(double num);
203 static Query Int(int32 num);
Paweł Hajdan Jr. 2011/10/26 08:38:40 nit: Please either change the type to int, or name
204 static Query Uint(uint32 num);
205
206 // Compare with the given bool.
207 static Query Bool(bool boolean);
208
209 // Compare with the given phase.
210 static Query Phase(base::debug::TraceEventPhase phase);
211
212 // Compare with the given string pattern. Only works with == and != operators.
213 // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*")
214 static Query Pattern(const std::string& pattern);
215
216 // Common queries:
217
218 // Find BEGIN events that have a corresponding END event.
219 static Query MatchBeginWithEnd() {
220 return (Query(EVENT_PHASE) ==
221 Query::Phase(base::debug::TRACE_EVENT_PHASE_BEGIN)) &&
222 Query(EVENT_HAS_OTHER);
223 }
224
225 // Find END events that have a corresponding BEGIN event.
226 static Query MatchEndWithBegin2() {
227 return (Query(EVENT_PHASE) == base::debug::TRACE_EVENT_PHASE_END) &&
228 Query(EVENT_HAS_OTHER);
229 }
230
231 // Find BEGIN events of given |name| which also have associated END events.
232 static Query MatchBeginName(const std::string& name) {
233 return (Query(EVENT_NAME) == name) && MatchBeginWithEnd();
234 }
235
236 // Match given Process ID and Thread ID.
237 static Query MatchPidTid(TraceEvent::PidTid pid_tid) {
238 return (Query(EVENT_PID) == Query::Int(pid_tid.pid)) &&
239 (Query(EVENT_TID) == Query::Int(pid_tid.tid));
240 }
241
242 // Match event pair that spans multiple threads.
243 static Query MatchCrossPidTid() {
244 return (Query(EVENT_PID) != Query(OTHER_PID)) ||
245 (Query(EVENT_TID) != Query(OTHER_TID));
246 }
247
248 // Boolean operators:
249 Query operator==(const Query& rhs) const;
250 Query operator!=(const Query& rhs) const;
251 Query operator< (const Query& rhs) const;
252 Query operator<=(const Query& rhs) const;
253 Query operator> (const Query& rhs) const;
254 Query operator>=(const Query& rhs) const;
255 Query operator&&(const Query& rhs) const;
256 Query operator||(const Query& rhs) const;
257 Query operator!() const;
258
259 // Arithmetic operators:
260 // Following operators are applied to double arguments:
261 Query operator+(const Query& rhs) const;
262 Query operator-(const Query& rhs) const;
263 Query operator*(const Query& rhs) const;
264 Query operator/(const Query& rhs) const;
265 Query operator-() const;
266 // Mod operates on int64 args (doubles are casted to int64 beforehand):
267 Query operator%(const Query& rhs) const;
268
269 // Return true if the given event matches this query tree.
270 // This is a recursive method that walks the query tree.
271 bool Evaluate(const TraceEvent& event) const;
272
273 private:
274 enum Operator {
275 OP_INVALID,
276 // Boolean operators:
277 OP_EQ,
278 OP_NE,
279 OP_LT,
280 OP_LE,
281 OP_GT,
282 OP_GE,
283 OP_AND,
284 OP_OR,
285 OP_NOT,
286 // Arithmetic operators:
287 OP_ADD,
288 OP_SUB,
289 OP_MUL,
290 OP_DIV,
291 OP_MOD,
292 OP_NEGATE
293 };
294
295 enum QueryType {
296 QUERY_BOOLEAN_OPERATOR,
297 QUERY_ARITHMETIC_OPERATOR,
298 QUERY_EVENT_MEMBER,
299 QUERY_NUMBER,
300 QUERY_STRING
301 };
302
303 // Compare with the given string.
304 Query(const std::string& str);
305
306 // Compare with the given number.
307 Query(double num);
308
309 // Construct a boolean Query that returns (left <binary_op> right).
310 Query(const Query& left, const Query& right, Operator binary_op);
311
312 // Construct a boolean Query that returns (<binary_op> left).
313 Query(const Query& left, Operator unary_op);
314
315 // Try to compare left_ against right_ based on operator_.
316 // If either left or right does not convert to double, false is returned.
317 // Otherwise, true is returned and |result| is set to the comparison result.
318 bool CompareAsDouble(const TraceEvent& event, bool* result) const;
319
320 // Try to compare left_ against right_ based on operator_.
321 // If either left or right does not convert to string, false is returned.
322 // Otherwise, true is returned and |result| is set to the comparison result.
323 bool CompareAsString(const TraceEvent& event, bool* result) const;
324
325 // Attempt to convert this Query to a double. On success, true is returned
326 // and the double value is stored in |num|.
327 bool GetAsDouble(const TraceEvent& event, double* num) const;
328
329 // Attempt to convert this Query to a string. On success, true is returned
330 // and the string value is stored in |str|.
331 bool GetAsString(const TraceEvent& event, std::string* str) const;
332
333 // Evaluate this Query as an arithmetic operator on left_ and right_.
334 bool EvaluateArithmeticOperator(const TraceEvent& event,
335 double* num) const;
336
337 // For QUERY_EVENT_MEMBER Query: attempt to get the value of the Query.
338 // The TraceValue will either be TRACE_TYPE_DOUBLE, TRACE_TYPE_STRING,
339 // or if requested member does not exist, it will be TRACE_TYPE_UNDEFINED.
340 base::debug::TraceValue GetMemberValue(const TraceEvent& event) const;
341
342 // Does this Query represent a value?
343 bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
344
345 bool is_unary_operator() const {
346 return operator_ == OP_NOT || operator_ == OP_NEGATE;
347 }
348
349 const Query& left() const;
350 const Query& right() const;
351
352 QueryType type_;
353 Operator operator_;
354 scoped_refptr<QueryNode> left_;
355 scoped_refptr<QueryNode> right_;
356 TraceEventMember member_;
357 double number_;
358 std::string string_;
359 bool is_pattern_;
360 };
361
362 // Implementation detail:
363 // QueryNode allows Query to store a ref-counted query tree.
364 class QueryNode : public base::RefCounted<QueryNode> {
365 public:
366 explicit QueryNode(const Query& query);
367 const Query& query() const { return query_; }
368
369 private:
370 friend class base::RefCounted<QueryNode>;
371 ~QueryNode();
372
373 Query query_;
374 };
375
376 // TraceAnalyzer helps tests search for trace events.
377 class BASE_EXPORT TraceAnalyzer {
378 public:
379 typedef std::vector<const TraceEvent*> TraceEventVector;
380
381 ~TraceAnalyzer();
382
383 // Use trace events from JSON string generated by tracing API.
384 // Returns non-NULL if the JSON is successfully parsed.
385 static TraceAnalyzer* Create(const std::string& json_events)
386 WARN_UNUSED_RESULT;
387
388 // Associate BEGIN and END events with each other. This allows Query(OTHER_*)
389 // to access the associated event and enables Query(EVENT_DURATION).
390 // An end event will match the most recent begin event with the same name,
391 // category, process ID and thread ID. This matches what is shown in
392 // about:tracing.
393 void AssociateBeginEndEvents();
394
395 // AssociateEvents can be used to customize event associations by setting the
396 // other_event member of TraceEvent. This should be used to associate two
397 // INSTANT events.
398 //
399 // The assumptions are:
400 // - |first| events occur before |second| events.
401 // - the closest matching |second| event is the correct match.
402 //
403 // |first| - Eligible |first| events match this query.
404 // |second| - Eligible |second| events match this query.
405 // |match| - This query is run on the |first| event. The OTHER_* EventMember
406 // queries will point to an eligible |second| event. The query
407 // should evaluate to true if the |first|/|second| pair is a match.
408 //
409 // When a match is found, the pair will be associated by having their
410 // other_event member point to each other. AssociateEvents does not clear
411 // previous associations, so it is possible to associate multiple pairs of
412 // events by calling AssociateEvents more than once with different queries.
413 //
414 // NOTE: AssociateEvents will overwrite existing other_event associations if
415 // the queries pass for events that already had a previous association.
416 //
417 // After calling FindEvents or FindOneEvent, it is not allowed to call
418 // AssociateEvents again.
419 void AssociateEvents(const Query& first,
420 const Query& second,
421 const Query& match);
422
423 // Find all events that match query and replace output vector.
424 size_t FindEvents(const Query& query, TraceEventVector* output);
425
426 // Helper method: find first event that matches query
427 const TraceEvent* FindOneEvent(const Query& query);
428
429 const std::string& GetThreadName(const TraceEvent::PidTid& pid_tid);
430
431 private:
432 TraceAnalyzer();
433
434 bool SetEvents(const std::string& json_events) WARN_UNUSED_RESULT;
435
436 // Read metadata (thread names, etc) from events.
437 void ParseMetadata();
438
439 std::map<TraceEvent::PidTid, std::string> thread_names_;
440 std::vector<TraceEvent> raw_events_;
441 bool allow_assocation_changes_;
442
443 DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer);
444 };
445
446 } // namespace trace_analyzer
447
448 #endif // BASE_TEST_TRACE_EVENT_ANALYZER_H_
OLDNEW
« no previous file with comments | « base/debug/trace_event.cc ('k') | base/test/trace_event_analyzer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698