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