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

Side by Side Diff: base/test/trace_event_analyzer.h

Issue 8418044: add classes trace_analyzer::Query and TraceAnalyzer to improve testing (retry) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month 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) == Query::String("my_event") &&
43 // Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) &&
44 // Query(EVENT_DURATION) > Query::Double(1000000.0));
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) == Query::String("timing1_begin"));
63 // Query end(Query(EVENT_NAME) == Query::String("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) == Query::String("timing1_begin") &&
69 // Query(EVENT_HAS_OTHER));
70 // analyzer.FindEvents(q, &events);
71 //
72 // Step 4: analyze events, such as checking durations.
73 // for (size_t i = 0; i < events.size(); ++i) {
74 // double duration;
75 // EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration));
76 // EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second.
77 // }
78
79
80 #ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
81 #define BASE_TEST_TRACE_EVENT_ANALYZER_H_
82 #pragma once
83
84 #include <map>
85
86 #include "base/debug/trace_event.h"
87 #include "base/memory/ref_counted_memory.h"
88 #include "base/memory/scoped_ptr.h"
89
90 namespace base {
91 class Value;
92 }
93
94 namespace trace_analyzer {
95 class QueryNode;
96
97 // trace_analyzer::TraceEvent is a more convenient form of the
98 // base::debug::TraceEvent class to make tracing-based tests easier to write.
99 struct TraceEvent {
100 // ProcessThreadID contains a Process ID and Thread ID.
101 struct ProcessThreadID {
102 ProcessThreadID() : process_id(0), thread_id(0) {}
103 ProcessThreadID(int process_id, int thread_id)
104 : process_id(process_id), thread_id(thread_id) {}
105 bool operator< (const ProcessThreadID& rhs) const {
106 if (process_id != rhs.process_id)
107 return process_id < rhs.process_id;
108 return thread_id < rhs.thread_id;
109 }
110 int process_id;
111 int thread_id;
112 };
113
114 TraceEvent();
115 ~TraceEvent();
116
117 bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
118
119 bool operator< (const TraceEvent& rhs) const {
120 return timestamp < rhs.timestamp;
121 }
122
123 bool has_other_event() const { return other_event; }
124
125 // Returns absolute duration in microseconds between this event and other
126 // event. Returns false if has_other_event() is false.
127 bool GetAbsTimeToOtherEvent(double* duration) const;
128
129 // Return the argument value if it exists and it is a string.
130 bool GetArgAsString(const std::string& name, std::string* arg) const;
131 // Return the argument value if it exists and it is a number.
132 bool GetArgAsNumber(const std::string& name, double* arg) const;
133
134 // Process ID and Thread ID.
135 ProcessThreadID thread;
136
137 // Time since epoch in microseconds.
138 // Stored as double to match its JSON representation.
139 double timestamp;
140
141 base::debug::TraceEventPhase phase;
142
143 std::string category;
144
145 std::string name;
146
147 // All numbers and bool values from TraceEvent args are cast to double.
148 // bool becomes 1.0 (true) or 0.0 (false).
149 std::map<std::string, double> arg_numbers;
150
151 std::map<std::string, std::string> arg_strings;
152
153 // The other event associated with this event (or NULL).
154 const TraceEvent* other_event;
155 };
156
157 // Pass these values to Query to compare with the corresponding member of a
158 // TraceEvent.
159 enum TraceEventMember {
160 EVENT_INVALID,
161 // Use these to access the event members:
162 EVENT_PID,
163 EVENT_TID,
164 // Return the timestamp of the event in microseconds since epoch.
165 EVENT_TIME,
166 // Return the absolute time between event and other event in microseconds.
167 // Only works for events with associated BEGIN/END: Query(EVENT_HAS_OTHER).
168 EVENT_DURATION,
169 EVENT_PHASE,
170 EVENT_CATEGORY,
171 EVENT_NAME,
172 EVENT_HAS_ARG,
173 EVENT_ARG,
174 // Return true if associated event exists.
175 // (Typically BEGIN for END or END for BEGIN).
176 EVENT_HAS_OTHER,
177 // Use these to access the associated event's members:
178 OTHER_PID,
179 OTHER_TID,
180 OTHER_TIME,
181 OTHER_PHASE,
182 OTHER_CATEGORY,
183 OTHER_NAME,
184 OTHER_HAS_ARG,
185 OTHER_ARG
186 };
187
188 class Query {
189 public:
190 // Compare with the given member.
191 Query(TraceEventMember member);
192
193 // Compare with the given member argument value.
194 Query(TraceEventMember member, const std::string& arg_name);
195
196 Query(const Query& query);
197
198 ~Query();
199
200 // Compare with the given string.
201 static Query String(const std::string& str);
202
203 // Compare with the given number.
204 static Query Double(double num);
205 static Query Int(int32 num);
206 static Query Uint(uint32 num);
207
208 // Compare with the given bool.
209 static Query Bool(bool boolean);
210
211 // Compare with the given phase.
212 static Query Phase(base::debug::TraceEventPhase phase);
213
214 // Compare with the given string pattern. Only works with == and != operators.
215 // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*")
216 static Query Pattern(const std::string& pattern);
217
218 // Common queries:
219
220 // Find BEGIN events that have a corresponding END event.
221 static Query MatchBeginWithEnd() {
222 return (Query(EVENT_PHASE) ==
223 Query::Phase(base::debug::TRACE_EVENT_PHASE_BEGIN)) &&
224 Query(EVENT_HAS_OTHER);
225 }
226
227 // Find BEGIN events of given |name| which also have associated END events.
228 static Query MatchBeginName(const std::string& name) {
229 return (Query(EVENT_NAME) == name) && MatchBeginWithEnd();
230 }
231
232 // Match given Process ID and Thread ID.
233 static Query MatchThread(const TraceEvent::ProcessThreadID& thread) {
234 return (Query(EVENT_PID) == Query::Int(thread.process_id)) &&
235 (Query(EVENT_TID) == Query::Int(thread.thread_id));
236 }
237
238 // Match event pair that spans multiple threads.
239 static Query MatchCrossThread() {
240 return (Query(EVENT_PID) != Query(OTHER_PID)) ||
241 (Query(EVENT_TID) != Query(OTHER_TID));
242 }
243
244 // Boolean operators:
245 Query operator==(const Query& rhs) const;
246 Query operator!=(const Query& rhs) const;
247 Query operator< (const Query& rhs) const;
248 Query operator<=(const Query& rhs) const;
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;
254
255 // Arithmetic operators:
256 // Following operators are applied to double arguments:
257 Query operator+(const Query& rhs) const;
258 Query operator-(const Query& rhs) const;
259 Query operator*(const Query& rhs) const;
260 Query operator/(const Query& rhs) const;
261 Query operator-() const;
262 // Mod operates on int64 args (doubles are casted to int64 beforehand):
263 Query operator%(const Query& rhs) const;
264
265 // Return true if the given event matches this query tree.
266 // This is a recursive method that walks the query tree.
267 bool Evaluate(const TraceEvent& event) const;
268
269 private:
270 enum Operator {
271 OP_INVALID,
272 // Boolean operators:
273 OP_EQ,
274 OP_NE,
275 OP_LT,
276 OP_LE,
277 OP_GT,
278 OP_GE,
279 OP_AND,
280 OP_OR,
281 OP_NOT,
282 // Arithmetic operators:
283 OP_ADD,
284 OP_SUB,
285 OP_MUL,
286 OP_DIV,
287 OP_MOD,
288 OP_NEGATE
289 };
290
291 enum QueryType {
292 QUERY_BOOLEAN_OPERATOR,
293 QUERY_ARITHMETIC_OPERATOR,
294 QUERY_EVENT_MEMBER,
295 QUERY_NUMBER,
296 QUERY_STRING
297 };
298
299 // Compare with the given string.
300 Query(const std::string& str);
301
302 // Compare with the given number.
303 Query(double num);
304
305 // Construct a boolean Query that returns (left <binary_op> right).
306 Query(const Query& left, const Query& right, Operator binary_op);
307
308 // Construct a boolean Query that returns (<binary_op> left).
309 Query(const Query& left, Operator unary_op);
310
311 // Try to compare left_ against right_ based on operator_.
312 // If either left or right does not convert to double, false is returned.
313 // Otherwise, true is returned and |result| is set to the comparison result.
314 bool CompareAsDouble(const TraceEvent& event, bool* result) const;
315
316 // Try to compare left_ against right_ based on operator_.
317 // If either left or right does not convert to string, false is returned.
318 // Otherwise, true is returned and |result| is set to the comparison result.
319 bool CompareAsString(const TraceEvent& event, bool* result) const;
320
321 // Attempt to convert this Query to a double. On success, true is returned
322 // and the double value is stored in |num|.
323 bool GetAsDouble(const TraceEvent& event, double* num) const;
324
325 // Attempt to convert this Query to a string. On success, true is returned
326 // and the string value is stored in |str|.
327 bool GetAsString(const TraceEvent& event, std::string* str) const;
328
329 // Evaluate this Query as an arithmetic operator on left_ and right_.
330 bool EvaluateArithmeticOperator(const TraceEvent& event,
331 double* num) const;
332
333 // For QUERY_EVENT_MEMBER Query: attempt to get the value of the Query.
334 // The TraceValue will either be TRACE_TYPE_DOUBLE, TRACE_TYPE_STRING,
335 // or if requested member does not exist, it will be TRACE_TYPE_UNDEFINED.
336 base::debug::TraceValue GetMemberValue(const TraceEvent& event) const;
337
338 // Does this Query represent a value?
339 bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
340
341 bool is_unary_operator() const {
342 return operator_ == OP_NOT || operator_ == OP_NEGATE;
343 }
344
345 bool is_comparison_operator() const {
346 return operator_ != OP_INVALID && operator_ < OP_AND;
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 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::ProcessThreadID& thread);
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::ProcessThreadID, 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