• 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           InstantId id = context_->event_tracker->PushInstant(
266               ts, name, utid, RefType::kRefUtid);
267           auto inserter = context_->args_tracker->AddArgsTo(id);
268           for (const Arg& arg : args) {
269             inserter.AddArg(
270                 arg.name, arg.value.ToStorageVariadic(context_->storage.get()));
271           }
272           context_->args_tracker->Flush();
273           break;
274         }
275         case kCounter: {
276           UniqueTid utid =
277               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
278                                   static_cast<uint32_t>(tinfo.pid));
279           std::string name_str =
280               context_->storage->GetString(name).ToStdString();
281           // Note: In the Fuchsia trace format, counter values are stored in the
282           // arguments for the record, with the data series defined by both the
283           // record name and the argument name. In Perfetto, counters only have
284           // one name, so we combine both names into one here.
285           for (const Arg& arg : args) {
286             std::string counter_name_str = name_str + ":";
287             counter_name_str +=
288                 context_->storage->GetString(arg.name).ToStdString();
289             bool is_valid_value = false;
290             double counter_value = -1;
291             switch (arg.value.Type()) {
292               case fuchsia_trace_utils::ArgValue::kInt32:
293                 is_valid_value = true;
294                 counter_value = static_cast<double>(arg.value.Int32());
295                 break;
296               case fuchsia_trace_utils::ArgValue::kUint32:
297                 is_valid_value = true;
298                 counter_value = static_cast<double>(arg.value.Uint32());
299                 break;
300               case fuchsia_trace_utils::ArgValue::kInt64:
301                 is_valid_value = true;
302                 counter_value = static_cast<double>(arg.value.Int64());
303                 break;
304               case fuchsia_trace_utils::ArgValue::kUint64:
305                 is_valid_value = true;
306                 counter_value = static_cast<double>(arg.value.Uint64());
307                 break;
308               case fuchsia_trace_utils::ArgValue::kDouble:
309                 is_valid_value = true;
310                 counter_value = arg.value.Double();
311                 break;
312               case fuchsia_trace_utils::ArgValue::kNull:
313               case fuchsia_trace_utils::ArgValue::kString:
314               case fuchsia_trace_utils::ArgValue::kPointer:
315               case fuchsia_trace_utils::ArgValue::kKoid:
316               case fuchsia_trace_utils::ArgValue::kUnknown:
317                 context_->storage->IncrementStats(
318                     stats::fuchsia_non_numeric_counters);
319                 break;
320             }
321             if (is_valid_value) {
322               StringId counter_name_id = context_->storage->InternString(
323                   base::StringView(counter_name_str));
324               TrackId track = context_->track_tracker->InternThreadCounterTrack(
325                   counter_name_id, utid);
326               context_->event_tracker->PushCounter(ts, counter_value, track);
327             }
328           }
329           break;
330         }
331         case kDurationBegin: {
332           UniqueTid utid =
333               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
334                                   static_cast<uint32_t>(tinfo.pid));
335           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
336           slices->Begin(ts, track_id, cat, name, insert_args);
337           break;
338         }
339         case kDurationEnd: {
340           UniqueTid utid =
341               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
342                                   static_cast<uint32_t>(tinfo.pid));
343           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
344           // TODO(b/131181693): |cat| and |name| are not passed here so that
345           // if two slices end at the same timestep, the slices get closed in
346           // the correct order regardless of which end event is processed first.
347           slices->End(ts, track_id, {}, {}, insert_args);
348           break;
349         }
350         case kDurationComplete: {
351           int64_t end_ts;
352           if (!cursor.ReadTimestamp(record->get_ticks_per_second(), &end_ts)) {
353             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
354             return;
355           }
356           int64_t duration = end_ts - ts;
357           if (duration < 0) {
358             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
359             return;
360           }
361           UniqueTid utid =
362               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
363                                   static_cast<uint32_t>(tinfo.pid));
364           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
365           slices->Scoped(ts, track_id, cat, name, duration, insert_args);
366           break;
367         }
368         case kAsyncBegin: {
369           int64_t correlation_id;
370           if (!cursor.ReadInt64(&correlation_id)) {
371             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
372             return;
373           }
374           UniquePid upid =
375               procs->GetOrCreateProcess(static_cast<uint32_t>(tinfo.pid));
376           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
377               name, upid, correlation_id);
378           slices->Begin(ts, track_id, cat, name, insert_args);
379           break;
380         }
381         case kAsyncInstant: {
382           // TODO(eseckler): Consider storing these instants as 0-duration
383           // slices instead, so that they get nested underneath begin/end
384           // slices.
385           int64_t correlation_id;
386           if (!cursor.ReadInt64(&correlation_id)) {
387             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
388             return;
389           }
390           UniquePid upid =
391               procs->GetOrCreateProcess(static_cast<uint32_t>(tinfo.pid));
392           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
393               name, upid, correlation_id);
394           InstantId id = context_->event_tracker->PushInstant(
395               ts, name, track_id.value, RefType::kRefTrack);
396           auto inserter = context_->args_tracker->AddArgsTo(id);
397           for (const Arg& arg : args) {
398             inserter.AddArg(
399                 arg.name, arg.name,
400                 arg.value.ToStorageVariadic(context_->storage.get()));
401           }
402           context_->args_tracker->Flush();
403           break;
404         }
405         case kAsyncEnd: {
406           int64_t correlation_id;
407           if (!cursor.ReadInt64(&correlation_id)) {
408             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
409             return;
410           }
411           UniquePid upid =
412               procs->GetOrCreateProcess(static_cast<uint32_t>(tinfo.pid));
413           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
414               name, upid, correlation_id);
415           slices->End(ts, track_id, cat, name, insert_args);
416           break;
417         }
418         case kFlowBegin: {
419           uint64_t correlation_id;
420           if (!cursor.ReadUint64(&correlation_id)) {
421             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
422             return;
423           }
424           UniqueTid utid =
425               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
426                                   static_cast<uint32_t>(tinfo.pid));
427           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
428           context_->flow_tracker->Begin(track_id, correlation_id);
429           break;
430         }
431         case kFlowStep: {
432           uint64_t correlation_id;
433           if (!cursor.ReadUint64(&correlation_id)) {
434             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
435             return;
436           }
437           UniqueTid utid =
438               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
439                                   static_cast<uint32_t>(tinfo.pid));
440           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
441           context_->flow_tracker->Step(track_id, correlation_id);
442           break;
443         }
444         case kFlowEnd: {
445           uint64_t correlation_id;
446           if (!cursor.ReadUint64(&correlation_id)) {
447             context_->storage->IncrementStats(stats::fuchsia_invalid_event);
448             return;
449           }
450           UniqueTid utid =
451               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
452                                   static_cast<uint32_t>(tinfo.pid));
453           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
454           context_->flow_tracker->End(track_id, correlation_id, true, true);
455           break;
456         }
457       }
458       break;
459     }
460     default: {
461       PERFETTO_DFATAL("Unknown record type %d in FuchsiaTraceParser",
462                       record_type);
463       break;
464     }
465   }
466 }
467 
468 }  // namespace trace_processor
469 }  // namespace perfetto
470