xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/stack_profile_sequence_state.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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/proto/stack_profile_sequence_state.h"
18 
19 #include <cstdint>
20 #include <optional>
21 #include <utility>
22 #include <vector>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/ext/base/string_utils.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
28 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
29 #include "src/trace_processor/importers/common/address_range.h"
30 #include "src/trace_processor/importers/common/mapping_tracker.h"
31 #include "src/trace_processor/importers/common/process_tracker.h"
32 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
33 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
34 #include "src/trace_processor/importers/proto/profile_packet_utils.h"
35 #include "src/trace_processor/storage/stats.h"
36 #include "src/trace_processor/storage/trace_storage.h"
37 #include "src/trace_processor/types/trace_processor_context.h"
38 #include "src/trace_processor/util/build_id.h"
39 
40 namespace perfetto {
41 namespace trace_processor {
42 namespace {
ToStringView(protozero::ConstBytes bytes)43 base::StringView ToStringView(protozero::ConstBytes bytes) {
44   return base::StringView(reinterpret_cast<const char*>(bytes.data),
45                           bytes.size);
46 }
47 
48 // Determine wether this is the magical kernel mapping created in
49 // `perfetto::::profiling::Unwinder::SymbolizeKernelCallchain`
IsMagicalKernelMapping(const CreateMappingParams & params)50 bool IsMagicalKernelMapping(const CreateMappingParams& params) {
51   return params.memory_range.start() == 0 &&
52          params.memory_range.length() == 0 && params.exact_offset == 0 &&
53          !params.build_id.has_value() && (params.name == "/kernel");
54 }
55 
56 }  // namespace
57 
StackProfileSequenceState(TraceProcessorContext * context)58 StackProfileSequenceState::StackProfileSequenceState(
59     TraceProcessorContext* context)
60     : context_(context) {}
61 
62 StackProfileSequenceState::~StackProfileSequenceState() = default;
63 
FindOrInsertMapping(uint64_t iid)64 VirtualMemoryMapping* StackProfileSequenceState::FindOrInsertMapping(
65     uint64_t iid) {
66   if (pid_and_tid_valid()) {
67     return FindOrInsertMappingImpl(
68         context_->process_tracker->GetOrCreateProcess(
69             static_cast<uint32_t>(pid())),
70         iid);
71   }
72 
73   return FindOrInsertMappingImpl(std::nullopt, iid);
74 }
75 
FindOrInsertMappingImpl(std::optional<UniquePid> upid,uint64_t iid)76 VirtualMemoryMapping* StackProfileSequenceState::FindOrInsertMappingImpl(
77     std::optional<UniquePid> upid,
78     uint64_t iid) {
79   if (auto ptr = cached_mappings_.Find({upid, iid}); ptr) {
80     return *ptr;
81   }
82   auto* decoder =
83       LookupInternedMessage<protos::pbzero::InternedData::kMappingsFieldNumber,
84                             protos::pbzero::Mapping>(iid);
85   if (!decoder) {
86     context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
87     return nullptr;
88   }
89 
90   std::vector<base::StringView> path_components;
91   for (auto it = decoder->path_string_ids(); it; ++it) {
92     std::optional<base::StringView> str = LookupInternedMappingPath(*it);
93     if (!str) {
94       // For backward compatibility reasons we do not return an error but
95       // instead stop adding path components.
96       break;
97     }
98     path_components.push_back(*str);
99   }
100 
101   CreateMappingParams params;
102   std::optional<base::StringView> build_id =
103       LookupInternedBuildId(decoder->build_id());
104   if (!build_id) {
105     return nullptr;
106   }
107   if (!build_id->empty()) {
108     params.build_id = BuildId::FromRaw(*build_id);
109   }
110 
111   params.memory_range = AddressRange(decoder->start(), decoder->end());
112   params.exact_offset = decoder->exact_offset();
113   params.start_offset = decoder->start_offset();
114   params.load_bias = decoder->load_bias();
115   params.name = ProfilePacketUtils::MakeMappingName(path_components);
116 
117   VirtualMemoryMapping* mapping;
118 
119   if (IsMagicalKernelMapping(params)) {
120     mapping = &context_->mapping_tracker->CreateKernelMemoryMapping(
121         std::move(params));
122     // A lot of tests to not set a proper mapping range
123     // Dummy mappings can also be emitted (e.g. for errors during unwinding)
124   } else if (params.memory_range.empty()) {
125     mapping =
126         &context_->mapping_tracker->InternMemoryMapping(std::move(params));
127   } else if (upid.has_value()) {
128     mapping = &context_->mapping_tracker->CreateUserMemoryMapping(
129         *upid, std::move(params));
130   } else {
131     mapping =
132         &context_->mapping_tracker->InternMemoryMapping(std::move(params));
133   }
134 
135   cached_mappings_.Insert({upid, iid}, mapping);
136   return mapping;
137 }
138 
139 std::optional<base::StringView>
LookupInternedBuildId(uint64_t iid)140 StackProfileSequenceState::LookupInternedBuildId(uint64_t iid) {
141   // This should really be an error (value not set) or at the very least return
142   // a null string, but for backward compatibility use an empty string instead.
143   if (iid == 0) {
144     return "";
145   }
146   auto* decoder =
147       LookupInternedMessage<protos::pbzero::InternedData::kBuildIdsFieldNumber,
148                             protos::pbzero::InternedString>(iid);
149   if (!decoder) {
150     context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
151     return std::nullopt;
152   }
153 
154   return ToStringView(decoder->str());
155 }
156 
157 std::optional<base::StringView>
LookupInternedMappingPath(uint64_t iid)158 StackProfileSequenceState::LookupInternedMappingPath(uint64_t iid) {
159   auto* decoder = LookupInternedMessage<
160       protos::pbzero::InternedData::kMappingPathsFieldNumber,
161       protos::pbzero::InternedString>(iid);
162   if (!decoder) {
163     context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
164     return std::nullopt;
165   }
166 
167   return ToStringView(decoder->str());
168 }
169 
FindOrInsertCallstack(UniquePid upid,uint64_t iid)170 std::optional<CallsiteId> StackProfileSequenceState::FindOrInsertCallstack(
171     UniquePid upid,
172     uint64_t iid) {
173   if (CallsiteId* id = cached_callstacks_.Find({upid, iid}); id) {
174     return *id;
175   }
176   auto* decoder = LookupInternedMessage<
177       protos::pbzero::InternedData::kCallstacksFieldNumber,
178       protos::pbzero::Callstack>(iid);
179   if (!decoder) {
180     context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
181     return std::nullopt;
182   }
183 
184   std::optional<CallsiteId> parent_callsite_id;
185   uint32_t depth = 0;
186   for (auto it = decoder->frame_ids(); it; ++it) {
187     std::optional<FrameId> frame_id = FindOrInsertFrame(upid, *it);
188     if (!frame_id) {
189       return std::nullopt;
190     }
191     parent_callsite_id = context_->stack_profile_tracker->InternCallsite(
192         parent_callsite_id, *frame_id, depth);
193     ++depth;
194   }
195 
196   if (!parent_callsite_id) {
197     context_->storage->IncrementStats(stats::stackprofile_empty_callstack);
198     return std::nullopt;
199   }
200 
201   cached_callstacks_.Insert({upid, iid}, *parent_callsite_id);
202 
203   return parent_callsite_id;
204 }
205 
FindOrInsertFrame(UniquePid upid,uint64_t iid)206 std::optional<FrameId> StackProfileSequenceState::FindOrInsertFrame(
207     UniquePid upid,
208     uint64_t iid) {
209   if (FrameId* id = cached_frames_.Find({upid, iid}); id) {
210     return *id;
211   }
212   auto* decoder =
213       LookupInternedMessage<protos::pbzero::InternedData::kFramesFieldNumber,
214                             protos::pbzero::Frame>(iid);
215   if (!decoder) {
216     context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
217     return std::nullopt;
218   }
219 
220   VirtualMemoryMapping* mapping =
221       FindOrInsertMappingImpl(upid, decoder->mapping_id());
222   if (!mapping) {
223     return std::nullopt;
224   }
225 
226   base::StringView function_name;
227   if (decoder->function_name_id() != 0) {
228     std::optional<base::StringView> func =
229         LookupInternedFunctionName(decoder->function_name_id());
230     if (!func) {
231       return std::nullopt;
232     }
233     function_name = *func;
234   }
235 
236   FrameId frame_id = mapping->InternFrame(decoder->rel_pc(), function_name);
237   if (!mapping->is_jitted()) {
238     cached_frames_.Insert({upid, iid}, frame_id);
239   }
240 
241   return frame_id;
242 }
243 
244 std::optional<base::StringView>
LookupInternedFunctionName(uint64_t iid)245 StackProfileSequenceState::LookupInternedFunctionName(uint64_t iid) {
246   // This should really be an error (value not set) or at the very least return
247   // a null string, but for backward compatibility use an empty string instead.
248   if (iid == 0) {
249     return "";
250   }
251   auto* decoder = LookupInternedMessage<
252       protos::pbzero::InternedData::kFunctionNamesFieldNumber,
253       protos::pbzero::InternedString>(iid);
254   if (!decoder) {
255     context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
256     return std::nullopt;
257   }
258 
259   return ToStringView(decoder->str());
260 }
261 
262 }  // namespace trace_processor
263 }  // namespace perfetto
264