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

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

Issue 7866026: Added trace query code and wired tracing through BrowserProxy so tests can run traces. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 9 years, 3 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_test_utils.h ('k') | base/debug/trace_event_unittest.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 #include <algorithm>
6
7 #include "base/debug/trace_event_test_utils.h"
8
9 namespace base {
10 namespace debug {
11
12 namespace trace {
13
14 QueryNode::QueryNode(const Query& query) : query_(query) {
15 }
16
17 QueryNode::~QueryNode() {
18 }
19
20 Query::Query(TraceEventMember member)
21 : type_(QUERY_EventMember),
22 operator_(OP_NONE),
23 member_(member),
24 number_(0),
25 is_pattern_(false) {
26 }
27
28 Query::Query(TraceEventMember member, const std::string& arg_name)
29 : type_(QUERY_EventMember),
30 operator_(OP_NONE),
31 member_(member),
32 number_(0),
33 string_(arg_name),
34 is_pattern_(false) {
35 }
36
37 Query::Query(const std::string& str)
38 : type_(QUERY_String),
39 operator_(OP_NONE),
40 member_(EVENT_INVALID),
41 number_(0),
42 string_(str),
43 is_pattern_(false) {
44 }
45
46 Query::Query(double num)
47 : type_(QUERY_Number),
48 operator_(OP_NONE),
49 member_(EVENT_INVALID),
50 number_(num),
51 is_pattern_(false) {
52 }
53
54 Query::~Query() {
55 }
56
57 // static
58 Query Query::Pattern(const std::string& pattern) {
59 Query query(pattern);
60 query.is_pattern_ = true;
61 return query;
62 }
63
64 bool Query::Evaluate(const TestTraceEvent& event) const {
65 // First check for values that can convert to bool.
66
67 // double is true if != 0:
68 double bool_value = 0.0;
69 bool is_bool = GetAsDouble(event, &bool_value);
70 if (is_bool)
71 return (bool_value != 0.0);
72
73 // string is true if it exists:
74 std::string str_value;
75 bool is_str = GetAsString(event, &str_value);
76 if (is_str)
77 return !str_value.empty();
78
79 DCHECK(type_ == QUERY_Operator)
80 << "Invalid query: missing boolean expression";
81 DCHECK(left_.get() && (right_.get() || is_unary_operator()));
82
83 if (operator_ < OP_AND) {
84 DCHECK(left().is_value() && right().is_value())
85 << "Invalid query: comparison operator used between event member and "
86 "value.";
87 bool compare_result = false;
88 if (CompareAsDouble(event, &compare_result))
89 return compare_result;
90 else if (CompareAsString(event, &compare_result))
91 return compare_result;
92 } else {
93 switch (operator_) {
94 case OP_AND:
95 return left().Evaluate(event) && right().Evaluate(event);
96 case OP_OR:
97 return left().Evaluate(event) || right().Evaluate(event);
98 case OP_NOT:
99 return !left().Evaluate(event);
100 default:
101 NOTREACHED();
102 }
103 }
104
105 NOTREACHED();
106 return false;
107 }
108
109 bool Query::CompareAsDouble(const TestTraceEvent& event, bool* result) const {
110 double lhs, rhs;
111 if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
112 return false;
113 switch (operator_) {
114 case OP_EQ:
115 *result = (lhs == rhs);
116 return true;
117 case OP_NE:
118 *result = (lhs != rhs);
119 return true;
120 case OP_LT:
121 *result = (lhs < rhs);
122 return true;
123 case OP_LE:
124 *result = (lhs <= rhs);
125 return true;
126 case OP_GT:
127 *result = (lhs > rhs);
128 return true;
129 case OP_GE:
130 *result = (lhs >= rhs);
131 return true;
132 default:
133 NOTREACHED();
134 return false;
135 }
136 return true;
137 }
138
139 bool Query::CompareAsString(const TestTraceEvent& event, bool* result) const {
140 std::string lhs, rhs;
141 if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
142 return false;
143 switch (operator_) {
144 case OP_EQ:
145 if (right().is_pattern_)
146 *result = MatchPattern(lhs, rhs);
147 else if (left().is_pattern_)
148 *result = MatchPattern(rhs, lhs);
149 else
150 *result = (lhs == rhs);
151 return true;
152 case OP_NE:
153 if (right().is_pattern_)
154 *result = !MatchPattern(lhs, rhs);
155 else if (left().is_pattern_)
156 *result = !MatchPattern(rhs, lhs);
157 else
158 *result = (lhs != rhs);
159 return true;
160 case OP_LT:
161 *result = (lhs < rhs);
162 return true;
163 case OP_LE:
164 *result = (lhs <= rhs);
165 return true;
166 case OP_GT:
167 *result = (lhs > rhs);
168 return true;
169 case OP_GE:
170 *result = (lhs >= rhs);
171 return true;
172 default:
173 NOTREACHED();
174 return false;
175 }
176 return true;
177 }
178
179 bool Query::GetAsDouble(const TestTraceEvent& event, double* num) const {
180 TraceValue value;
181 switch (type_) {
182 case QUERY_EventMember:
183 value = GetMemberValue(event);
184 if(value.type() == TraceValue::TRACE_TYPE_DOUBLE) {
185 *num = value.as_double();
186 return true;
187 }
188 return false;
189 case QUERY_Number:
190 *num = number_;
191 return true;
192 default:
193 return false;
194 }
195 }
196
197 bool Query::GetAsString(const TestTraceEvent& event, std::string* str) const {
198 TraceValue value;
199 switch (type_) {
200 case QUERY_EventMember:
201 value = GetMemberValue(event);
202 if(value.is_string()) {
203 *str = value.as_string();
204 return true;
205 }
206 return false;
207 case QUERY_String:
208 *str = string_;
209 return true;
210 default:
211 return false;
212 }
213 }
214
215 TraceValue Query::GetMemberValue(const TestTraceEvent& event) const {
216 DCHECK(type_ == QUERY_EventMember);
217
218 // This could be a request for a member of |event| or a member of |event|'s
219 // associated event. Store the target event in the_event:
220 const TestTraceEvent* the_event = (member_ < OTHER_PID) ?
221 &event : event.associated_event;
222
223 // Request for member of associated event, but there is no associated event.
224 if (!the_event)
225 return TraceValue();
226
227 switch (member_) {
228 case EVENT_PID:
229 case OTHER_PID:
230 return static_cast<double>(the_event->pid_tid.pid);
231 case EVENT_TID:
232 case OTHER_TID:
233 return static_cast<double>(the_event->pid_tid.tid);
234 case EVENT_TIME:
235 case OTHER_TIME:
236 return the_event->timestamp;
237 case EVENT_DURATION:
238 {
239 double duration;
240 if (the_event->GetDuration(&duration))
241 return duration;
242 else
243 return TraceValue();
244 }
245 case EVENT_PHASE:
246 case OTHER_PHASE:
247 return static_cast<double>(the_event->phase);
248 case EVENT_CATEGORY:
249 return the_event->category;
250 case EVENT_NAME:
251 return the_event->name;
252 case EVENT_HAS_ARG:
253 case OTHER_HAS_ARG:
254 // Search for the argument name and return true if found.
255 return static_cast<double>((the_event->arg_strings.find(string_) !=
256 the_event->arg_strings.end()) ||
257 (the_event->arg_numbers.find(string_) !=
258 the_event->arg_numbers.end()) ? 1 : 0);
259 case EVENT_ARG:
260 case OTHER_ARG:
261 {
262 // Search for the argument name and return its value if found.
263
264 std::map<std::string, std::string>::const_iterator str_i =
265 the_event->arg_strings.find(string_);
266 if (str_i != the_event->arg_strings.end())
267 return str_i->second;
268
269 std::map<std::string, double>::const_iterator num_i =
270 the_event->arg_numbers.find(string_);
271 if (num_i != the_event->arg_numbers.end())
272 return num_i->second;
273
274 return TraceValue();
275 }
276 case EVENT_HAS_OTHER:
277 {
278 // return 1.0 (true) if the associated event exists
279 double result = event.associated_event ? 1.0 : 0.0;
280 return result;
281 }
282 default:
283 NOTREACHED();
284 return TraceValue();
285 }
286 }
287
288 const Query& Query::left() const {
289 return left_->query();
290 }
291
292 const Query& Query::right() const {
293 return right_->query();
294 }
295
296 Query Query::operator==(const Query& rhs) const {
297 return Query(*this, rhs, OP_EQ);
298 }
299
300 Query Query::operator!=(const Query& rhs) const {
301 return Query(*this, rhs, OP_NE);
302 }
303
304 Query Query::operator<(const Query& rhs) const {
305 return Query(*this, rhs, OP_LT);
306 }
307
308 Query Query::operator<=(const Query& rhs) const {
309 return Query(*this, rhs, OP_LE);
310 }
311
312 Query Query::operator>(const Query& rhs) const {
313 return Query(*this, rhs, OP_GT);
314 }
315
316 Query Query::operator>=(const Query& rhs) const {
317 return Query(*this, rhs, OP_GE);
318 }
319
320 Query Query::operator&&(const Query& rhs) const {
321 return Query(*this, rhs, OP_AND);
322 }
323
324 Query Query::operator||(const Query& rhs) const {
325 return Query(*this, rhs, OP_OR);
326 }
327
328 Query Query::operator!() const {
329 return Query(*this, OP_NOT);
330 }
331
332 Query::Query(const Query& left, const Query& right, Operator binary_op)
333 : type_(QUERY_Operator),
334 operator_(binary_op),
335 left_(new QueryNode(left)),
336 right_(new QueryNode(right)),
337 member_(EVENT_INVALID),
338 number_(0) {
339 }
340
341 Query::Query(const Query& left, Operator unary_op)
342 : type_(QUERY_Operator),
343 operator_(unary_op),
344 left_(new QueryNode(left)),
345 member_(EVENT_INVALID),
346 number_(0) {
347 }
348
349 } // namespace trace
350
351 namespace {
352
353 // Search |events| for |query| and add matches to |output|.
354 size_t FindMatchingEvents(const TraceAnalyzer::EventVector& events,
355 const trace::Query& query,
356 TraceAnalyzer::ConstEventPtrVector* output) {
357 for (size_t i = 0; i < events.size(); ++i) {
358 if (query.Evaluate(events[i]))
359 output->push_back(&events[i]);
360 }
361 return output->size();
362 }
363
364 // < operator for TestTraceEvent pointers.
365 bool CompareTestTraceEventPtr(const TestTraceEvent* lhs,
366 const TestTraceEvent* rhs) {
367 return lhs->timestamp < rhs->timestamp;
368 }
369
370 } // namespace
371
372 TraceAnalyzer::TraceAnalyzer() {
373 }
374
375 TraceAnalyzer::TraceAnalyzer(const std::string& json_events) {
376 SetEvents(json_events);
377 }
378
379 TraceAnalyzer::TraceAnalyzer(const EventVector& events) {
380 SetEvents(events);
381 }
382
383 TraceAnalyzer::~TraceAnalyzer() {
384 }
385
386 void TraceAnalyzer::SetEvents(const std::string& json_events) {
387 TestTraceEvent::ParseEventsFromJson(json_events, &raw_events_);
388 AssociateAllEvents();
389 }
390
391 void TraceAnalyzer::SetEvents(const EventVector& events) {
392 raw_events_ = events;
393 AssociateAllEvents();
394 }
395
396 const std::string& TraceAnalyzer::GetThreadName(
397 const base::debug::TestTraceEvent::PidTid& pid_tid) {
398 // If pid_tid is not found, just add and return empty string.
399 return thread_names_[pid_tid];
400 }
401
402 size_t TraceAnalyzer::FindEvents(const trace::Query& query,
403 ConstEventPtrVector* output) const {
404 return FindMatchingEvents(raw_events_, query, output);
405 }
406
407 const base::debug::TestTraceEvent* TraceAnalyzer::FindEvent(
408 const trace::Query& query) const {
409 ConstEventPtrVector output;
410 if (FindEvents(query, &output) > 0)
411 return output.front();
412 return NULL;
413 }
414
415 void TraceAnalyzer::AssociateAllEvents() {
416 EventPtrTree threaded_events;
417
418 // Divide events into their respective threads.
419 for (size_t i = 0; i < raw_events_.size(); ++i)
420 threaded_events[raw_events_[i].pid_tid].push_back(&raw_events_[i]);
421
422 // For each thread, find associated events.
423 EventPtrVector orphans;
424 EventPtrTree::iterator thread_i = threaded_events.begin();
425 for (; thread_i != threaded_events.end(); ++thread_i)
426 AssociateEvents(thread_i->second, orphans);
427
428 // The BEGIN/END events in orphans had no associated events. They could be
429 // cross thread BEGIN/END pairs, or they could be fragments from the start or
430 // end of the trace.
431 // Determine if any orphans are cross-thread begin/end pairs.
432
433 // Sort, because raw events are not in order across threads.
434 std::sort(orphans.begin(), orphans.end(), CompareTestTraceEventPtr);
435
436 // Find associations between BEGIN/END events that span multiple threads:
437 EventPtrVector final_orphans;
438 AssociateEvents(orphans, final_orphans);
439
440 // final_orphans contains likely fragments from the start/end of the trace.
441 }
442
443 void TraceAnalyzer::AssociateEvents(EventPtrVector& events_input,
444 EventPtrVector& orphans_output) {
445 // Search for matching BEGIN/END pairs. When a matching END is found, it is
446 // merged with the BEGIN event to create a single DURATION event.
447 std::vector<TestTraceEvent*> event_stack;
448 for (size_t input_i = 0; input_i < events_input.size(); ++input_i) {
449
450 TestTraceEvent& this_event = *events_input[input_i];
451
452 if (this_event.phase == TRACE_EVENT_PHASE_BEGIN) {
453 event_stack.push_back(&this_event);
454 } else if (this_event.phase == TRACE_EVENT_PHASE_END) {
455 // Search stack for matching begin, starting from top (end).
456 bool found = false;
457 for (int si = static_cast<int>(event_stack.size()) - 1; si >= 0; --si) {
458 TestTraceEvent& begin_event = *event_stack[si];
459 if (begin_event.name == this_event.name &&
460 begin_event.category == this_event.category) {
461 // Found a matching begin/end pair.
462 // Set event association:
463 begin_event.SetAssociatedEvent(&this_event);
464 // Erase the matching begin event index from the stack.
465 event_stack.erase(event_stack.begin() + si);
466 found = true;
467 break;
468 }
469 }
470 if (!found) {
471 // END without matching BEGIN, add it to orphans.
472 orphans_output.push_back(&this_event);
473 }
474 } else if (this_event.phase == TRACE_EVENT_PHASE_METADATA) {
475 // Check for thread name metadata.
476 if (this_event.name == "thread_name") {
477 std::map<std::string, std::string>::const_iterator string_i =
478 this_event.arg_strings.find("name");
479 if (string_i != this_event.arg_strings.end())
480 thread_names_[this_event.pid_tid] = string_i->second;
481 }
482 }
483 }
484
485 for (size_t si = 0; si < event_stack.size(); ++si) {
486 // BEGIN without matching END, add it to orphans.
487 orphans_output.push_back(event_stack[si]);
488 }
489 }
490
491 } // namespace debug
492 } // namespace base
493
OLDNEW
« no previous file with comments | « base/debug/trace_event_test_utils.h ('k') | base/debug/trace_event_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698