• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/fuchsia/fuchsia_trace_parser.h"
18 
19 #include "src/trace_processor/importers/common/args_tracker.h"
20 #include "src/trace_processor/importers/common/event_tracker.h"
21 #include "src/trace_processor/importers/common/flow_tracker.h"
22 #include "src/trace_processor/importers/common/process_tracker.h"
23 #include "src/trace_processor/importers/common/slice_tracker.h"
24 #include "src/trace_processor/importers/common/track_tracker.h"
25 #include "src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h"
26 #include "src/trace_processor/importers/proto/proto_trace_parser.h"
27 
28 namespace perfetto {
29 namespace trace_processor {
30 
31 namespace {
32 // Record Types
33 constexpr uint32_t kEvent = 4;
34 
35 // Event Types
36 constexpr uint32_t kInstant = 0;
37 constexpr uint32_t kCounter = 1;
38 constexpr uint32_t kDurationBegin = 2;
39 constexpr uint32_t kDurationEnd = 3;
40 constexpr uint32_t kDurationComplete = 4;
41 constexpr uint32_t kAsyncBegin = 5;
42 constexpr uint32_t kAsyncInstant = 6;
43 constexpr uint32_t kAsyncEnd = 7;
44 constexpr uint32_t kFlowBegin = 8;
45 constexpr uint32_t kFlowStep = 9;
46 constexpr uint32_t kFlowEnd = 10;
47 
48 // Argument Types
49 constexpr uint32_t kNull = 0;
50 constexpr uint32_t kInt32 = 1;
51 constexpr uint32_t kUint32 = 2;
52 constexpr uint32_t kInt64 = 3;
53 constexpr uint32_t kUint64 = 4;
54 constexpr uint32_t kDouble = 5;
55 constexpr uint32_t kString = 6;
56 constexpr uint32_t kPointer = 7;
57 constexpr uint32_t kKoid = 8;
58 constexpr uint32_t kBool = 9;
59 
60 }  // namespace
61 
FuchsiaTraceParser(TraceProcessorContext * context)62 FuchsiaTraceParser::FuchsiaTraceParser(TraceProcessorContext* context)
63     : context_(context), proto_parser_(new ProtoTraceParser(context_)) {}
64 
65 FuchsiaTraceParser::~FuchsiaTraceParser() = default;
66 
ParseTrackEvent(int64_t ts,TrackEventData data)67 void FuchsiaTraceParser::ParseTrackEvent(int64_t ts, TrackEventData data) {
68   proto_parser_->ParseTrackEvent(ts, std::move(data));
69 }
70 
ParseTracePacket(int64_t ts,TracePacketData data)71 void FuchsiaTraceParser::ParseTracePacket(int64_t ts, TracePacketData data) {
72   proto_parser_->ParseTracePacket(ts, std::move(data));
73 }
74 
75 std::optional<std::vector<FuchsiaTraceParser::Arg>>
ParseArgs(fuchsia_trace_utils::RecordCursor & cursor,uint32_t n_args,std::function<StringId (base::StringView string)> intern_string,std::function<StringId (uint32_t index)> get_string)76 FuchsiaTraceParser::ParseArgs(
77     fuchsia_trace_utils::RecordCursor& cursor,
78     uint32_t n_args,
79     std::function<StringId(base::StringView string)> intern_string,
80     std::function<StringId(uint32_t index)> get_string) {
81   std::vector<Arg> args;
82   for (uint32_t i = 0; i < n_args; i++) {
83     size_t arg_base = cursor.WordIndex();
84     uint64_t arg_header;
85     if (!cursor.ReadUint64(&arg_header)) {
86       return std::nullopt;
87     }
88     uint32_t arg_type =
89         fuchsia_trace_utils::ReadField<uint32_t>(arg_header, 0, 3);
90     uint32_t arg_size_words =
91         fuchsia_trace_utils::ReadField<uint32_t>(arg_header, 4, 15);
92     uint32_t arg_name_ref =
93         fuchsia_trace_utils::ReadField<uint32_t>(arg_header, 16, 31);
94     Arg arg;
95     if (fuchsia_trace_utils::IsInlineString(arg_name_ref)) {
96       base::StringView arg_name_view;
97       if (!cursor.ReadInlineString(arg_name_ref, &arg_name_view)) {
98         return std::nullopt;
99       }
100       arg.name = intern_string(arg_name_view);
101     } else {
102       arg.name = get_string(arg_name_ref);
103     }
104 
105     switch (arg_type) {
106       case kNull:
107         arg.value = fuchsia_trace_utils::ArgValue::Null();
108         break;
109       case kInt32:
110         arg.value = fuchsia_trace_utils::ArgValue::Int32(
111             fuchsia_trace_utils::ReadField<int32_t>(arg_header, 32, 63));
112         break;
113       case kUint32:
114         arg.value = fuchsia_trace_utils::ArgValue::Uint32(
115             fuchsia_trace_utils::ReadField<uint32_t>(arg_header, 32, 63));
116         break;
117       case kInt64: {
118         int64_t value;
119         if (!cursor.ReadInt64(&value)) {
120           return std::nullopt;
121         }
122         arg.value = fuchsia_trace_utils::ArgValue::Int64(value);
123         break;
124       }
125       case kUint64: {
126         uint64_t value;
127         if (!cursor.ReadUint64(&value)) {
128           return std::nullopt;
129         }
130         arg.value = fuchsia_trace_utils::ArgValue::Uint64(value);
131         break;
132       }
133       case kDouble: {
134         double value;
135         if (!cursor.ReadDouble(&value)) {
136           return std::nullopt;
137         }
138         arg.value = fuchsia_trace_utils::ArgValue::Double(value);
139         break;
140       }
141       case kString: {
142         uint32_t arg_value_ref =
143             fuchsia_trace_utils::ReadField<uint32_t>(arg_header, 32, 47);
144         StringId value;
145         if (fuchsia_trace_utils::IsInlineString(arg_value_ref)) {
146           base::StringView arg_value_view;
147           if (!cursor.ReadInlineString(arg_value_ref, &arg_value_view)) {
148             return std::nullopt;
149           }
150           value = intern_string(arg_value_view);
151         } else {
152           value = get_string(arg_value_ref);
153         }
154         arg.value = fuchsia_trace_utils::ArgValue::String(value);
155         break;
156       }
157       case kPointer: {
158         uint64_t value;
159         if (!cursor.ReadUint64(&value)) {
160           return std::nullopt;
161         }
162         arg.value = fuchsia_trace_utils::ArgValue::Pointer(value);
163         break;
164       }
165       case kKoid: {
166         uint64_t value;
167         if (!cursor.ReadUint64(&value)) {
168           return std::nullopt;
169         }
170         arg.value = fuchsia_trace_utils::ArgValue::Koid(value);
171         break;
172       }
173       case kBool: {
174         arg.value = fuchsia_trace_utils::ArgValue::Bool(
175             fuchsia_trace_utils::ReadField<bool>(arg_header, 32, 63));
176         break;
177       }
178       default:
179         arg.value = fuchsia_trace_utils::ArgValue::Unknown();
180         break;
181     }
182 
183     args.push_back(arg);
184     cursor.SetWordIndex(arg_base + arg_size_words);
185   }
186 
187   return {std::move(args)};
188 }
189 
ParseFuchsiaRecord(int64_t,FuchsiaRecord fr)190 void FuchsiaTraceParser::ParseFuchsiaRecord(int64_t, FuchsiaRecord fr) {
191   // The timestamp is also present in the record, so we'll ignore the one
192   // passed as an argument.
193   fuchsia_trace_utils::RecordCursor cursor(fr.record_view()->data(),
194                                            fr.record_view()->length());
195   ProcessTracker* procs = context_->process_tracker.get();
196   SliceTracker* slices = context_->slice_tracker.get();
197 
198   uint64_t header;
199   if (!cursor.ReadUint64(&header)) {
200     context_->storage->IncrementStats(stats::fuchsia_invalid_event);
201     return;
202   }
203   uint32_t record_type = fuchsia_trace_utils::ReadField<uint32_t>(header, 0, 3);
204   switch (record_type) {
205     case kEvent: {
206       uint32_t event_type =
207           fuchsia_trace_utils::ReadField<uint32_t>(header, 16, 19);
208       uint32_t n_args =
209           fuchsia_trace_utils::ReadField<uint32_t>(header, 20, 23);
210       uint32_t thread_ref =
211           fuchsia_trace_utils::ReadField<uint32_t>(header, 24, 31);
212       uint32_t cat_ref =
213           fuchsia_trace_utils::ReadField<uint32_t>(header, 32, 47);
214       uint32_t name_ref =
215           fuchsia_trace_utils::ReadField<uint32_t>(header, 48, 63);
216 
217       int64_t ts;
218       if (!cursor.ReadTimestamp(fr.get_ticks_per_second(), &ts)) {
219         context_->storage->IncrementStats(stats::fuchsia_invalid_event);
220         return;
221       }
222       FuchsiaThreadInfo tinfo;
223       if (fuchsia_trace_utils::IsInlineThread(thread_ref)) {
224         if (!cursor.ReadInlineThread(&tinfo)) {
225           context_->storage->IncrementStats(stats::fuchsia_invalid_event);
226           return;
227         }
228       } else {
229         tinfo = fr.GetThread(thread_ref);
230       }
231       StringId cat;
232       if (fuchsia_trace_utils::IsInlineString(cat_ref)) {
233         base::StringView cat_string_view;
234         if (!cursor.ReadInlineString(cat_ref, &cat_string_view)) {
235           context_->storage->IncrementStats(stats::fuchsia_invalid_event);
236           return;
237         }
238         cat = context_->storage->InternString(cat_string_view);
239       } else {
240         cat = fr.GetString(cat_ref);
241       }
242       StringId name;
243       if (fuchsia_trace_utils::IsInlineString(name_ref)) {
244         base::StringView name_string_view;
245         if (!cursor.ReadInlineString(name_ref, &name_string_view)) {
246           context_->storage->IncrementStats(stats::fuchsia_invalid_event);
247           return;
248         }
249         name = context_->storage->InternString(name_string_view);
250       } else {
251         name = fr.GetString(name_ref);
252       }
253 
254       // Read arguments
255       const auto intern_string = [this](base::StringView string) {
256         return context_->storage->InternString(string);
257       };
258       const auto get_string = [&fr](uint32_t index) {
259         return fr.GetString(index);
260       };
261 
262       auto maybe_args = FuchsiaTraceParser::ParseArgs(
263           cursor, n_args, intern_string, get_string);
264       if (!maybe_args.has_value()) {
265         context_->storage->IncrementStats(stats::fuchsia_invalid_event);
266         return;
267       }
268 
269       auto insert_args =
270           [this, args = *maybe_args](ArgsTracker::BoundInserter* inserter) {
271             for (const Arg& arg : args) {
272               inserter->AddArg(
273                   arg.name, arg.name,
274                   arg.value.ToStorageVariadic(context_->storage.get()));
275             }
276           };
277 
278       switch (event_type) {
279         case kInstant: {
280           UniqueTid utid =
281               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
282                                   static_cast<uint32_t>(tinfo.pid));
283           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
284           slices->Scoped(ts, track_id, cat, name, 0, std::move(insert_args));
285           break;
286         }
287         case kCounter: {
288           UniquePid upid =
289               procs->GetOrCreateProcess(static_cast<uint32_t>(tinfo.pid));
290           std::string name_str =
291               context_->storage->GetString(name).ToStdString();
292           uint64_t counter_id;
293           if (!cursor.ReadUint64(&counter_id)) {
294             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
295             return;
296           }
297           // Note: In the Fuchsia trace format, counter values are stored
298           // in the arguments for the record, with the data series defined
299           // by both the record name and the argument name. In Perfetto,
300           // counters only have one name, so we combine both names into
301           // one here.
302           for (const Arg& arg : *maybe_args) {
303             std::string counter_name_str = name_str + ":";
304             counter_name_str +=
305                 context_->storage->GetString(arg.name).ToStdString();
306             counter_name_str += ":" + std::to_string(counter_id);
307             bool is_valid_value = false;
308             double counter_value = -1;
309             switch (arg.value.Type()) {
310               case fuchsia_trace_utils::ArgValue::kInt32:
311                 is_valid_value = true;
312                 counter_value = static_cast<double>(arg.value.Int32());
313                 break;
314               case fuchsia_trace_utils::ArgValue::kUint32:
315                 is_valid_value = true;
316                 counter_value = static_cast<double>(arg.value.Uint32());
317                 break;
318               case fuchsia_trace_utils::ArgValue::kInt64:
319                 is_valid_value = true;
320                 counter_value = static_cast<double>(arg.value.Int64());
321                 break;
322               case fuchsia_trace_utils::ArgValue::kUint64:
323                 is_valid_value = true;
324                 counter_value = static_cast<double>(arg.value.Uint64());
325                 break;
326               case fuchsia_trace_utils::ArgValue::kDouble:
327                 is_valid_value = true;
328                 counter_value = arg.value.Double();
329                 break;
330               case fuchsia_trace_utils::ArgValue::kNull:
331               case fuchsia_trace_utils::ArgValue::kString:
332               case fuchsia_trace_utils::ArgValue::kPointer:
333               case fuchsia_trace_utils::ArgValue::kKoid:
334               case fuchsia_trace_utils::ArgValue::kBool:
335               case fuchsia_trace_utils::ArgValue::kUnknown:
336                 context_->storage->IncrementStats(
337                     stats::fuchsia_non_numeric_counters);
338                 break;
339             }
340             if (is_valid_value) {
341               StringId counter_name_id = context_->storage->InternString(
342                   base::StringView(counter_name_str));
343               TrackId track =
344                   context_->track_tracker->InternProcessCounterTrack(
345                       counter_name_id, upid);
346               context_->event_tracker->PushCounter(ts, counter_value, track);
347             }
348           }
349           break;
350         }
351         case kDurationBegin: {
352           UniqueTid utid =
353               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
354                                   static_cast<uint32_t>(tinfo.pid));
355           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
356           slices->Begin(ts, track_id, cat, name, std::move(insert_args));
357           break;
358         }
359         case kDurationEnd: {
360           UniqueTid utid =
361               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
362                                   static_cast<uint32_t>(tinfo.pid));
363           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
364           // TODO(b/131181693): |cat| and |name| are not passed here so
365           // that if two slices end at the same timestep, the slices get
366           // closed in the correct order regardless of which end event is
367           // processed first.
368           slices->End(ts, track_id, {}, {}, std::move(insert_args));
369           break;
370         }
371         case kDurationComplete: {
372           int64_t end_ts;
373           if (!cursor.ReadTimestamp(fr.get_ticks_per_second(), &end_ts)) {
374             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
375             return;
376           }
377           int64_t duration = end_ts - ts;
378           if (duration < 0) {
379             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
380             return;
381           }
382           UniqueTid utid =
383               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
384                                   static_cast<uint32_t>(tinfo.pid));
385           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
386           slices->Scoped(ts, track_id, cat, name, duration,
387                          std::move(insert_args));
388           break;
389         }
390         case kAsyncBegin: {
391           int64_t correlation_id;
392           if (!cursor.ReadInt64(&correlation_id)) {
393             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
394             return;
395           }
396           UniquePid upid =
397               procs->GetOrCreateProcess(static_cast<uint32_t>(tinfo.pid));
398           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
399               name, upid, correlation_id);
400           slices->Begin(ts, track_id, cat, name, std::move(insert_args));
401           break;
402         }
403         case kAsyncInstant: {
404           int64_t correlation_id;
405           if (!cursor.ReadInt64(&correlation_id)) {
406             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
407             return;
408           }
409           UniquePid upid =
410               procs->GetOrCreateProcess(static_cast<uint32_t>(tinfo.pid));
411           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
412               name, upid, correlation_id);
413           slices->Scoped(ts, track_id, cat, name, 0, std::move(insert_args));
414           break;
415         }
416         case kAsyncEnd: {
417           int64_t correlation_id;
418           if (!cursor.ReadInt64(&correlation_id)) {
419             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
420             return;
421           }
422           UniquePid upid =
423               procs->GetOrCreateProcess(static_cast<uint32_t>(tinfo.pid));
424           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
425               name, upid, correlation_id);
426           slices->End(ts, track_id, cat, name, std::move(insert_args));
427           break;
428         }
429         case kFlowBegin: {
430           uint64_t correlation_id;
431           if (!cursor.ReadUint64(&correlation_id)) {
432             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
433             return;
434           }
435           UniqueTid utid =
436               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
437                                   static_cast<uint32_t>(tinfo.pid));
438           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
439           context_->flow_tracker->Begin(track_id, correlation_id);
440           break;
441         }
442         case kFlowStep: {
443           uint64_t correlation_id;
444           if (!cursor.ReadUint64(&correlation_id)) {
445             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
446             return;
447           }
448           UniqueTid utid =
449               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
450                                   static_cast<uint32_t>(tinfo.pid));
451           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
452           context_->flow_tracker->Step(track_id, correlation_id);
453           break;
454         }
455         case kFlowEnd: {
456           uint64_t correlation_id;
457           if (!cursor.ReadUint64(&correlation_id)) {
458             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
459             return;
460           }
461           UniqueTid utid =
462               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
463                                   static_cast<uint32_t>(tinfo.pid));
464           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
465           context_->flow_tracker->End(track_id, correlation_id, true, true);
466           break;
467         }
468       }
469       break;
470     }
471     default: {
472       PERFETTO_DFATAL("Unknown record type %d in FuchsiaTraceParser",
473                       record_type);
474       break;
475     }
476   }
477 }
478 
479 }  // namespace trace_processor
480 }  // namespace perfetto
481