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