1 /*
2 * Copyright (C) 2024 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/instruments/row_parser.h"
18
19 #include "perfetto/ext/base/flat_hash_map.h"
20 #include "perfetto/ext/base/string_view.h"
21 #include "src/trace_processor/importers/common/mapping_tracker.h"
22 #include "src/trace_processor/importers/common/process_tracker.h"
23 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
24 #include "src/trace_processor/importers/instruments/row.h"
25 #include "src/trace_processor/importers/instruments/row_data_tracker.h"
26
27 #if !PERFETTO_BUILDFLAG(PERFETTO_TP_INSTRUMENTS)
28 #error \
29 "This file should not be built when enable_perfetto_trace_processor_mac_instruments=false"
30 #endif
31
32 namespace perfetto::trace_processor::instruments_importer {
33
RowParser(TraceProcessorContext * context)34 RowParser::RowParser(TraceProcessorContext* context)
35 : context_(context), data_(RowDataTracker::GetOrCreate(context)) {}
36
ParseInstrumentsRow(int64_t ts,instruments_importer::Row row)37 void RowParser::ParseInstrumentsRow(int64_t ts, instruments_importer::Row row) {
38 if (!row.backtrace) {
39 return;
40 }
41
42 Thread* thread = data_.GetThread(row.thread);
43 Process* process = data_.GetProcess(thread->process);
44 uint32_t tid = static_cast<uint32_t>(thread->tid);
45 uint32_t pid = static_cast<uint32_t>(process->pid);
46
47 UniqueTid utid = context_->process_tracker->UpdateThread(tid, pid);
48 UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
49
50 // TODO(leszeks): Avoid setting thread/process name if we've already seen this
51 // Thread* / Process*.
52 context_->process_tracker->UpdateThreadNameByUtid(utid, thread->fmt,
53 ThreadNamePriority::kOther);
54 context_->process_tracker->SetProcessNameIfUnset(upid, process->fmt);
55
56 auto& stack_profile_tracker = *context_->stack_profile_tracker;
57
58 Backtrace* backtrace = data_.GetBacktrace(row.backtrace);
59 std::optional<CallsiteId> parent;
60 uint32_t depth = 0;
61 auto leaf = backtrace->frames.rend() - 1;
62 for (auto it = backtrace->frames.rbegin(); it != backtrace->frames.rend();
63 ++it) {
64 Frame* frame = data_.GetFrame(*it);
65 Binary* binary = data_.GetBinary(frame->binary);
66
67 uint64_t rel_pc = static_cast<uint64_t>(frame->addr);
68 if (frame->binary) {
69 rel_pc -= static_cast<uint64_t>(binary->load_addr);
70 }
71
72 // For non-leaf functions, the pc will be after the end of the call. Adjust
73 // it to be within the call instruction.
74 if (rel_pc != 0 && it != leaf) {
75 --rel_pc;
76 }
77
78 auto frame_inserted = frame_to_frame_id_.Insert(*it, FrameId{0});
79 if (frame_inserted.second) {
80 auto mapping_inserted = binary_to_mapping_.Insert(frame->binary, nullptr);
81 if (mapping_inserted.second) {
82 if (binary == nullptr) {
83 *mapping_inserted.first = GetDummyMapping(upid);
84 } else {
85 BuildId build_id = binary->uuid;
86 *mapping_inserted.first =
87 &context_->mapping_tracker->CreateUserMemoryMapping(
88 upid, {AddressRange(static_cast<uint64_t>(binary->load_addr),
89 static_cast<uint64_t>(binary->max_addr)),
90 0, 0, 0, binary->path, build_id});
91 }
92 }
93 VirtualMemoryMapping* mapping = *mapping_inserted.first;
94
95 // Intern the frame with no function name -- the symbolizer will annotate
96 // frames later.
97 *frame_inserted.first =
98 mapping->InternFrame(rel_pc, base::StringView(""));
99 }
100 FrameId frame_id = *frame_inserted.first;
101
102 parent = stack_profile_tracker.InternCallsite(parent, frame_id, depth);
103 depth++;
104 }
105
106 context_->storage->mutable_instruments_sample_table()->Insert(
107 {ts, utid, row.core_id, parent});
108 }
109
GetDummyMapping(UniquePid upid)110 DummyMemoryMapping* RowParser::GetDummyMapping(UniquePid upid) {
111 if (auto it = dummy_mappings_.Find(upid); it) {
112 return *it;
113 }
114
115 DummyMemoryMapping* mapping =
116 &context_->mapping_tracker->CreateDummyMapping("");
117 dummy_mappings_.Insert(upid, mapping);
118 return mapping;
119 }
120
121 } // namespace perfetto::trace_processor::instruments_importer
122