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