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