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