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