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