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