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

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

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: more 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
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_EVENT_MEMBER),
22 operator_(OP_INVALID),
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_EVENT_MEMBER),
30 operator_(OP_INVALID),
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_INVALID),
40 member_(EVENT_INVALID),
41 number_(0),
42 string_(str),
43 is_pattern_(false) {
44 }
45
46 Query::Query(const char* str) {
47 *this = Query(std::string(str));
48 }
49
50 Query::Query(double num)
51 : type_(QUERY_NUMBER),
52 operator_(OP_INVALID),
53 member_(EVENT_INVALID),
54 number_(num),
55 is_pattern_(false) {
56 }
57
58 Query::Query(float num) {
59 *this = Query(static_cast<double>(num));
60 }
61
62 Query::Query(int num) {
63 *this = Query(static_cast<double>(num));
64 }
65
66 Query::Query(uint32 num) {
67 *this = Query(static_cast<double>(num));
68 }
69
70 Query::Query(bool boolean) {
71 *this = Query(static_cast<double>(boolean ? 1 : 0));
72 }
73
74 Query::Query(TraceEventPhase phase) {
75 *this = Query(static_cast<double>(phase));
76 }
77
78 Query::Query(const Query& query)
79 : type_(query.type_),
80 operator_(query.operator_),
81 left_(query.left_),
82 right_(query.right_),
83 member_(query.member_),
84 number_(query.number_),
85 string_(query.string_),
86 is_pattern_(query.is_pattern_) {
87 }
88
89 Query::~Query() {
90 }
91
92 // static
93 Query Query::Pattern(const std::string& pattern) {
94 Query query(pattern);
95 query.is_pattern_ = true;
96 return query;
97 }
98
99 bool Query::Evaluate(const TestTraceEvent& event) const {
100 // First check for values that can convert to bool.
101
102 // double is true if != 0:
103 double bool_value = 0.0;
104 bool is_bool = GetAsDouble(event, &bool_value);
105 if (is_bool)
106 return (bool_value != 0.0);
107
108 // string is true if it is non-empty:
109 std::string str_value;
110 bool is_str = GetAsString(event, &str_value);
111 if (is_str)
112 return !str_value.empty();
113
114 CHECK(type_ == QUERY_BOOLEAN_OPERATOR)
115 << "Invalid query: missing boolean expression";
116 CHECK(left_.get() && (right_.get() || is_unary_operator()));
117
118 if (operator_ < OP_AND) {
119 CHECK(left().is_value() && right().is_value())
120 << "Invalid query: comparison operator used between event member and "
121 "value.";
122 bool compare_result = false;
123 if (CompareAsDouble(event, &compare_result))
124 return compare_result;
125 else if (CompareAsString(event, &compare_result))
126 return compare_result;
127 return false;
128 } else {
129 switch (operator_) {
130 case OP_AND:
131 return left().Evaluate(event) && right().Evaluate(event);
132 case OP_OR:
133 return left().Evaluate(event) || right().Evaluate(event);
134 case OP_NOT:
135 return !left().Evaluate(event);
136 default:
137 NOTREACHED();
138 }
139 }
140
141 NOTREACHED();
142 return false;
143 }
144
145 bool Query::CompareAsDouble(const TestTraceEvent& event, bool* result) const {
146 double lhs, rhs;
147 if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
148 return false;
149 switch (operator_) {
150 case OP_EQ:
151 *result = (lhs == rhs);
152 return true;
153 case OP_NE:
154 *result = (lhs != rhs);
155 return true;
156 case OP_LT:
157 *result = (lhs < rhs);
158 return true;
159 case OP_LE:
160 *result = (lhs <= rhs);
161 return true;
162 case OP_GT:
163 *result = (lhs > rhs);
164 return true;
165 case OP_GE:
166 *result = (lhs >= rhs);
167 return true;
168 default:
169 NOTREACHED();
170 return false;
171 }
172 return true;
173 }
174
175 bool Query::CompareAsString(const TestTraceEvent& event, bool* result) const {
176 std::string lhs, rhs;
177 if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
178 return false;
179 switch (operator_) {
180 case OP_EQ:
181 if (right().is_pattern_)
182 *result = MatchPattern(lhs, rhs);
183 else if (left().is_pattern_)
184 *result = MatchPattern(rhs, lhs);
185 else
186 *result = (lhs == rhs);
187 return true;
188 case OP_NE:
189 if (right().is_pattern_)
190 *result = !MatchPattern(lhs, rhs);
191 else if (left().is_pattern_)
192 *result = !MatchPattern(rhs, lhs);
193 else
194 *result = (lhs != rhs);
195 return true;
196 case OP_LT:
197 *result = (lhs < rhs);
198 return true;
199 case OP_LE:
200 *result = (lhs <= rhs);
201 return true;
202 case OP_GT:
203 *result = (lhs > rhs);
204 return true;
205 case OP_GE:
206 *result = (lhs >= rhs);
207 return true;
208 default:
209 NOTREACHED();
210 return false;
211 }
212 return true;
213 }
214
215 bool Query::EvaluateArithmeticOperator(const TestTraceEvent& event,
216 double* num) const {
217 CHECK(type_ == QUERY_ARITHMETIC_OPERATOR);
218 CHECK(left_.get() && (right_.get() || is_unary_operator()));
219
220 double lhs = 0, rhs = 0;
221 if (!left().GetAsDouble(event, &lhs))
222 return false;
223 if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
224 return false;
225
226 switch (operator_) {
227 case OP_ADD:
228 *num = lhs + rhs;
229 break;
230 case OP_SUB:
231 *num = lhs - rhs;
232 break;
233 case OP_MUL:
234 *num = lhs * rhs;
235 break;
236 case OP_DIV:
237 *num = lhs / rhs;
238 break;
239 case OP_MOD:
240 *num = static_cast<double>(static_cast<int64>(lhs) %
241 static_cast<int64>(rhs));
242 break;
243 case OP_NEGATE:
244 *num = -lhs;
245 break;
246 default:
247 NOTREACHED();
248 return false;
249 }
250
251 return true;
252 }
253
254 bool Query::GetAsDouble(const TestTraceEvent& event, double* num) const {
255 TraceValue value;
256 switch (type_) {
257 case QUERY_ARITHMETIC_OPERATOR:
258 return EvaluateArithmeticOperator(event, num);
259 case QUERY_EVENT_MEMBER:
260 value = GetMemberValue(event);
261 if(value.type() == TraceValue::TRACE_TYPE_DOUBLE) {
262 *num = value.as_double();
263 return true;
264 }
265 return false;
266 case QUERY_NUMBER:
267 *num = number_;
268 return true;
269 default:
270 return false;
271 }
272 }
273
274 bool Query::GetAsString(const TestTraceEvent& event, std::string* str) const {
275 TraceValue value;
276 switch (type_) {
277 case QUERY_EVENT_MEMBER:
278 value = GetMemberValue(event);
279 if(value.is_string()) {
280 *str = value.as_string();
281 return true;
282 }
283 return false;
284 case QUERY_STRING:
285 *str = string_;
286 return true;
287 default:
288 return false;
289 }
290 }
291
292 TraceValue Query::GetMemberValue(const TestTraceEvent& event) const {
293 CHECK(type_ == QUERY_EVENT_MEMBER);
294
295 // This could be a request for a member of |event| or a member of |event|'s
296 // associated event. Store the target event in the_event:
297 const TestTraceEvent* the_event = (member_ < OTHER_PID) ?
298 &event : event.other_event;
299
300 // Request for member of associated event, but there is no associated event.
301 if (!the_event)
302 return TraceValue();
303
304 switch (member_) {
305 case EVENT_PID:
306 case OTHER_PID:
307 return static_cast<double>(the_event->pid_tid.pid);
308 case EVENT_TID:
309 case OTHER_TID:
310 return static_cast<double>(the_event->pid_tid.tid);
311 case EVENT_TIME:
312 case OTHER_TIME:
313 return the_event->timestamp;
314 case EVENT_DURATION:
315 {
316 double duration;
317 if (the_event->GetDuration(&duration))
318 return duration;
319 else
320 return TraceValue();
321 }
322 case EVENT_PHASE:
323 case OTHER_PHASE:
324 return static_cast<double>(the_event->phase);
325 case EVENT_CATEGORY:
326 case OTHER_CATEGORY:
327 return the_event->category;
328 case EVENT_NAME:
329 case OTHER_NAME:
330 return the_event->name;
331 case EVENT_HAS_ARG:
332 case OTHER_HAS_ARG:
333 // Search for the argument name and return true if found.
334 return static_cast<double>((the_event->arg_strings.find(string_) !=
335 the_event->arg_strings.end()) ||
336 (the_event->arg_numbers.find(string_) !=
337 the_event->arg_numbers.end()) ? 1 : 0);
338 case EVENT_ARG:
339 case OTHER_ARG:
340 {
341 // Search for the argument name and return its value if found.
342
343 std::map<std::string, std::string>::const_iterator str_i =
344 the_event->arg_strings.find(string_);
345 if (str_i != the_event->arg_strings.end())
346 return str_i->second;
347
348 std::map<std::string, double>::const_iterator num_i =
349 the_event->arg_numbers.find(string_);
350 if (num_i != the_event->arg_numbers.end())
351 return num_i->second;
352
353 return TraceValue();
354 }
355 case EVENT_HAS_OTHER:
356 {
357 // return 1.0 (true) if the other event exists
358 double result = event.other_event ? 1.0 : 0.0;
359 return result;
360 }
361 default:
362 NOTREACHED();
363 return TraceValue();
364 }
365 }
366
367 const Query& Query::left() const {
368 return left_->query();
369 }
370
371 const Query& Query::right() const {
372 return right_->query();
373 }
374
375 Query Query::operator==(const Query& rhs) const {
376 return Query(*this, rhs, OP_EQ);
377 }
378
379 Query Query::operator!=(const Query& rhs) const {
380 return Query(*this, rhs, OP_NE);
381 }
382
383 Query Query::operator<(const Query& rhs) const {
384 return Query(*this, rhs, OP_LT);
385 }
386
387 Query Query::operator<=(const Query& rhs) const {
388 return Query(*this, rhs, OP_LE);
389 }
390
391 Query Query::operator>(const Query& rhs) const {
392 return Query(*this, rhs, OP_GT);
393 }
394
395 Query Query::operator>=(const Query& rhs) const {
396 return Query(*this, rhs, OP_GE);
397 }
398
399 Query Query::operator&&(const Query& rhs) const {
400 return Query(*this, rhs, OP_AND);
401 }
402
403 Query Query::operator||(const Query& rhs) const {
404 return Query(*this, rhs, OP_OR);
405 }
406
407 Query Query::operator!() const {
408 return Query(*this, OP_NOT);
409 }
410
411 Query Query::operator+(const Query& rhs) const {
412 return Query(*this, rhs, OP_ADD);
413 }
414
415 Query Query::operator-(const Query& rhs) const {
416 return Query(*this, rhs, OP_SUB);
417 }
418
419 Query Query::operator*(const Query& rhs) const {
420 return Query(*this, rhs, OP_MUL);
421 }
422
423 Query Query::operator/(const Query& rhs) const {
424 return Query(*this, rhs, OP_DIV);
425 }
426
427 Query Query::operator%(const Query& rhs) const {
428 return Query(*this, rhs, OP_MOD);
429 }
430
431 Query Query::operator-() const {
432 return Query(*this, OP_NEGATE);
433 }
434
435
436 Query::Query(const Query& left, const Query& right, Operator binary_op)
437 : operator_(binary_op),
438 left_(new QueryNode(left)),
439 right_(new QueryNode(right)),
440 member_(EVENT_INVALID),
441 number_(0) {
442 type_ = (binary_op < OP_ADD ?
443 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
444 }
445
446 Query::Query(const Query& left, Operator unary_op)
447 : operator_(unary_op),
448 left_(new QueryNode(left)),
449 member_(EVENT_INVALID),
450 number_(0) {
451 type_ = (unary_op < OP_ADD ?
452 QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
453 }
454
455 } // namespace trace
456
457 namespace {
458
459 // Search |events| for |query| and add matches to |output|.
460 size_t FindMatchingEvents(const TraceAnalyzer::EventVector& events,
461 const trace::Query& query,
462 TraceAnalyzer::ConstEventPtrVector* output) {
463 for (size_t i = 0; i < events.size(); ++i) {
464 if (query.Evaluate(events[i]))
465 output->push_back(&events[i]);
466 }
467 return output->size();
468 }
469
470 } // namespace
471
472 TraceAnalyzer::TraceAnalyzer() {
473 }
474
475 TraceAnalyzer::TraceAnalyzer(const std::string& json_events) {
476 SetEvents(json_events);
477 }
478
479 TraceAnalyzer::TraceAnalyzer(const EventVector& events) {
480 SetEvents(events);
481 }
482
483 TraceAnalyzer::~TraceAnalyzer() {
484 }
485
486 void TraceAnalyzer::SetEvents(const std::string& json_events) {
487 TestTraceEvent::ParseEventsFromJson(json_events, &raw_events_);
488 std::stable_sort(raw_events_.begin(), raw_events_.end());
489 ParseMetadata();
490 SetDefaultAssociations();
491 }
492
493 void TraceAnalyzer::SetEvents(const EventVector& events) {
494 raw_events_ = events;
495 std::stable_sort(raw_events_.begin(), raw_events_.end());
496 ParseMetadata();
497 SetDefaultAssociations();
498 }
499
500 void TraceAnalyzer::SetDefaultAssociations() {
501 using namespace base::debug::trace;
502
503 Query begin(Query(EVENT_PHASE) == TRACE_EVENT_PHASE_BEGIN);
504 Query end(Query(EVENT_PHASE) == TRACE_EVENT_PHASE_END);
505 Query match(Query(EVENT_NAME) == Query(OTHER_NAME) &&
506 Query(EVENT_CATEGORY) == Query(OTHER_CATEGORY) &&
507 Query(EVENT_TID) == Query(OTHER_TID) &&
508 Query(EVENT_PID) == Query(OTHER_PID));
509
510 AssociateEvents(begin, end, match);
511 }
512
513 void TraceAnalyzer::ClearAssociations() {
514 for (size_t input_i = 0; input_i < raw_events_.size(); ++input_i)
515 raw_events_[input_i].other_event = NULL;
516 }
517
518 void TraceAnalyzer::AssociateEvents(const trace::Query& begin,
519 const trace::Query& end,
520 const trace::Query& match) {
521 // Search for matching begin/end event pairs. When a matching end is found,
522 // it is associated with the begin event.
523 std::vector<TestTraceEvent*> begin_stack;
524 for (size_t input_i = 0; input_i < raw_events_.size(); ++input_i) {
525
526 TestTraceEvent& this_event = raw_events_[input_i];
527
528 if (begin.Evaluate(this_event)) {
529 begin_stack.push_back(&this_event);
530 } else if (end.Evaluate(this_event)) {
531 // Search stack for matching begin, starting from end.
532 for (int si = static_cast<int>(begin_stack.size()) - 1; si >= 0; --si) {
533 TestTraceEvent& begin_event = *begin_stack[si];
534
535 // Temporarily set other to test against the match query.
536 const TestTraceEvent* other_backup = begin_event.other_event;
537 begin_event.set_other_event(&this_event);
538 if (match.Evaluate(begin_event)) {
539 // Found a matching begin/end pair.
540 // Set event association:
541 this_event.set_other_event(&begin_event);
542 // Erase the matching begin event index from the stack.
543 begin_stack.erase(begin_stack.begin() + si);
544 break;
545 }
546
547 // Not a match, restore original other and continue.
548 begin_event.set_other_event(other_backup);
549 }
550 }
551 }
552 }
553
554 const std::string& TraceAnalyzer::GetThreadName(
555 const base::debug::TestTraceEvent::PidTid& pid_tid) {
556 // If pid_tid is not found, just add and return empty string.
557 return thread_names_[pid_tid];
558 }
559
560 size_t TraceAnalyzer::FindEvents(const trace::Query& query,
561 ConstEventPtrVector* output) const {
562 output->clear();
563 return FindMatchingEvents(raw_events_, query, output);
564 }
565
566 const base::debug::TestTraceEvent* TraceAnalyzer::FindEvent(
567 const trace::Query& query) const {
568 ConstEventPtrVector output;
569 if (FindEvents(query, &output) > 0)
570 return output.front();
571 return NULL;
572 }
573
574 void TraceAnalyzer::ParseMetadata() {
575 for (size_t i = 0; i < raw_events_.size(); ++i) {
576 TestTraceEvent& this_event = raw_events_[i];
577 if (this_event.phase == TRACE_EVENT_PHASE_METADATA) {
578 // Check for thread name metadata.
579 if (this_event.name == "thread_name") {
580 std::map<std::string, std::string>::const_iterator string_i =
581 this_event.arg_strings.find("name");
582 if (string_i != this_event.arg_strings.end())
583 thread_names_[this_event.pid_tid] = string_i->second;
584 }
585 }
586 }
587 }
588
589 } // namespace debug
590 } // namespace base
591
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698