xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/perf/perf_tracker.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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/perf/perf_tracker.h"
18 
19 #include <cstdint>
20 #include <limits>
21 #include <memory>
22 #include <optional>
23 
24 #include "perfetto/ext/base/flat_hash_map.h"
25 #include "src/trace_processor/importers/common/address_range.h"
26 #include "src/trace_processor/importers/common/mapping_tracker.h"
27 #include "src/trace_processor/importers/common/virtual_memory_mapping.h"
28 #include "src/trace_processor/importers/perf/aux_data_tokenizer.h"
29 #include "src/trace_processor/importers/perf/perf_event.h"
30 #include "src/trace_processor/importers/perf/spe_tokenizer.h"
31 #include "src/trace_processor/storage/trace_storage.h"
32 
33 namespace perfetto::trace_processor::perf_importer {
34 namespace {
35 
36 using third_party::simpleperf::proto::pbzero::FileFeature;
37 using DexFile = FileFeature::DexFile;
38 using ElfFile = FileFeature::ElfFile;
39 using KernelModule = FileFeature::KernelModule;
40 using DsoType = FileFeature::DsoType;
41 using Symbol = FileFeature::Symbol;
42 
InsertSymbols(const FileFeature::Decoder & file,AddressRangeMap<std::string> & out)43 void InsertSymbols(const FileFeature::Decoder& file,
44                    AddressRangeMap<std::string>& out) {
45   for (auto raw_symbol = file.symbol(); raw_symbol; ++raw_symbol) {
46     Symbol::Decoder symbol(*raw_symbol);
47     out.TrimOverlapsAndEmplace(
48         AddressRange::FromStartAndSize(symbol.vaddr(), symbol.len()),
49         symbol.name().ToStdString());
50   }
51 }
52 
IsBpfMapping(const CreateMappingParams & params)53 bool IsBpfMapping(const CreateMappingParams& params) {
54   return params.name == "[bpf]";
55 }
56 
57 }  // namespace
58 
PerfTracker(TraceProcessorContext * context)59 PerfTracker::PerfTracker(TraceProcessorContext* context)
60     : context_(context),
61       mapping_table_(context->storage->stack_profile_mapping_table()) {
62   RegisterAuxTokenizer(PERF_AUXTRACE_ARM_SPE, &SpeTokenizer::Create);
63 }
64 
65 PerfTracker::~PerfTracker() = default;
66 
67 base::StatusOr<std::unique_ptr<AuxDataTokenizer>>
CreateAuxDataTokenizer(AuxtraceInfoRecord info)68 PerfTracker::CreateAuxDataTokenizer(AuxtraceInfoRecord info) {
69   auto it = factories_.Find(info.type);
70   if (!it) {
71     return std::unique_ptr<AuxDataTokenizer>(
72         new DummyAuxDataTokenizer(context_));
73   }
74 
75   return (*it)(context_, std::move(info));
76 }
77 
AddSimpleperfFile2(const FileFeature::Decoder & file)78 void PerfTracker::AddSimpleperfFile2(const FileFeature::Decoder& file) {
79   Dso dso;
80   switch (file.type()) {
81     case DsoType::DSO_KERNEL:
82       InsertSymbols(file, kernel_symbols_);
83       return;
84 
85     case DsoType::DSO_ELF_FILE: {
86       ElfFile::Decoder elf(file.elf_file());
87       dso.load_bias = file.min_vaddr() - elf.file_offset_of_min_vaddr();
88       break;
89     }
90 
91     case DsoType::DSO_KERNEL_MODULE: {
92       KernelModule::Decoder module(file.kernel_module());
93       dso.load_bias = file.min_vaddr() - module.memory_offset_of_min_vaddr();
94       break;
95     }
96 
97     case DsoType::DSO_DEX_FILE:
98     case DsoType::DSO_SYMBOL_MAP_FILE:
99     case DsoType::DSO_UNKNOWN_FILE:
100     default:
101       return;
102   }
103 
104   InsertSymbols(file, dso.symbols);
105   files_.Insert(context_->storage->InternString(file.path()), std::move(dso));
106 }
107 
SymbolizeFrames()108 void PerfTracker::SymbolizeFrames() {
109   const StringId kEmptyString = context_->storage->InternString("");
110   for (auto frame = context_->storage->mutable_stack_profile_frame_table()
111                         ->IterateRows();
112        frame; ++frame) {
113     if (frame.name() != kNullStringId && frame.name() != kEmptyString) {
114       continue;
115     }
116 
117     if (!TrySymbolizeFrame(frame.row_reference())) {
118       SymbolizeKernelFrame(frame.row_reference());
119     }
120   }
121 }
122 
SymbolizeKernelFrame(tables::StackProfileFrameTable::RowReference frame)123 void PerfTracker::SymbolizeKernelFrame(
124     tables::StackProfileFrameTable::RowReference frame) {
125   const auto mapping = *mapping_table_.FindById(frame.mapping());
126   uint64_t address = static_cast<uint64_t>(frame.rel_pc()) +
127                      static_cast<uint64_t>(mapping.start());
128   auto symbol = kernel_symbols_.Find(address);
129   if (symbol == kernel_symbols_.end()) {
130     return;
131   }
132   frame.set_name(
133       context_->storage->InternString(base::StringView(symbol->second)));
134 }
135 
TrySymbolizeFrame(tables::StackProfileFrameTable::RowReference frame)136 bool PerfTracker::TrySymbolizeFrame(
137     tables::StackProfileFrameTable::RowReference frame) {
138   const auto mapping = *mapping_table_.FindById(frame.mapping());
139   auto* file = files_.Find(mapping.name());
140   if (!file) {
141     return false;
142   }
143 
144   // Load bias is something we can only determine by looking at the actual elf
145   // file. Thus PERF_RECORD_MMAP{2} events do not record it. So we need to
146   // potentially do an adjustment here if the load_bias tracked in the mapping
147   // table and the one reported by the file are mismatched.
148   uint64_t adj = file->load_bias - static_cast<uint64_t>(mapping.load_bias());
149 
150   auto symbol = file->symbols.Find(static_cast<uint64_t>(frame.rel_pc()) + adj);
151   if (symbol == file->symbols.end()) {
152     return false;
153   }
154   frame.set_name(
155       context_->storage->InternString(base::StringView(symbol->second)));
156   return true;
157 }
158 
CreateKernelMemoryMapping(int64_t trace_ts,CreateMappingParams params)159 void PerfTracker::CreateKernelMemoryMapping(int64_t trace_ts,
160                                             CreateMappingParams params) {
161   // Ignore BPF mapping that spans the entire memory range
162   if (IsBpfMapping(params) &&
163       params.memory_range.size() == std::numeric_limits<uint64_t>::max()) {
164     return;
165   }
166   const KernelMemoryMapping* mapping =
167       &context_->mapping_tracker->CreateKernelMemoryMapping(std::move(params));
168 
169   context_->storage->mutable_mmap_record_table()->Insert(
170       {trace_ts, std::nullopt, mapping->mapping_id()});
171 }
172 
CreateUserMemoryMapping(int64_t trace_ts,UniquePid upid,CreateMappingParams params)173 void PerfTracker::CreateUserMemoryMapping(int64_t trace_ts,
174                                           UniquePid upid,
175                                           CreateMappingParams params) {
176   const UserMemoryMapping* mapping =
177       &context_->mapping_tracker->CreateUserMemoryMapping(upid,
178                                                           std::move(params));
179 
180   context_->storage->mutable_mmap_record_table()->Insert(
181       {trace_ts, upid, mapping->mapping_id()});
182 }
183 
NotifyEndOfFile()184 void PerfTracker::NotifyEndOfFile() {
185   SymbolizeFrames();
186 }
187 
RegisterAuxTokenizer(uint32_t type,AuxDataTokenizerFactory factory)188 void PerfTracker::RegisterAuxTokenizer(uint32_t type,
189                                        AuxDataTokenizerFactory factory) {
190   PERFETTO_CHECK(factories_.Insert(type, std::move(factory)).second);
191 }
192 
193 }  // namespace perfetto::trace_processor::perf_importer
194