xref: /aosp_15_r20/external/cronet/base/test/trace_event_analyzer.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
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 "base/test/trace_event_analyzer.h"
6 
7 #include <math.h>
8 
9 #include <algorithm>
10 #include <optional>
11 #include <set>
12 
13 #include "base/functional/bind.h"
14 #include "base/json/json_reader.h"
15 #include "base/logging.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/memory/ref_counted_memory.h"
18 #include "base/ranges/algorithm.h"
19 #include "base/run_loop.h"
20 #include "base/strings/pattern.h"
21 #include "base/trace_event/trace_buffer.h"
22 #include "base/trace_event/trace_config.h"
23 #include "base/trace_event/trace_log.h"
24 #include "base/values.h"
25 
26 namespace {
OnTraceDataCollected(base::OnceClosure quit_closure,base::trace_event::TraceResultBuffer * buffer,const scoped_refptr<base::RefCountedString> & json,bool has_more_events)27 void OnTraceDataCollected(base::OnceClosure quit_closure,
28                           base::trace_event::TraceResultBuffer* buffer,
29                           const scoped_refptr<base::RefCountedString>& json,
30                           bool has_more_events) {
31   buffer->AddFragment(json->data());
32   if (!has_more_events)
33     std::move(quit_closure).Run();
34 }
35 }  // namespace
36 
37 namespace trace_analyzer {
38 
39 // TraceEvent
40 
TraceEvent()41 TraceEvent::TraceEvent() : thread(0, 0) {}
42 
43 TraceEvent::TraceEvent(TraceEvent&& other) = default;
44 
45 TraceEvent::~TraceEvent() = default;
46 
47 TraceEvent& TraceEvent::operator=(TraceEvent&& rhs) = default;
48 
SetFromJSON(const base::Value * event_value)49 bool TraceEvent::SetFromJSON(const base::Value* event_value) {
50   if (!event_value->is_dict()) {
51     LOG(ERROR) << "Value must be Type::DICT";
52     return false;
53   }
54 
55   const base::Value::Dict& event_dict = event_value->GetDict();
56   const std::string* maybe_phase = event_dict.FindString("ph");
57   if (!maybe_phase) {
58     LOG(ERROR) << "ph is missing from TraceEvent JSON";
59     return false;
60   }
61 
62   phase = *maybe_phase->data();
63 
64   bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
65   bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
66   bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
67                      phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
68                      phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
69                      phase == TRACE_EVENT_PHASE_MEMORY_DUMP ||
70                      phase == TRACE_EVENT_PHASE_CREATE_OBJECT ||
71                      phase == TRACE_EVENT_PHASE_DELETE_OBJECT ||
72                      phase == TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ||
73                      phase == TRACE_EVENT_PHASE_ASYNC_END ||
74                      phase == TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN ||
75                      phase == TRACE_EVENT_PHASE_NESTABLE_ASYNC_END);
76 
77   if (require_origin) {
78     std::optional<int> maybe_process_id = event_dict.FindInt("pid");
79     if (!maybe_process_id) {
80       LOG(ERROR) << "pid is missing from TraceEvent JSON";
81       return false;
82     }
83     thread.process_id = *maybe_process_id;
84 
85     std::optional<int> maybe_thread_id = event_dict.FindInt("tid");
86     if (!maybe_thread_id) {
87       LOG(ERROR) << "tid is missing from TraceEvent JSON";
88       return false;
89     }
90     thread.thread_id = *maybe_thread_id;
91 
92     std::optional<double> maybe_timestamp = event_dict.FindDouble("ts");
93     if (!maybe_timestamp) {
94       LOG(ERROR) << "ts is missing from TraceEvent JSON";
95       return false;
96     }
97     timestamp = *maybe_timestamp;
98   }
99   if (may_have_duration) {
100     std::optional<double> maybe_duration = event_dict.FindDouble("dur");
101     if (maybe_duration)
102       duration = *maybe_duration;
103   }
104   const std::string* maybe_category = event_dict.FindString("cat");
105   if (!maybe_category) {
106     LOG(ERROR) << "cat is missing from TraceEvent JSON";
107     return false;
108   }
109   category = *maybe_category;
110   const std::string* maybe_name = event_dict.FindString("name");
111   if (!maybe_name) {
112     LOG(ERROR) << "name is missing from TraceEvent JSON";
113     return false;
114   }
115   name = *maybe_name;
116   const base::Value::Dict* maybe_args = event_dict.FindDict("args");
117   if (!maybe_args) {
118     // If argument filter is enabled, the arguments field contains a string
119     // value.
120     const std::string* maybe_stripped_args = event_dict.FindString("args");
121     if (!maybe_stripped_args || *maybe_stripped_args != "__stripped__") {
122       LOG(ERROR) << "args is missing from TraceEvent JSON";
123       return false;
124     }
125   }
126   const base::Value::Dict* maybe_id2 = nullptr;
127   if (require_id) {
128     const std::string* maybe_id = event_dict.FindString("id");
129     maybe_id2 = event_dict.FindDict("id2");
130     if (!maybe_id && !maybe_id2) {
131       LOG(ERROR)
132           << "id/id2 is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
133       return false;
134     }
135     if (maybe_id)
136       id = *maybe_id;
137   }
138 
139   std::optional<double> maybe_thread_duration = event_dict.FindDouble("tdur");
140   if (maybe_thread_duration) {
141     thread_duration = *maybe_thread_duration;
142   }
143   std::optional<double> maybe_thread_timestamp = event_dict.FindDouble("tts");
144   if (maybe_thread_timestamp) {
145     thread_timestamp = *maybe_thread_timestamp;
146   }
147   const std::string* maybe_scope = event_dict.FindString("scope");
148   if (maybe_scope) {
149     scope = *maybe_scope;
150   }
151   const std::string* maybe_bind_id = event_dict.FindString("bind_id");
152   if (maybe_bind_id) {
153     bind_id = *maybe_bind_id;
154   }
155   std::optional<bool> maybe_flow_out = event_dict.FindBool("flow_out");
156   if (maybe_flow_out) {
157     flow_out = *maybe_flow_out;
158   }
159   std::optional<bool> maybe_flow_in = event_dict.FindBool("flow_in");
160   if (maybe_flow_in) {
161     flow_in = *maybe_flow_in;
162   }
163 
164   if (maybe_id2) {
165     const std::string* maybe_global_id2 = maybe_id2->FindString("global");
166     if (maybe_global_id2) {
167       global_id2 = *maybe_global_id2;
168     }
169     const std::string* maybe_local_id2 = maybe_id2->FindString("local");
170     if (maybe_local_id2) {
171       local_id2 = *maybe_local_id2;
172     }
173   }
174 
175   // For each argument, copy the type and create a trace_analyzer::TraceValue.
176   // TODO(crbug.com/1303874): Add BINARY and LIST arg types if needed.
177   if (maybe_args) {
178     for (auto pair : *maybe_args) {
179       switch (pair.second.type()) {
180         case base::Value::Type::STRING:
181           arg_strings[pair.first] = pair.second.GetString();
182           break;
183 
184         case base::Value::Type::INTEGER:
185           arg_numbers[pair.first] = static_cast<double>(pair.second.GetInt());
186           break;
187 
188         case base::Value::Type::BOOLEAN:
189           arg_numbers[pair.first] = pair.second.GetBool() ? 1.0 : 0.0;
190           break;
191 
192         case base::Value::Type::DOUBLE:
193           arg_numbers[pair.first] = pair.second.GetDouble();
194           break;
195 
196         case base::Value::Type::DICT:
197           arg_dicts[pair.first] = pair.second.GetDict().Clone();
198           break;
199 
200         default:
201           break;
202       }
203     }
204   }
205 
206   return true;
207 }
208 
GetAbsTimeToOtherEvent() const209 double TraceEvent::GetAbsTimeToOtherEvent() const {
210   return fabs(other_event->timestamp - timestamp);
211 }
212 
GetArgAsString(const std::string & arg_name,std::string * arg) const213 bool TraceEvent::GetArgAsString(const std::string& arg_name,
214                                 std::string* arg) const {
215   const auto it = arg_strings.find(arg_name);
216   if (it != arg_strings.end()) {
217     *arg = it->second;
218     return true;
219   }
220   return false;
221 }
222 
GetArgAsNumber(const std::string & arg_name,double * arg) const223 bool TraceEvent::GetArgAsNumber(const std::string& arg_name,
224                                 double* arg) const {
225   const auto it = arg_numbers.find(arg_name);
226   if (it != arg_numbers.end()) {
227     *arg = it->second;
228     return true;
229   }
230   return false;
231 }
232 
GetArgAsDict(const std::string & arg_name,base::Value::Dict * arg) const233 bool TraceEvent::GetArgAsDict(const std::string& arg_name,
234                               base::Value::Dict* arg) const {
235   const auto it = arg_dicts.find(arg_name);
236   if (it != arg_dicts.end()) {
237     *arg = it->second.Clone();
238     return true;
239   }
240   return false;
241 }
242 
HasStringArg(const std::string & arg_name) const243 bool TraceEvent::HasStringArg(const std::string& arg_name) const {
244   return (arg_strings.find(arg_name) != arg_strings.end());
245 }
246 
HasNumberArg(const std::string & arg_name) const247 bool TraceEvent::HasNumberArg(const std::string& arg_name) const {
248   return (arg_numbers.find(arg_name) != arg_numbers.end());
249 }
250 
HasDictArg(const std::string & arg_name) const251 bool TraceEvent::HasDictArg(const std::string& arg_name) const {
252   return (arg_dicts.find(arg_name) != arg_dicts.end());
253 }
254 
GetKnownArgAsString(const std::string & arg_name) const255 std::string TraceEvent::GetKnownArgAsString(const std::string& arg_name) const {
256   std::string arg_string;
257   bool result = GetArgAsString(arg_name, &arg_string);
258   DCHECK(result);
259   return arg_string;
260 }
261 
GetKnownArgAsDouble(const std::string & arg_name) const262 double TraceEvent::GetKnownArgAsDouble(const std::string& arg_name) const {
263   double arg_double = 0;
264   bool result = GetArgAsNumber(arg_name, &arg_double);
265   DCHECK(result);
266   return arg_double;
267 }
268 
GetKnownArgAsInt(const std::string & arg_name) const269 int TraceEvent::GetKnownArgAsInt(const std::string& arg_name) const {
270   double arg_double = 0;
271   bool result = GetArgAsNumber(arg_name, &arg_double);
272   DCHECK(result);
273   return static_cast<int>(arg_double);
274 }
275 
GetKnownArgAsBool(const std::string & arg_name) const276 bool TraceEvent::GetKnownArgAsBool(const std::string& arg_name) const {
277   double arg_double = 0;
278   bool result = GetArgAsNumber(arg_name, &arg_double);
279   DCHECK(result);
280   return (arg_double != 0.0);
281 }
282 
GetKnownArgAsDict(const std::string & arg_name) const283 base::Value::Dict TraceEvent::GetKnownArgAsDict(
284     const std::string& arg_name) const {
285   base::Value::Dict arg_dict;
286   bool result = GetArgAsDict(arg_name, &arg_dict);
287   DCHECK(result);
288   return arg_dict;
289 }
290 
291 // QueryNode
292 
QueryNode(const Query & query)293 QueryNode::QueryNode(const Query& query) : query_(query) {
294 }
295 
296 QueryNode::~QueryNode() = default;
297 
298 // Query
299 
Query(TraceEventMember member)300 Query::Query(TraceEventMember member)
301     : type_(QUERY_EVENT_MEMBER),
302       operator_(OP_INVALID),
303       member_(member),
304       number_(0),
305       is_pattern_(false) {
306 }
307 
Query(TraceEventMember member,const std::string & arg_name)308 Query::Query(TraceEventMember member, const std::string& arg_name)
309     : type_(QUERY_EVENT_MEMBER),
310       operator_(OP_INVALID),
311       member_(member),
312       number_(0),
313       string_(arg_name),
314       is_pattern_(false) {
315 }
316 
317 Query::Query(const Query& query) = default;
318 
319 Query::~Query() = default;
320 
String(const std::string & str)321 Query Query::String(const std::string& str) {
322   return Query(str);
323 }
324 
Double(double num)325 Query Query::Double(double num) {
326   return Query(num);
327 }
328 
Int(int32_t num)329 Query Query::Int(int32_t num) {
330   return Query(static_cast<double>(num));
331 }
332 
Uint(uint32_t num)333 Query Query::Uint(uint32_t num) {
334   return Query(static_cast<double>(num));
335 }
336 
Bool(bool boolean)337 Query Query::Bool(bool boolean) {
338   return Query(boolean ? 1.0 : 0.0);
339 }
340 
Phase(char phase)341 Query Query::Phase(char phase) {
342   return Query(static_cast<double>(phase));
343 }
344 
Pattern(const std::string & pattern)345 Query Query::Pattern(const std::string& pattern) {
346   Query query(pattern);
347   query.is_pattern_ = true;
348   return query;
349 }
350 
Evaluate(const TraceEvent & event) const351 bool Query::Evaluate(const TraceEvent& event) const {
352   // First check for values that can convert to bool.
353 
354   // double is true if != 0:
355   double bool_value = 0.0;
356   bool is_bool = GetAsDouble(event, &bool_value);
357   if (is_bool)
358     return (bool_value != 0.0);
359 
360   // string is true if it is non-empty:
361   std::string str_value;
362   bool is_str = GetAsString(event, &str_value);
363   if (is_str)
364     return !str_value.empty();
365 
366   DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
367       << "Invalid query: missing boolean expression";
368   DCHECK(left_.get());
369   DCHECK(right_.get() || is_unary_operator());
370 
371   if (is_comparison_operator()) {
372     DCHECK(left().is_value() && right().is_value())
373         << "Invalid query: comparison operator used between event member and "
374            "value.";
375     bool compare_result = false;
376     if (CompareAsDouble(event, &compare_result))
377       return compare_result;
378     if (CompareAsString(event, &compare_result))
379       return compare_result;
380     return false;
381   }
382   // It's a logical operator.
383   switch (operator_) {
384     case OP_AND:
385       return left().Evaluate(event) && right().Evaluate(event);
386     case OP_OR:
387       return left().Evaluate(event) || right().Evaluate(event);
388     case OP_NOT:
389       return !left().Evaluate(event);
390     default:
391       NOTREACHED();
392       return false;
393   }
394 }
395 
CompareAsDouble(const TraceEvent & event,bool * result) const396 bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const {
397   double lhs, rhs;
398   if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
399     return false;
400   switch (operator_) {
401     case OP_EQ:
402       *result = (lhs == rhs);
403       return true;
404     case OP_NE:
405       *result = (lhs != rhs);
406       return true;
407     case OP_LT:
408       *result = (lhs < rhs);
409       return true;
410     case OP_LE:
411       *result = (lhs <= rhs);
412       return true;
413     case OP_GT:
414       *result = (lhs > rhs);
415       return true;
416     case OP_GE:
417       *result = (lhs >= rhs);
418       return true;
419     default:
420       NOTREACHED();
421       return false;
422   }
423 }
424 
CompareAsString(const TraceEvent & event,bool * result) const425 bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
426   std::string lhs, rhs;
427   if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
428     return false;
429   switch (operator_) {
430     case OP_EQ:
431       if (right().is_pattern_)
432         *result = base::MatchPattern(lhs, rhs);
433       else if (left().is_pattern_)
434         *result = base::MatchPattern(rhs, lhs);
435       else
436         *result = (lhs == rhs);
437       return true;
438     case OP_NE:
439       if (right().is_pattern_)
440         *result = !base::MatchPattern(lhs, rhs);
441       else if (left().is_pattern_)
442         *result = !base::MatchPattern(rhs, lhs);
443       else
444         *result = (lhs != rhs);
445       return true;
446     case OP_LT:
447       *result = (lhs < rhs);
448       return true;
449     case OP_LE:
450       *result = (lhs <= rhs);
451       return true;
452     case OP_GT:
453       *result = (lhs > rhs);
454       return true;
455     case OP_GE:
456       *result = (lhs >= rhs);
457       return true;
458     default:
459       NOTREACHED();
460       return false;
461   }
462 }
463 
EvaluateArithmeticOperator(const TraceEvent & event,double * num) const464 bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
465                                        double* num) const {
466   DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_);
467   DCHECK(left_.get());
468   DCHECK(right_.get() || is_unary_operator());
469 
470   double lhs = 0, rhs = 0;
471   if (!left().GetAsDouble(event, &lhs))
472     return false;
473   if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
474     return false;
475 
476   switch (operator_) {
477     case OP_ADD:
478       *num = lhs + rhs;
479       return true;
480     case OP_SUB:
481       *num = lhs - rhs;
482       return true;
483     case OP_MUL:
484       *num = lhs * rhs;
485       return true;
486     case OP_DIV:
487       *num = lhs / rhs;
488       return true;
489     case OP_MOD:
490       *num = static_cast<double>(static_cast<int64_t>(lhs) %
491                                  static_cast<int64_t>(rhs));
492       return true;
493     case OP_NEGATE:
494       *num = -lhs;
495       return true;
496     default:
497       NOTREACHED();
498       return false;
499   }
500 }
501 
GetAsDouble(const TraceEvent & event,double * num) const502 bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
503   switch (type_) {
504     case QUERY_ARITHMETIC_OPERATOR:
505       return EvaluateArithmeticOperator(event, num);
506     case QUERY_EVENT_MEMBER:
507       return GetMemberValueAsDouble(event, num);
508     case QUERY_NUMBER:
509       *num = number_;
510       return true;
511     default:
512       return false;
513   }
514 }
515 
GetAsString(const TraceEvent & event,std::string * str) const516 bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
517   switch (type_) {
518     case QUERY_EVENT_MEMBER:
519       return GetMemberValueAsString(event, str);
520     case QUERY_STRING:
521       *str = string_;
522       return true;
523     default:
524       return false;
525   }
526 }
527 
SelectTargetEvent(const TraceEvent * event,TraceEventMember member)528 const TraceEvent* Query::SelectTargetEvent(const TraceEvent* event,
529                                            TraceEventMember member) {
530   if (member >= OTHER_FIRST_MEMBER && member <= OTHER_LAST_MEMBER)
531     return event->other_event;
532   if (member >= PREV_FIRST_MEMBER && member <= PREV_LAST_MEMBER)
533     return event->prev_event;
534   return event;
535 }
536 
GetMemberValueAsDouble(const TraceEvent & event,double * num) const537 bool Query::GetMemberValueAsDouble(const TraceEvent& event,
538                                    double* num) const {
539   DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
540 
541   // This could be a request for a member of |event| or a member of |event|'s
542   // associated previous or next event. Store the target event in the_event:
543   const TraceEvent* the_event = SelectTargetEvent(&event, member_);
544 
545   // Request for member of associated event, but there is no associated event.
546   if (!the_event)
547     return false;
548 
549   switch (member_) {
550     case EVENT_PID:
551     case OTHER_PID:
552     case PREV_PID:
553       *num = static_cast<double>(the_event->thread.process_id);
554       return true;
555     case EVENT_TID:
556     case OTHER_TID:
557     case PREV_TID:
558       *num = static_cast<double>(the_event->thread.thread_id);
559       return true;
560     case EVENT_TIME:
561     case OTHER_TIME:
562     case PREV_TIME:
563       *num = the_event->timestamp;
564       return true;
565     case EVENT_DURATION:
566       if (!the_event->has_other_event())
567         return false;
568       *num = the_event->GetAbsTimeToOtherEvent();
569       return true;
570     case EVENT_COMPLETE_DURATION:
571       if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE)
572         return false;
573       *num = the_event->duration;
574       return true;
575     case EVENT_PHASE:
576     case OTHER_PHASE:
577     case PREV_PHASE:
578       *num = static_cast<double>(the_event->phase);
579       return true;
580     case EVENT_HAS_STRING_ARG:
581     case OTHER_HAS_STRING_ARG:
582     case PREV_HAS_STRING_ARG:
583       *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0);
584       return true;
585     case EVENT_HAS_NUMBER_ARG:
586     case OTHER_HAS_NUMBER_ARG:
587     case PREV_HAS_NUMBER_ARG:
588       *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0);
589       return true;
590     case EVENT_ARG:
591     case OTHER_ARG:
592     case PREV_ARG: {
593       // Search for the argument name and return its value if found.
594       auto num_i = the_event->arg_numbers.find(string_);
595       if (num_i == the_event->arg_numbers.end())
596         return false;
597       *num = num_i->second;
598       return true;
599     }
600     case EVENT_HAS_OTHER:
601       // return 1.0 (true) if the other event exists
602       *num = event.other_event ? 1.0 : 0.0;
603       return true;
604     case EVENT_HAS_PREV:
605       *num = event.prev_event ? 1.0 : 0.0;
606       return true;
607     default:
608       return false;
609   }
610 }
611 
GetMemberValueAsString(const TraceEvent & event,std::string * str) const612 bool Query::GetMemberValueAsString(const TraceEvent& event,
613                                    std::string* str) const {
614   DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
615 
616   // This could be a request for a member of |event| or a member of |event|'s
617   // associated previous or next event. Store the target event in the_event:
618   const TraceEvent* the_event = SelectTargetEvent(&event, member_);
619 
620   // Request for member of associated event, but there is no associated event.
621   if (!the_event)
622     return false;
623 
624   switch (member_) {
625     case EVENT_CATEGORY:
626     case OTHER_CATEGORY:
627     case PREV_CATEGORY:
628       *str = the_event->category;
629       return true;
630     case EVENT_NAME:
631     case OTHER_NAME:
632     case PREV_NAME:
633       *str = the_event->name;
634       return true;
635     case EVENT_ID:
636     case OTHER_ID:
637     case PREV_ID:
638       *str = the_event->id;
639       return true;
640     case EVENT_ARG:
641     case OTHER_ARG:
642     case PREV_ARG: {
643       // Search for the argument name and return its value if found.
644       auto str_i = the_event->arg_strings.find(string_);
645       if (str_i == the_event->arg_strings.end())
646         return false;
647       *str = str_i->second;
648       return true;
649     }
650     default:
651       return false;
652   }
653 }
654 
Query(const std::string & str)655 Query::Query(const std::string& str)
656     : type_(QUERY_STRING),
657       operator_(OP_INVALID),
658       member_(EVENT_INVALID),
659       number_(0),
660       string_(str),
661       is_pattern_(false) {
662 }
663 
Query(double num)664 Query::Query(double num)
665     : type_(QUERY_NUMBER),
666       operator_(OP_INVALID),
667       member_(EVENT_INVALID),
668       number_(num),
669       is_pattern_(false) {
670 }
left() const671 const Query& Query::left() const {
672   return left_->query();
673 }
674 
right() const675 const Query& Query::right() const {
676   return right_->query();
677 }
678 
operator ==(const Query & rhs) const679 Query Query::operator==(const Query& rhs) const {
680   return Query(*this, rhs, OP_EQ);
681 }
682 
operator !=(const Query & rhs) const683 Query Query::operator!=(const Query& rhs) const {
684   return Query(*this, rhs, OP_NE);
685 }
686 
operator <(const Query & rhs) const687 Query Query::operator<(const Query& rhs) const {
688   return Query(*this, rhs, OP_LT);
689 }
690 
operator <=(const Query & rhs) const691 Query Query::operator<=(const Query& rhs) const {
692   return Query(*this, rhs, OP_LE);
693 }
694 
operator >(const Query & rhs) const695 Query Query::operator>(const Query& rhs) const {
696   return Query(*this, rhs, OP_GT);
697 }
698 
operator >=(const Query & rhs) const699 Query Query::operator>=(const Query& rhs) const {
700   return Query(*this, rhs, OP_GE);
701 }
702 
operator &&(const Query & rhs) const703 Query Query::operator&&(const Query& rhs) const {
704   return Query(*this, rhs, OP_AND);
705 }
706 
operator ||(const Query & rhs) const707 Query Query::operator||(const Query& rhs) const {
708   return Query(*this, rhs, OP_OR);
709 }
710 
operator !() const711 Query Query::operator!() const {
712   return Query(*this, OP_NOT);
713 }
714 
operator +(const Query & rhs) const715 Query Query::operator+(const Query& rhs) const {
716   return Query(*this, rhs, OP_ADD);
717 }
718 
operator -(const Query & rhs) const719 Query Query::operator-(const Query& rhs) const {
720   return Query(*this, rhs, OP_SUB);
721 }
722 
operator *(const Query & rhs) const723 Query Query::operator*(const Query& rhs) const {
724   return Query(*this, rhs, OP_MUL);
725 }
726 
operator /(const Query & rhs) const727 Query Query::operator/(const Query& rhs) const {
728   return Query(*this, rhs, OP_DIV);
729 }
730 
operator %(const Query & rhs) const731 Query Query::operator%(const Query& rhs) const {
732   return Query(*this, rhs, OP_MOD);
733 }
734 
operator -() const735 Query Query::operator-() const {
736   return Query(*this, OP_NEGATE);
737 }
738 
739 
Query(const Query & left,const Query & right,Operator binary_op)740 Query::Query(const Query& left, const Query& right, Operator binary_op)
741     : operator_(binary_op),
742       left_(new QueryNode(left)),
743       right_(new QueryNode(right)),
744       member_(EVENT_INVALID),
745       number_(0) {
746   type_ = (binary_op < OP_ADD ?
747            QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
748 }
749 
Query(const Query & left,Operator unary_op)750 Query::Query(const Query& left, Operator unary_op)
751     : operator_(unary_op),
752       left_(new QueryNode(left)),
753       member_(EVENT_INVALID),
754       number_(0) {
755   type_ = (unary_op < OP_ADD ?
756            QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
757 }
758 
759 namespace {
760 
761 // Search |events| for |query| and add matches to |output|.
FindMatchingEvents(const std::vector<TraceEvent> & events,const Query & query,TraceEventVector * output,bool ignore_metadata_events)762 size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
763                           const Query& query,
764                           TraceEventVector* output,
765                           bool ignore_metadata_events) {
766   for (const auto& i : events) {
767     if (ignore_metadata_events && i.phase == TRACE_EVENT_PHASE_METADATA)
768       continue;
769     if (query.Evaluate(i))
770       output->push_back(&i);
771   }
772   return output->size();
773 }
774 
ParseEventsFromJson(const std::string & json,std::vector<TraceEvent> * output)775 bool ParseEventsFromJson(const std::string& json,
776                          std::vector<TraceEvent>* output) {
777   std::optional<base::Value> root = base::JSONReader::Read(json);
778 
779   if (!root)
780     return false;
781 
782   base::Value::List* list = nullptr;
783   if (root->is_list()) {
784     list = &root->GetList();
785   } else if (root->is_dict()) {
786     list = root->GetDict().FindList("traceEvents");
787   }
788   if (!list)
789     return false;
790 
791   for (const auto& item : *list) {
792     TraceEvent event;
793     if (!event.SetFromJSON(&item))
794       return false;
795     output->push_back(std::move(event));
796   }
797 
798   return true;
799 }
800 
801 }  // namespace
802 
803 // TraceAnalyzer
804 
TraceAnalyzer()805 TraceAnalyzer::TraceAnalyzer()
806     : ignore_metadata_events_(false), allow_association_changes_(true) {}
807 
808 TraceAnalyzer::~TraceAnalyzer() = default;
809 
810 // static
Create(const std::string & json_events)811 std::unique_ptr<TraceAnalyzer> TraceAnalyzer::Create(
812     const std::string& json_events) {
813   std::unique_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
814   if (analyzer->SetEvents(json_events))
815     return analyzer;
816   return nullptr;
817 }
818 
SetEvents(const std::string & json_events)819 bool TraceAnalyzer::SetEvents(const std::string& json_events) {
820   raw_events_.clear();
821   if (!ParseEventsFromJson(json_events, &raw_events_))
822     return false;
823   base::ranges::stable_sort(raw_events_);
824   ParseMetadata();
825   return true;
826 }
827 
AssociateBeginEndEvents()828 void TraceAnalyzer::AssociateBeginEndEvents() {
829   using trace_analyzer::Query;
830 
831   Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
832   Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
833   Query match(Query::EventName() == Query::OtherName() &&
834               Query::EventCategory() == Query::OtherCategory() &&
835               Query::EventTid() == Query::OtherTid() &&
836               Query::EventPid() == Query::OtherPid());
837 
838   AssociateEvents(begin, end, match);
839 }
840 
AssociateAsyncBeginEndEvents(bool match_pid)841 void TraceAnalyzer::AssociateAsyncBeginEndEvents(bool match_pid) {
842   using trace_analyzer::Query;
843 
844   Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
845               Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
846               Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST) ||
847               Query::EventPhaseIs(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN));
848   Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
849             Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
850             Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST) ||
851             Query::EventPhaseIs(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END));
852   Query match(Query::EventCategory() == Query::OtherCategory() &&
853               Query::EventId() == Query::OtherId());
854 
855   if (match_pid) {
856     match = match && Query::EventPid() == Query::OtherPid();
857   }
858 
859   AssociateEvents(begin, end, match);
860 }
861 
AssociateEvents(const Query & first,const Query & second,const Query & match)862 void TraceAnalyzer::AssociateEvents(const Query& first,
863                                     const Query& second,
864                                     const Query& match) {
865   DCHECK(allow_association_changes_)
866       << "AssociateEvents not allowed after FindEvents";
867 
868   // Search for matching begin/end event pairs. When a matching end is found,
869   // it is associated with the begin event.
870   std::vector<TraceEvent*> begin_stack;
871   for (auto& this_event : raw_events_) {
872     if (second.Evaluate(this_event)) {
873       // Search stack for matching begin, starting from end.
874       for (int stack_index = static_cast<int>(begin_stack.size()) - 1;
875            stack_index >= 0; --stack_index) {
876         TraceEvent& begin_event = *begin_stack[stack_index];
877 
878         // Temporarily set other to test against the match query.
879         const TraceEvent* other_backup = begin_event.other_event;
880         begin_event.other_event = &this_event;
881         if (match.Evaluate(begin_event)) {
882           // Found a matching begin/end pair.
883           // Set the associated previous event
884           this_event.prev_event = &begin_event;
885           // Erase the matching begin event index from the stack.
886           begin_stack.erase(begin_stack.begin() + stack_index);
887           break;
888         }
889 
890         // Not a match, restore original other and continue.
891         begin_event.other_event = other_backup;
892       }
893     }
894     // Even if this_event is a |second| event that has matched an earlier
895     // |first| event, it can still also be a |first| event and be associated
896     // with a later |second| event.
897     if (first.Evaluate(this_event)) {
898       begin_stack.push_back(&this_event);
899     }
900   }
901 }
902 
MergeAssociatedEventArgs()903 void TraceAnalyzer::MergeAssociatedEventArgs() {
904   for (auto& i : raw_events_) {
905     // Merge all associated events with the first event.
906     const TraceEvent* other = i.other_event;
907     // Avoid looping by keeping set of encountered TraceEvents.
908     std::set<const TraceEvent*> encounters;
909     encounters.insert(&i);
910     while (other && encounters.find(other) == encounters.end()) {
911       encounters.insert(other);
912       i.arg_numbers.insert(other->arg_numbers.begin(),
913                            other->arg_numbers.end());
914       i.arg_strings.insert(other->arg_strings.begin(),
915                            other->arg_strings.end());
916       other = other->other_event;
917     }
918   }
919 }
920 
FindEvents(const Query & query,TraceEventVector * output)921 size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) {
922   allow_association_changes_ = false;
923   output->clear();
924   return FindMatchingEvents(
925       raw_events_, query, output, ignore_metadata_events_);
926 }
927 
FindFirstOf(const Query & query)928 const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
929   TraceEventVector output;
930   if (FindEvents(query, &output) > 0)
931     return output.front();
932   return nullptr;
933 }
934 
FindLastOf(const Query & query)935 const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
936   TraceEventVector output;
937   if (FindEvents(query, &output) > 0)
938     return output.back();
939   return nullptr;
940 }
941 
GetThreadName(const TraceEvent::ProcessThreadID & thread)942 const std::string& TraceAnalyzer::GetThreadName(
943     const TraceEvent::ProcessThreadID& thread) {
944   // If thread is not found, just add and return empty string.
945   return thread_names_[thread];
946 }
947 
ParseMetadata()948 void TraceAnalyzer::ParseMetadata() {
949   for (const auto& this_event : raw_events_) {
950     // Check for thread name metadata.
951     if (this_event.phase != TRACE_EVENT_PHASE_METADATA ||
952         this_event.name != "thread_name")
953       continue;
954     std::map<std::string, std::string>::const_iterator string_it =
955         this_event.arg_strings.find("name");
956     if (string_it != this_event.arg_strings.end())
957       thread_names_[this_event.thread] = string_it->second;
958   }
959 }
960 
961 // Utility functions for collecting process-local traces and creating a
962 // |TraceAnalyzer| from the result.
963 
Start(const std::string & category_filter_string)964 void Start(const std::string& category_filter_string) {
965   DCHECK(!base::trace_event::TraceLog::GetInstance()->IsEnabled());
966   base::trace_event::TraceLog::GetInstance()->SetEnabled(
967       base::trace_event::TraceConfig(category_filter_string, ""),
968       base::trace_event::TraceLog::RECORDING_MODE);
969 }
970 
Stop()971 std::unique_ptr<TraceAnalyzer> Stop() {
972   DCHECK(base::trace_event::TraceLog::GetInstance()->IsEnabled());
973   base::trace_event::TraceLog::GetInstance()->SetDisabled();
974 
975   base::trace_event::TraceResultBuffer buffer;
976   base::trace_event::TraceResultBuffer::SimpleOutput trace_output;
977   buffer.SetOutputCallback(trace_output.GetCallback());
978   base::RunLoop run_loop;
979   buffer.Start();
980   base::trace_event::TraceLog::GetInstance()->Flush(
981       base::BindRepeating(&OnTraceDataCollected, run_loop.QuitClosure(),
982                           base::Unretained(&buffer)));
983   run_loop.Run();
984   buffer.Finish();
985 
986   return TraceAnalyzer::Create(trace_output.json_output);
987 }
988 
989 // TraceEventVector utility functions.
990 
GetRateStats(const TraceEventVector & events,RateStats * stats,const RateStatsOptions * options)991 bool GetRateStats(const TraceEventVector& events,
992                   RateStats* stats,
993                   const RateStatsOptions* options) {
994   DCHECK(stats);
995   // Need at least 3 events to calculate rate stats.
996   const size_t kMinEvents = 3;
997   if (events.size() < kMinEvents) {
998     LOG(ERROR) << "Not enough events: " << events.size();
999     return false;
1000   }
1001 
1002   std::vector<double> deltas;
1003   size_t num_deltas = events.size() - 1;
1004   for (size_t i = 0; i < num_deltas; ++i) {
1005     double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp;
1006     if (delta < 0.0) {
1007       LOG(ERROR) << "Events are out of order";
1008       return false;
1009     }
1010     deltas.push_back(delta);
1011   }
1012 
1013   base::ranges::sort(deltas);
1014 
1015   if (options) {
1016     if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
1017       LOG(ERROR) << "Attempt to trim too many events";
1018       return false;
1019     }
1020     deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
1021     deltas.erase(deltas.end() - options->trim_max, deltas.end());
1022   }
1023 
1024   num_deltas = deltas.size();
1025   double delta_sum = 0.0;
1026   for (size_t i = 0; i < num_deltas; ++i)
1027     delta_sum += deltas[i];
1028 
1029   stats->min_us = *base::ranges::min_element(deltas);
1030   stats->max_us = *base::ranges::max_element(deltas);
1031   stats->mean_us = delta_sum / static_cast<double>(num_deltas);
1032 
1033   double sum_mean_offsets_squared = 0.0;
1034   for (size_t i = 0; i < num_deltas; ++i) {
1035     double offset = fabs(deltas[i] - stats->mean_us);
1036     sum_mean_offsets_squared += offset * offset;
1037   }
1038   stats->standard_deviation_us =
1039       sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
1040 
1041   return true;
1042 }
1043 
FindFirstOf(const TraceEventVector & events,const Query & query,size_t position,size_t * return_index)1044 bool FindFirstOf(const TraceEventVector& events,
1045                  const Query& query,
1046                  size_t position,
1047                  size_t* return_index) {
1048   DCHECK(return_index);
1049   for (size_t i = position; i < events.size(); ++i) {
1050     if (query.Evaluate(*events[i])) {
1051       *return_index = i;
1052       return true;
1053     }
1054   }
1055   return false;
1056 }
1057 
FindLastOf(const TraceEventVector & events,const Query & query,size_t position,size_t * return_index)1058 bool FindLastOf(const TraceEventVector& events,
1059                 const Query& query,
1060                 size_t position,
1061                 size_t* return_index) {
1062   DCHECK(return_index);
1063   for (size_t i = std::min(position + 1, events.size()); i != 0; --i) {
1064     if (query.Evaluate(*events[i - 1])) {
1065       *return_index = i - 1;
1066       return true;
1067     }
1068   }
1069   return false;
1070 }
1071 
FindClosest(const TraceEventVector & events,const Query & query,size_t position,size_t * return_closest,size_t * return_second_closest)1072 bool FindClosest(const TraceEventVector& events,
1073                  const Query& query,
1074                  size_t position,
1075                  size_t* return_closest,
1076                  size_t* return_second_closest) {
1077   DCHECK(return_closest);
1078   if (events.empty() || position >= events.size())
1079     return false;
1080   size_t closest = events.size();
1081   size_t second_closest = events.size();
1082   for (size_t i = 0; i < events.size(); ++i) {
1083     if (!query.Evaluate(*events.at(i)))
1084       continue;
1085     if (closest == events.size()) {
1086       closest = i;
1087       continue;
1088     }
1089     if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
1090         fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
1091       second_closest = closest;
1092       closest = i;
1093     } else if (second_closest == events.size()) {
1094       second_closest = i;
1095     }
1096   }
1097 
1098   if (closest < events.size() &&
1099       (!return_second_closest || second_closest < events.size())) {
1100     *return_closest = closest;
1101     if (return_second_closest)
1102       *return_second_closest = second_closest;
1103     return true;
1104   }
1105 
1106   return false;
1107 }
1108 
CountMatches(const TraceEventVector & events,const Query & query,size_t begin_position,size_t end_position)1109 size_t CountMatches(const TraceEventVector& events,
1110                     const Query& query,
1111                     size_t begin_position,
1112                     size_t end_position) {
1113   if (begin_position >= events.size())
1114     return 0u;
1115   end_position = (end_position < events.size()) ? end_position : events.size();
1116   size_t count = 0u;
1117   for (size_t i = begin_position; i < end_position; ++i) {
1118     if (query.Evaluate(*events.at(i)))
1119       ++count;
1120   }
1121   return count;
1122 }
1123 
1124 }  // namespace trace_analyzer
1125