xref: /aosp_15_r20/external/perfetto/src/profiling/perf/unwinding.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/perf/unwinding.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
20*6dbdd20aSAndroid Build Coastguard Worker #include <mutex>
21*6dbdd20aSAndroid Build Coastguard Worker 
22*6dbdd20aSAndroid Build Coastguard Worker #include <unwindstack/Unwinder.h>
23*6dbdd20aSAndroid Build Coastguard Worker 
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/metatrace.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/no_destructor.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_utils.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/perf/frame_pointer_unwinder.h"
29*6dbdd20aSAndroid Build Coastguard Worker 
30*6dbdd20aSAndroid Build Coastguard Worker namespace {
31*6dbdd20aSAndroid Build Coastguard Worker constexpr size_t kUnwindingMaxFrames = 1000;
32*6dbdd20aSAndroid Build Coastguard Worker constexpr uint32_t kDataSourceShutdownRetryDelayMs = 400;
33*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
34*6dbdd20aSAndroid Build Coastguard Worker 
35*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
36*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
37*6dbdd20aSAndroid Build Coastguard Worker 
38*6dbdd20aSAndroid Build Coastguard Worker Unwinder::Delegate::~Delegate() = default;
39*6dbdd20aSAndroid Build Coastguard Worker 
Unwinder(Delegate * delegate,base::UnixTaskRunner * task_runner)40*6dbdd20aSAndroid Build Coastguard Worker Unwinder::Unwinder(Delegate* delegate, base::UnixTaskRunner* task_runner)
41*6dbdd20aSAndroid Build Coastguard Worker     : task_runner_(task_runner), delegate_(delegate) {
42*6dbdd20aSAndroid Build Coastguard Worker   ResetAndEnableUnwindstackCache();
43*6dbdd20aSAndroid Build Coastguard Worker   base::MaybeSetThreadName("stack-unwinding");
44*6dbdd20aSAndroid Build Coastguard Worker }
45*6dbdd20aSAndroid Build Coastguard Worker 
PostStartDataSource(DataSourceInstanceID ds_id,bool kernel_frames,UnwindMode unwind_mode)46*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostStartDataSource(DataSourceInstanceID ds_id,
47*6dbdd20aSAndroid Build Coastguard Worker                                    bool kernel_frames,
48*6dbdd20aSAndroid Build Coastguard Worker                                    UnwindMode unwind_mode) {
49*6dbdd20aSAndroid Build Coastguard Worker   // No need for a weak pointer as the associated task runner quits (stops
50*6dbdd20aSAndroid Build Coastguard Worker   // running tasks) strictly before the Unwinder's destruction.
51*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostTask([this, ds_id, kernel_frames, unwind_mode] {
52*6dbdd20aSAndroid Build Coastguard Worker     StartDataSource(ds_id, kernel_frames, unwind_mode);
53*6dbdd20aSAndroid Build Coastguard Worker   });
54*6dbdd20aSAndroid Build Coastguard Worker }
55*6dbdd20aSAndroid Build Coastguard Worker 
StartDataSource(DataSourceInstanceID ds_id,bool kernel_frames,UnwindMode unwind_mode)56*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::StartDataSource(DataSourceInstanceID ds_id,
57*6dbdd20aSAndroid Build Coastguard Worker                                bool kernel_frames,
58*6dbdd20aSAndroid Build Coastguard Worker                                UnwindMode unwind_mode) {
59*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
60*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwinder::StartDataSource(%zu)", static_cast<size_t>(ds_id));
61*6dbdd20aSAndroid Build Coastguard Worker 
62*6dbdd20aSAndroid Build Coastguard Worker   auto it_and_inserted =
63*6dbdd20aSAndroid Build Coastguard Worker       data_sources_.emplace(ds_id, DataSourceState{unwind_mode});
64*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(it_and_inserted.second);
65*6dbdd20aSAndroid Build Coastguard Worker 
66*6dbdd20aSAndroid Build Coastguard Worker   if (kernel_frames) {
67*6dbdd20aSAndroid Build Coastguard Worker     kernel_symbolizer_.GetOrCreateKernelSymbolMap();
68*6dbdd20aSAndroid Build Coastguard Worker   }
69*6dbdd20aSAndroid Build Coastguard Worker }
70*6dbdd20aSAndroid Build Coastguard Worker 
71*6dbdd20aSAndroid Build Coastguard Worker // c++11: use shared_ptr to transfer resource handles, so that the resources get
72*6dbdd20aSAndroid Build Coastguard Worker // released even if the task runner is destroyed with pending tasks.
73*6dbdd20aSAndroid Build Coastguard Worker // "Cleverness" warning:
74*6dbdd20aSAndroid Build Coastguard Worker // the task will be executed on a different thread, and will mutate the
75*6dbdd20aSAndroid Build Coastguard Worker // pointed-to memory. It may be the case that this posting thread will not
76*6dbdd20aSAndroid Build Coastguard Worker // decrement its shared_ptr refcount until *after* the task has executed. In
77*6dbdd20aSAndroid Build Coastguard Worker // that scenario, the destruction of the pointed-to memory will be happening on
78*6dbdd20aSAndroid Build Coastguard Worker // the posting thread. This implies a data race between the mutation on the task
79*6dbdd20aSAndroid Build Coastguard Worker // thread, and the destruction on the posting thread. *However*, we assume that
80*6dbdd20aSAndroid Build Coastguard Worker // there is no race in practice due to refcount decrements having
81*6dbdd20aSAndroid Build Coastguard Worker // release-acquire semantics. The refcount decrements pair with each other, and
82*6dbdd20aSAndroid Build Coastguard Worker // therefore also serve as a memory barrier between the destructor, and any
83*6dbdd20aSAndroid Build Coastguard Worker // previous modifications of the pointed-to memory.
84*6dbdd20aSAndroid Build Coastguard Worker // TODO(rsavitski): present a more convincing argument, or reimplement
85*6dbdd20aSAndroid Build Coastguard Worker // without relying on shared_ptr implementation details.
PostAdoptProcDescriptors(DataSourceInstanceID ds_id,pid_t pid,base::ScopedFile maps_fd,base::ScopedFile mem_fd)86*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostAdoptProcDescriptors(DataSourceInstanceID ds_id,
87*6dbdd20aSAndroid Build Coastguard Worker                                         pid_t pid,
88*6dbdd20aSAndroid Build Coastguard Worker                                         base::ScopedFile maps_fd,
89*6dbdd20aSAndroid Build Coastguard Worker                                         base::ScopedFile mem_fd) {
90*6dbdd20aSAndroid Build Coastguard Worker   auto shared_maps = std::make_shared<base::ScopedFile>(std::move(maps_fd));
91*6dbdd20aSAndroid Build Coastguard Worker   auto shared_mem = std::make_shared<base::ScopedFile>(std::move(mem_fd));
92*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostTask([this, ds_id, pid, shared_maps, shared_mem] {
93*6dbdd20aSAndroid Build Coastguard Worker     base::ScopedFile maps = std::move(*shared_maps.get());
94*6dbdd20aSAndroid Build Coastguard Worker     base::ScopedFile mem = std::move(*shared_mem.get());
95*6dbdd20aSAndroid Build Coastguard Worker     AdoptProcDescriptors(ds_id, pid, std::move(maps), std::move(mem));
96*6dbdd20aSAndroid Build Coastguard Worker   });
97*6dbdd20aSAndroid Build Coastguard Worker }
98*6dbdd20aSAndroid Build Coastguard Worker 
AdoptProcDescriptors(DataSourceInstanceID ds_id,pid_t pid,base::ScopedFile maps_fd,base::ScopedFile mem_fd)99*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::AdoptProcDescriptors(DataSourceInstanceID ds_id,
100*6dbdd20aSAndroid Build Coastguard Worker                                     pid_t pid,
101*6dbdd20aSAndroid Build Coastguard Worker                                     base::ScopedFile maps_fd,
102*6dbdd20aSAndroid Build Coastguard Worker                                     base::ScopedFile mem_fd) {
103*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
104*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwinder::AdoptProcDescriptors(%zu, %d, %d, %d)",
105*6dbdd20aSAndroid Build Coastguard Worker                 static_cast<size_t>(ds_id), static_cast<int>(pid),
106*6dbdd20aSAndroid Build Coastguard Worker                 maps_fd.get(), mem_fd.get());
107*6dbdd20aSAndroid Build Coastguard Worker 
108*6dbdd20aSAndroid Build Coastguard Worker   auto it = data_sources_.find(ds_id);
109*6dbdd20aSAndroid Build Coastguard Worker   if (it == data_sources_.end())
110*6dbdd20aSAndroid Build Coastguard Worker     return;
111*6dbdd20aSAndroid Build Coastguard Worker   DataSourceState& ds = it->second;
112*6dbdd20aSAndroid Build Coastguard Worker 
113*6dbdd20aSAndroid Build Coastguard Worker   ProcessState& proc_state = ds.process_states[pid];  // insert if new
114*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(proc_state.status == ProcessState::Status::kInitial ||
115*6dbdd20aSAndroid Build Coastguard Worker                   proc_state.status == ProcessState::Status::kFdsTimedOut);
116*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(!proc_state.unwind_state.has_value());
117*6dbdd20aSAndroid Build Coastguard Worker 
118*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_METATRACE_SCOPED(TAG_PRODUCER, PROFILER_MAPS_PARSE);
119*6dbdd20aSAndroid Build Coastguard Worker 
120*6dbdd20aSAndroid Build Coastguard Worker   proc_state.status = ProcessState::Status::kFdsResolved;
121*6dbdd20aSAndroid Build Coastguard Worker   proc_state.unwind_state =
122*6dbdd20aSAndroid Build Coastguard Worker       UnwindingMetadata{std::move(maps_fd), std::move(mem_fd)};
123*6dbdd20aSAndroid Build Coastguard Worker }
124*6dbdd20aSAndroid Build Coastguard Worker 
PostRecordTimedOutProcDescriptors(DataSourceInstanceID ds_id,pid_t pid)125*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostRecordTimedOutProcDescriptors(DataSourceInstanceID ds_id,
126*6dbdd20aSAndroid Build Coastguard Worker                                                  pid_t pid) {
127*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostTask([this, ds_id, pid] {
128*6dbdd20aSAndroid Build Coastguard Worker     UpdateProcessStateStatus(ds_id, pid, ProcessState::Status::kFdsTimedOut);
129*6dbdd20aSAndroid Build Coastguard Worker   });
130*6dbdd20aSAndroid Build Coastguard Worker }
131*6dbdd20aSAndroid Build Coastguard Worker 
PostRecordNoUserspaceProcess(DataSourceInstanceID ds_id,pid_t pid)132*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostRecordNoUserspaceProcess(DataSourceInstanceID ds_id,
133*6dbdd20aSAndroid Build Coastguard Worker                                             pid_t pid) {
134*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostTask([this, ds_id, pid] {
135*6dbdd20aSAndroid Build Coastguard Worker     UpdateProcessStateStatus(ds_id, pid, ProcessState::Status::kNoUserspace);
136*6dbdd20aSAndroid Build Coastguard Worker   });
137*6dbdd20aSAndroid Build Coastguard Worker }
138*6dbdd20aSAndroid Build Coastguard Worker 
UpdateProcessStateStatus(DataSourceInstanceID ds_id,pid_t pid,ProcessState::Status new_status)139*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::UpdateProcessStateStatus(DataSourceInstanceID ds_id,
140*6dbdd20aSAndroid Build Coastguard Worker                                         pid_t pid,
141*6dbdd20aSAndroid Build Coastguard Worker                                         ProcessState::Status new_status) {
142*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
143*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwinder::UpdateProcessStateStatus(%zu, %d, %d)",
144*6dbdd20aSAndroid Build Coastguard Worker                 static_cast<size_t>(ds_id), static_cast<int>(pid),
145*6dbdd20aSAndroid Build Coastguard Worker                 static_cast<int>(new_status));
146*6dbdd20aSAndroid Build Coastguard Worker 
147*6dbdd20aSAndroid Build Coastguard Worker   auto it = data_sources_.find(ds_id);
148*6dbdd20aSAndroid Build Coastguard Worker   if (it == data_sources_.end())
149*6dbdd20aSAndroid Build Coastguard Worker     return;
150*6dbdd20aSAndroid Build Coastguard Worker   DataSourceState& ds = it->second;
151*6dbdd20aSAndroid Build Coastguard Worker 
152*6dbdd20aSAndroid Build Coastguard Worker   ProcessState& proc_state = ds.process_states[pid];  // insert if new
153*6dbdd20aSAndroid Build Coastguard Worker   proc_state.status = new_status;
154*6dbdd20aSAndroid Build Coastguard Worker }
155*6dbdd20aSAndroid Build Coastguard Worker 
PostProcessQueue()156*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostProcessQueue() {
157*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostTask([this] { ProcessQueue(); });
158*6dbdd20aSAndroid Build Coastguard Worker }
159*6dbdd20aSAndroid Build Coastguard Worker 
160*6dbdd20aSAndroid Build Coastguard Worker // Note: we always walk the queue in order. So if there are multiple data
161*6dbdd20aSAndroid Build Coastguard Worker // sources, one of which is shutting down, its shutdown can be delayed by
162*6dbdd20aSAndroid Build Coastguard Worker // unwinding of other sources' samples. Instead, we could scan the queue
163*6dbdd20aSAndroid Build Coastguard Worker // multiple times, prioritizing the samples for shutting-down sources. At the
164*6dbdd20aSAndroid Build Coastguard Worker // time of writing, the earlier is considered to be fair enough.
ProcessQueue()165*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::ProcessQueue() {
166*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
167*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_METATRACE_SCOPED(TAG_PRODUCER, PROFILER_UNWIND_TICK);
168*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwinder::ProcessQueue");
169*6dbdd20aSAndroid Build Coastguard Worker 
170*6dbdd20aSAndroid Build Coastguard Worker   base::FlatSet<DataSourceInstanceID> pending_sample_sources =
171*6dbdd20aSAndroid Build Coastguard Worker       ConsumeAndUnwindReadySamples();
172*6dbdd20aSAndroid Build Coastguard Worker 
173*6dbdd20aSAndroid Build Coastguard Worker   // Deal with the possiblity of data sources that are shutting down.
174*6dbdd20aSAndroid Build Coastguard Worker   bool post_delayed_reprocess = false;
175*6dbdd20aSAndroid Build Coastguard Worker   base::FlatSet<DataSourceInstanceID> sources_to_stop;
176*6dbdd20aSAndroid Build Coastguard Worker   for (auto& id_and_ds : data_sources_) {
177*6dbdd20aSAndroid Build Coastguard Worker     DataSourceInstanceID ds_id = id_and_ds.first;
178*6dbdd20aSAndroid Build Coastguard Worker     const DataSourceState& ds = id_and_ds.second;
179*6dbdd20aSAndroid Build Coastguard Worker 
180*6dbdd20aSAndroid Build Coastguard Worker     if (ds.status == DataSourceState::Status::kActive)
181*6dbdd20aSAndroid Build Coastguard Worker       continue;
182*6dbdd20aSAndroid Build Coastguard Worker 
183*6dbdd20aSAndroid Build Coastguard Worker     // Data source that is shutting down. If we're still waiting on proc-fds (or
184*6dbdd20aSAndroid Build Coastguard Worker     // the lookup to time out) for samples in the queue - repost a later
185*6dbdd20aSAndroid Build Coastguard Worker     // attempt (as there is no guarantee that there are any readers waking up
186*6dbdd20aSAndroid Build Coastguard Worker     // the unwinder anymore).
187*6dbdd20aSAndroid Build Coastguard Worker     if (pending_sample_sources.count(ds_id)) {
188*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DLOG(
189*6dbdd20aSAndroid Build Coastguard Worker           "Unwinder delaying DS(%zu) stop: waiting on a pending sample",
190*6dbdd20aSAndroid Build Coastguard Worker           static_cast<size_t>(ds_id));
191*6dbdd20aSAndroid Build Coastguard Worker       post_delayed_reprocess = true;
192*6dbdd20aSAndroid Build Coastguard Worker     } else {
193*6dbdd20aSAndroid Build Coastguard Worker       // Otherwise, proceed with tearing down data source state (after
194*6dbdd20aSAndroid Build Coastguard Worker       // completing the loop, to avoid invalidating the iterator).
195*6dbdd20aSAndroid Build Coastguard Worker       sources_to_stop.insert(ds_id);
196*6dbdd20aSAndroid Build Coastguard Worker     }
197*6dbdd20aSAndroid Build Coastguard Worker   }
198*6dbdd20aSAndroid Build Coastguard Worker 
199*6dbdd20aSAndroid Build Coastguard Worker   for (auto ds_id : sources_to_stop)
200*6dbdd20aSAndroid Build Coastguard Worker     FinishDataSourceStop(ds_id);
201*6dbdd20aSAndroid Build Coastguard Worker 
202*6dbdd20aSAndroid Build Coastguard Worker   if (post_delayed_reprocess)
203*6dbdd20aSAndroid Build Coastguard Worker     task_runner_->PostDelayedTask([this] { ProcessQueue(); },
204*6dbdd20aSAndroid Build Coastguard Worker                                   kDataSourceShutdownRetryDelayMs);
205*6dbdd20aSAndroid Build Coastguard Worker }
206*6dbdd20aSAndroid Build Coastguard Worker 
ConsumeAndUnwindReadySamples()207*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<DataSourceInstanceID> Unwinder::ConsumeAndUnwindReadySamples() {
208*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
209*6dbdd20aSAndroid Build Coastguard Worker   base::FlatSet<DataSourceInstanceID> pending_sample_sources;
210*6dbdd20aSAndroid Build Coastguard Worker 
211*6dbdd20aSAndroid Build Coastguard Worker   // Use a single snapshot of the ring buffer pointers.
212*6dbdd20aSAndroid Build Coastguard Worker   ReadView read_view = unwind_queue_.BeginRead();
213*6dbdd20aSAndroid Build Coastguard Worker 
214*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_METATRACE_COUNTER(
215*6dbdd20aSAndroid Build Coastguard Worker       TAG_PRODUCER, PROFILER_UNWIND_QUEUE_SZ,
216*6dbdd20aSAndroid Build Coastguard Worker       static_cast<int32_t>(read_view.write_pos - read_view.read_pos));
217*6dbdd20aSAndroid Build Coastguard Worker 
218*6dbdd20aSAndroid Build Coastguard Worker   if (read_view.read_pos == read_view.write_pos)
219*6dbdd20aSAndroid Build Coastguard Worker     return pending_sample_sources;
220*6dbdd20aSAndroid Build Coastguard Worker 
221*6dbdd20aSAndroid Build Coastguard Worker   // Walk the queue.
222*6dbdd20aSAndroid Build Coastguard Worker   for (auto read_pos = read_view.read_pos; read_pos < read_view.write_pos;
223*6dbdd20aSAndroid Build Coastguard Worker        read_pos++) {
224*6dbdd20aSAndroid Build Coastguard Worker     UnwindEntry& entry = unwind_queue_.at(read_pos);
225*6dbdd20aSAndroid Build Coastguard Worker 
226*6dbdd20aSAndroid Build Coastguard Worker     if (!entry.valid)
227*6dbdd20aSAndroid Build Coastguard Worker       continue;  // already processed
228*6dbdd20aSAndroid Build Coastguard Worker 
229*6dbdd20aSAndroid Build Coastguard Worker     uint64_t sampled_stack_bytes = entry.sample.stack.size();
230*6dbdd20aSAndroid Build Coastguard Worker 
231*6dbdd20aSAndroid Build Coastguard Worker     // Data source might be gone due to an abrupt stop.
232*6dbdd20aSAndroid Build Coastguard Worker     auto it = data_sources_.find(entry.data_source_id);
233*6dbdd20aSAndroid Build Coastguard Worker     if (it == data_sources_.end()) {
234*6dbdd20aSAndroid Build Coastguard Worker       entry = UnwindEntry::Invalid();
235*6dbdd20aSAndroid Build Coastguard Worker       DecrementEnqueuedFootprint(sampled_stack_bytes);
236*6dbdd20aSAndroid Build Coastguard Worker       continue;
237*6dbdd20aSAndroid Build Coastguard Worker     }
238*6dbdd20aSAndroid Build Coastguard Worker     DataSourceState& ds = it->second;
239*6dbdd20aSAndroid Build Coastguard Worker 
240*6dbdd20aSAndroid Build Coastguard Worker     pid_t pid = entry.sample.common.pid;
241*6dbdd20aSAndroid Build Coastguard Worker     ProcessState& proc_state = ds.process_states[pid];  // insert if new
242*6dbdd20aSAndroid Build Coastguard Worker 
243*6dbdd20aSAndroid Build Coastguard Worker     // Giving up on the sample (proc-fd lookup timed out).
244*6dbdd20aSAndroid Build Coastguard Worker     if (proc_state.status == ProcessState::Status::kFdsTimedOut) {
245*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DLOG("Unwinder skipping sample for pid [%d]: kFdsTimedOut",
246*6dbdd20aSAndroid Build Coastguard Worker                     static_cast<int>(pid));
247*6dbdd20aSAndroid Build Coastguard Worker 
248*6dbdd20aSAndroid Build Coastguard Worker       // free up the sampled stack as the main thread has no use for it
249*6dbdd20aSAndroid Build Coastguard Worker       entry.sample.stack.clear();
250*6dbdd20aSAndroid Build Coastguard Worker       entry.sample.stack.shrink_to_fit();
251*6dbdd20aSAndroid Build Coastguard Worker 
252*6dbdd20aSAndroid Build Coastguard Worker       delegate_->PostEmitUnwinderSkippedSample(entry.data_source_id,
253*6dbdd20aSAndroid Build Coastguard Worker                                                std::move(entry.sample));
254*6dbdd20aSAndroid Build Coastguard Worker       entry = UnwindEntry::Invalid();
255*6dbdd20aSAndroid Build Coastguard Worker       DecrementEnqueuedFootprint(sampled_stack_bytes);
256*6dbdd20aSAndroid Build Coastguard Worker       continue;
257*6dbdd20aSAndroid Build Coastguard Worker     }
258*6dbdd20aSAndroid Build Coastguard Worker 
259*6dbdd20aSAndroid Build Coastguard Worker     // Still waiting to be notified how to handle this process.
260*6dbdd20aSAndroid Build Coastguard Worker     if (proc_state.status == ProcessState::Status::kInitial) {
261*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DLOG("Unwinder deferring sample for pid [%d]",
262*6dbdd20aSAndroid Build Coastguard Worker                     static_cast<int>(pid));
263*6dbdd20aSAndroid Build Coastguard Worker 
264*6dbdd20aSAndroid Build Coastguard Worker       pending_sample_sources.insert(entry.data_source_id);
265*6dbdd20aSAndroid Build Coastguard Worker       continue;
266*6dbdd20aSAndroid Build Coastguard Worker     }
267*6dbdd20aSAndroid Build Coastguard Worker 
268*6dbdd20aSAndroid Build Coastguard Worker     // b/324757089: we are not precisely tracking process lifetimes, so the
269*6dbdd20aSAndroid Build Coastguard Worker     // sample might be for a different process that reused the pid since the
270*6dbdd20aSAndroid Build Coastguard Worker     // start of the session. Normally this is both infrequent and not a problem
271*6dbdd20aSAndroid Build Coastguard Worker     // since the unwinding will fail due to invalidated procfs descriptors.
272*6dbdd20aSAndroid Build Coastguard Worker     // However we need this explicit skip for the specific case of a kernel
273*6dbdd20aSAndroid Build Coastguard Worker     // thread reusing a userspace pid, as the unwinding doesn't expect absent
274*6dbdd20aSAndroid Build Coastguard Worker     // userspace state for a thought-to-be-userspace process.
275*6dbdd20aSAndroid Build Coastguard Worker     // TODO(rsavitski): start tracking process exits more accurately, either
276*6dbdd20aSAndroid Build Coastguard Worker     // via PERF_RECORD_EXIT records or by checking the validity of the procfs
277*6dbdd20aSAndroid Build Coastguard Worker     // descriptors.
278*6dbdd20aSAndroid Build Coastguard Worker     if (PERFETTO_UNLIKELY(!entry.sample.regs &&
279*6dbdd20aSAndroid Build Coastguard Worker                           proc_state.status ==
280*6dbdd20aSAndroid Build Coastguard Worker                               ProcessState::Status::kFdsResolved)) {
281*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DLOG(
282*6dbdd20aSAndroid Build Coastguard Worker           "Unwinder discarding sample for pid [%d]: uspace->kthread pid reuse",
283*6dbdd20aSAndroid Build Coastguard Worker           static_cast<int>(pid));
284*6dbdd20aSAndroid Build Coastguard Worker 
285*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_CHECK(sampled_stack_bytes == 0);
286*6dbdd20aSAndroid Build Coastguard Worker       entry = UnwindEntry::Invalid();
287*6dbdd20aSAndroid Build Coastguard Worker       continue;
288*6dbdd20aSAndroid Build Coastguard Worker     }
289*6dbdd20aSAndroid Build Coastguard Worker 
290*6dbdd20aSAndroid Build Coastguard Worker     // Sample ready - process it.
291*6dbdd20aSAndroid Build Coastguard Worker     if (proc_state.status == ProcessState::Status::kFdsResolved ||
292*6dbdd20aSAndroid Build Coastguard Worker         proc_state.status == ProcessState::Status::kNoUserspace) {
293*6dbdd20aSAndroid Build Coastguard Worker       // Metatrace: emit both a scoped slice, as well as a "counter"
294*6dbdd20aSAndroid Build Coastguard Worker       // representing the pid being unwound.
295*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_METATRACE_SCOPED(TAG_PRODUCER, PROFILER_UNWIND_SAMPLE);
296*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_METATRACE_COUNTER(TAG_PRODUCER, PROFILER_UNWIND_CURRENT_PID,
297*6dbdd20aSAndroid Build Coastguard Worker                                  static_cast<int32_t>(pid));
298*6dbdd20aSAndroid Build Coastguard Worker 
299*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_CHECK(proc_state.status == ProcessState::Status::kNoUserspace ||
300*6dbdd20aSAndroid Build Coastguard Worker                      proc_state.unwind_state.has_value());
301*6dbdd20aSAndroid Build Coastguard Worker 
302*6dbdd20aSAndroid Build Coastguard Worker       UnwindingMetadata* opt_user_state =
303*6dbdd20aSAndroid Build Coastguard Worker           (proc_state.unwind_state.has_value()
304*6dbdd20aSAndroid Build Coastguard Worker                ? &proc_state.unwind_state.value()
305*6dbdd20aSAndroid Build Coastguard Worker                : nullptr);
306*6dbdd20aSAndroid Build Coastguard Worker       CompletedSample unwound_sample =
307*6dbdd20aSAndroid Build Coastguard Worker           UnwindSample(entry.sample, opt_user_state,
308*6dbdd20aSAndroid Build Coastguard Worker                        proc_state.attempted_unwinding, ds.unwind_mode);
309*6dbdd20aSAndroid Build Coastguard Worker       proc_state.attempted_unwinding = true;
310*6dbdd20aSAndroid Build Coastguard Worker 
311*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_METATRACE_COUNTER(TAG_PRODUCER, PROFILER_UNWIND_CURRENT_PID, 0);
312*6dbdd20aSAndroid Build Coastguard Worker 
313*6dbdd20aSAndroid Build Coastguard Worker       delegate_->PostEmitSample(entry.data_source_id,
314*6dbdd20aSAndroid Build Coastguard Worker                                 std::move(unwound_sample));
315*6dbdd20aSAndroid Build Coastguard Worker       entry = UnwindEntry::Invalid();
316*6dbdd20aSAndroid Build Coastguard Worker       DecrementEnqueuedFootprint(sampled_stack_bytes);
317*6dbdd20aSAndroid Build Coastguard Worker       continue;
318*6dbdd20aSAndroid Build Coastguard Worker     }
319*6dbdd20aSAndroid Build Coastguard Worker   }
320*6dbdd20aSAndroid Build Coastguard Worker 
321*6dbdd20aSAndroid Build Coastguard Worker   // Consume all leading processed entries in the queue.
322*6dbdd20aSAndroid Build Coastguard Worker   auto new_read_pos = read_view.read_pos;
323*6dbdd20aSAndroid Build Coastguard Worker   for (; new_read_pos < read_view.write_pos; new_read_pos++) {
324*6dbdd20aSAndroid Build Coastguard Worker     UnwindEntry& entry = unwind_queue_.at(new_read_pos);
325*6dbdd20aSAndroid Build Coastguard Worker     if (entry.valid)
326*6dbdd20aSAndroid Build Coastguard Worker       break;
327*6dbdd20aSAndroid Build Coastguard Worker   }
328*6dbdd20aSAndroid Build Coastguard Worker   if (new_read_pos != read_view.read_pos)
329*6dbdd20aSAndroid Build Coastguard Worker     unwind_queue_.CommitNewReadPosition(new_read_pos);
330*6dbdd20aSAndroid Build Coastguard Worker 
331*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_METATRACE_COUNTER(
332*6dbdd20aSAndroid Build Coastguard Worker       TAG_PRODUCER, PROFILER_UNWIND_QUEUE_SZ,
333*6dbdd20aSAndroid Build Coastguard Worker       static_cast<int32_t>(read_view.write_pos - new_read_pos));
334*6dbdd20aSAndroid Build Coastguard Worker 
335*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwind queue drain: [%" PRIu64 "]->[%" PRIu64 "]",
336*6dbdd20aSAndroid Build Coastguard Worker                 read_view.write_pos - read_view.read_pos,
337*6dbdd20aSAndroid Build Coastguard Worker                 read_view.write_pos - new_read_pos);
338*6dbdd20aSAndroid Build Coastguard Worker 
339*6dbdd20aSAndroid Build Coastguard Worker   return pending_sample_sources;
340*6dbdd20aSAndroid Build Coastguard Worker }
341*6dbdd20aSAndroid Build Coastguard Worker 
UnwindSample(const ParsedSample & sample,UnwindingMetadata * opt_user_state,bool pid_unwound_before,UnwindMode unwind_mode)342*6dbdd20aSAndroid Build Coastguard Worker CompletedSample Unwinder::UnwindSample(const ParsedSample& sample,
343*6dbdd20aSAndroid Build Coastguard Worker                                        UnwindingMetadata* opt_user_state,
344*6dbdd20aSAndroid Build Coastguard Worker                                        bool pid_unwound_before,
345*6dbdd20aSAndroid Build Coastguard Worker                                        UnwindMode unwind_mode) {
346*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
347*6dbdd20aSAndroid Build Coastguard Worker 
348*6dbdd20aSAndroid Build Coastguard Worker   CompletedSample ret;
349*6dbdd20aSAndroid Build Coastguard Worker   ret.common = sample.common;
350*6dbdd20aSAndroid Build Coastguard Worker 
351*6dbdd20aSAndroid Build Coastguard Worker   // Symbolize kernel-unwound kernel frames, if appropriate.
352*6dbdd20aSAndroid Build Coastguard Worker   std::vector<unwindstack::FrameData> kernel_frames =
353*6dbdd20aSAndroid Build Coastguard Worker       SymbolizeKernelCallchain(sample);
354*6dbdd20aSAndroid Build Coastguard Worker 
355*6dbdd20aSAndroid Build Coastguard Worker   size_t kernel_frames_size = kernel_frames.size();
356*6dbdd20aSAndroid Build Coastguard Worker   ret.frames = std::move(kernel_frames);
357*6dbdd20aSAndroid Build Coastguard Worker   ret.build_ids.resize(kernel_frames_size, "");
358*6dbdd20aSAndroid Build Coastguard Worker 
359*6dbdd20aSAndroid Build Coastguard Worker   // Perform userspace unwinding using libunwindstack, if appropriate.
360*6dbdd20aSAndroid Build Coastguard Worker   if (!opt_user_state)
361*6dbdd20aSAndroid Build Coastguard Worker     return ret;
362*6dbdd20aSAndroid Build Coastguard Worker 
363*6dbdd20aSAndroid Build Coastguard Worker   // Overlay the stack bytes over /proc/<pid>/mem.
364*6dbdd20aSAndroid Build Coastguard Worker   UnwindingMetadata* unwind_state = opt_user_state;
365*6dbdd20aSAndroid Build Coastguard Worker   std::shared_ptr<unwindstack::Memory> overlay_memory =
366*6dbdd20aSAndroid Build Coastguard Worker       std::make_shared<StackOverlayMemory>(
367*6dbdd20aSAndroid Build Coastguard Worker           unwind_state->fd_mem, sample.regs->sp(),
368*6dbdd20aSAndroid Build Coastguard Worker           reinterpret_cast<const uint8_t*>(sample.stack.data()),
369*6dbdd20aSAndroid Build Coastguard Worker           sample.stack.size());
370*6dbdd20aSAndroid Build Coastguard Worker 
371*6dbdd20aSAndroid Build Coastguard Worker   struct UnwindResult {
372*6dbdd20aSAndroid Build Coastguard Worker     unwindstack::ErrorCode error_code;
373*6dbdd20aSAndroid Build Coastguard Worker     uint64_t warnings;
374*6dbdd20aSAndroid Build Coastguard Worker     std::vector<unwindstack::FrameData> frames;
375*6dbdd20aSAndroid Build Coastguard Worker 
376*6dbdd20aSAndroid Build Coastguard Worker     UnwindResult(unwindstack::ErrorCode e,
377*6dbdd20aSAndroid Build Coastguard Worker                  uint64_t w,
378*6dbdd20aSAndroid Build Coastguard Worker                  std::vector<unwindstack::FrameData> f)
379*6dbdd20aSAndroid Build Coastguard Worker         : error_code(e), warnings(w), frames(std::move(f)) {}
380*6dbdd20aSAndroid Build Coastguard Worker     UnwindResult(const UnwindResult&) = delete;
381*6dbdd20aSAndroid Build Coastguard Worker     UnwindResult& operator=(const UnwindResult&) = delete;
382*6dbdd20aSAndroid Build Coastguard Worker     UnwindResult(UnwindResult&&) __attribute__((unused)) = default;
383*6dbdd20aSAndroid Build Coastguard Worker     UnwindResult& operator=(UnwindResult&&) = default;
384*6dbdd20aSAndroid Build Coastguard Worker   };
385*6dbdd20aSAndroid Build Coastguard Worker   auto attempt_unwind = [&sample, unwind_state, pid_unwound_before,
386*6dbdd20aSAndroid Build Coastguard Worker                          &overlay_memory, unwind_mode]() -> UnwindResult {
387*6dbdd20aSAndroid Build Coastguard Worker     metatrace::ScopedEvent m(metatrace::TAG_PRODUCER,
388*6dbdd20aSAndroid Build Coastguard Worker                              pid_unwound_before
389*6dbdd20aSAndroid Build Coastguard Worker                                  ? metatrace::PROFILER_UNWIND_ATTEMPT
390*6dbdd20aSAndroid Build Coastguard Worker                                  : metatrace::PROFILER_UNWIND_INITIAL_ATTEMPT);
391*6dbdd20aSAndroid Build Coastguard Worker 
392*6dbdd20aSAndroid Build Coastguard Worker     // Unwindstack clobbers registers, so make a copy in case of retries.
393*6dbdd20aSAndroid Build Coastguard Worker     auto regs_copy = std::unique_ptr<unwindstack::Regs>{sample.regs->Clone()};
394*6dbdd20aSAndroid Build Coastguard Worker 
395*6dbdd20aSAndroid Build Coastguard Worker     switch (unwind_mode) {
396*6dbdd20aSAndroid Build Coastguard Worker       case UnwindMode::kFramePointer: {
397*6dbdd20aSAndroid Build Coastguard Worker         FramePointerUnwinder unwinder(kUnwindingMaxFrames,
398*6dbdd20aSAndroid Build Coastguard Worker                                       &unwind_state->fd_maps, regs_copy.get(),
399*6dbdd20aSAndroid Build Coastguard Worker                                       overlay_memory, sample.stack.size());
400*6dbdd20aSAndroid Build Coastguard Worker         unwinder.Unwind();
401*6dbdd20aSAndroid Build Coastguard Worker         return {unwinder.LastErrorCode(), unwinder.warnings(),
402*6dbdd20aSAndroid Build Coastguard Worker                 unwinder.ConsumeFrames()};
403*6dbdd20aSAndroid Build Coastguard Worker       }
404*6dbdd20aSAndroid Build Coastguard Worker       case UnwindMode::kUnwindStack: {
405*6dbdd20aSAndroid Build Coastguard Worker         unwindstack::Unwinder unwinder(kUnwindingMaxFrames,
406*6dbdd20aSAndroid Build Coastguard Worker                                        &unwind_state->fd_maps, regs_copy.get(),
407*6dbdd20aSAndroid Build Coastguard Worker                                        overlay_memory);
408*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
409*6dbdd20aSAndroid Build Coastguard Worker         unwinder.SetJitDebug(unwind_state->GetJitDebug(regs_copy->Arch()));
410*6dbdd20aSAndroid Build Coastguard Worker         unwinder.SetDexFiles(unwind_state->GetDexFiles(regs_copy->Arch()));
411*6dbdd20aSAndroid Build Coastguard Worker #endif
412*6dbdd20aSAndroid Build Coastguard Worker         unwinder.Unwind(/*initial_map_names_to_skip=*/nullptr,
413*6dbdd20aSAndroid Build Coastguard Worker                         /*map_suffixes_to_ignore=*/nullptr);
414*6dbdd20aSAndroid Build Coastguard Worker         return {unwinder.LastErrorCode(), unwinder.warnings(),
415*6dbdd20aSAndroid Build Coastguard Worker                 unwinder.ConsumeFrames()};
416*6dbdd20aSAndroid Build Coastguard Worker       }
417*6dbdd20aSAndroid Build Coastguard Worker     }
418*6dbdd20aSAndroid Build Coastguard Worker   };
419*6dbdd20aSAndroid Build Coastguard Worker 
420*6dbdd20aSAndroid Build Coastguard Worker   // first unwind attempt
421*6dbdd20aSAndroid Build Coastguard Worker   UnwindResult unwind = attempt_unwind();
422*6dbdd20aSAndroid Build Coastguard Worker 
423*6dbdd20aSAndroid Build Coastguard Worker   bool should_retry = unwind.error_code == unwindstack::ERROR_INVALID_MAP ||
424*6dbdd20aSAndroid Build Coastguard Worker                       unwind.warnings & unwindstack::WARNING_DEX_PC_NOT_IN_MAP;
425*6dbdd20aSAndroid Build Coastguard Worker 
426*6dbdd20aSAndroid Build Coastguard Worker   // ERROR_INVALID_MAP means that unwinding reached a point in memory without a
427*6dbdd20aSAndroid Build Coastguard Worker   // corresponding mapping. This is possible if the parsed /proc/pid/maps is
428*6dbdd20aSAndroid Build Coastguard Worker   // outdated. Reparse and try again.
429*6dbdd20aSAndroid Build Coastguard Worker   //
430*6dbdd20aSAndroid Build Coastguard Worker   // Special case: skip reparsing if the stack sample was (most likely)
431*6dbdd20aSAndroid Build Coastguard Worker   // truncated. We perform the best-effort unwind of the sampled part, but an
432*6dbdd20aSAndroid Build Coastguard Worker   // error around the truncated part is not unexpected.
433*6dbdd20aSAndroid Build Coastguard Worker   //
434*6dbdd20aSAndroid Build Coastguard Worker   // TODO(rsavitski): consider rate-limiting unwind retries.
435*6dbdd20aSAndroid Build Coastguard Worker   if (should_retry && sample.stack_maxed) {
436*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("Skipping reparse/reunwind due to maxed stack for tid [%d]",
437*6dbdd20aSAndroid Build Coastguard Worker                   static_cast<int>(sample.common.tid));
438*6dbdd20aSAndroid Build Coastguard Worker   } else if (should_retry) {
439*6dbdd20aSAndroid Build Coastguard Worker     {
440*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_METATRACE_SCOPED(TAG_PRODUCER, PROFILER_MAPS_REPARSE);
441*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DLOG("Reparsing maps for pid [%d]",
442*6dbdd20aSAndroid Build Coastguard Worker                     static_cast<int>(sample.common.pid));
443*6dbdd20aSAndroid Build Coastguard Worker       unwind_state->ReparseMaps();
444*6dbdd20aSAndroid Build Coastguard Worker     }
445*6dbdd20aSAndroid Build Coastguard Worker     // reunwind attempt
446*6dbdd20aSAndroid Build Coastguard Worker     unwind = attempt_unwind();
447*6dbdd20aSAndroid Build Coastguard Worker   }
448*6dbdd20aSAndroid Build Coastguard Worker 
449*6dbdd20aSAndroid Build Coastguard Worker   ret.build_ids.reserve(kernel_frames_size + unwind.frames.size());
450*6dbdd20aSAndroid Build Coastguard Worker   ret.frames.reserve(kernel_frames_size + unwind.frames.size());
451*6dbdd20aSAndroid Build Coastguard Worker   for (unwindstack::FrameData& frame : unwind.frames) {
452*6dbdd20aSAndroid Build Coastguard Worker     ret.build_ids.emplace_back(unwind_state->GetBuildId(frame));
453*6dbdd20aSAndroid Build Coastguard Worker     ret.frames.emplace_back(std::move(frame));
454*6dbdd20aSAndroid Build Coastguard Worker   }
455*6dbdd20aSAndroid Build Coastguard Worker 
456*6dbdd20aSAndroid Build Coastguard Worker   // In case of an unwinding error, add a synthetic error frame (which will
457*6dbdd20aSAndroid Build Coastguard Worker   // appear as a caller of the partially-unwound fragment), for easier
458*6dbdd20aSAndroid Build Coastguard Worker   // visualization of errors.
459*6dbdd20aSAndroid Build Coastguard Worker   if (unwind.error_code != unwindstack::ERROR_NONE) {
460*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("Unwinding error %" PRIu8, unwind.error_code);
461*6dbdd20aSAndroid Build Coastguard Worker     unwindstack::FrameData frame_data{};
462*6dbdd20aSAndroid Build Coastguard Worker     frame_data.function_name =
463*6dbdd20aSAndroid Build Coastguard Worker         "ERROR " + StringifyLibUnwindstackError(unwind.error_code);
464*6dbdd20aSAndroid Build Coastguard Worker     ret.frames.emplace_back(std::move(frame_data));
465*6dbdd20aSAndroid Build Coastguard Worker     ret.build_ids.emplace_back("");
466*6dbdd20aSAndroid Build Coastguard Worker     ret.unwind_error = unwind.error_code;
467*6dbdd20aSAndroid Build Coastguard Worker   }
468*6dbdd20aSAndroid Build Coastguard Worker 
469*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(ret.build_ids.size() == ret.frames.size());
470*6dbdd20aSAndroid Build Coastguard Worker   return ret;
471*6dbdd20aSAndroid Build Coastguard Worker }
472*6dbdd20aSAndroid Build Coastguard Worker 
SymbolizeKernelCallchain(const ParsedSample & sample)473*6dbdd20aSAndroid Build Coastguard Worker std::vector<unwindstack::FrameData> Unwinder::SymbolizeKernelCallchain(
474*6dbdd20aSAndroid Build Coastguard Worker     const ParsedSample& sample) {
475*6dbdd20aSAndroid Build Coastguard Worker   static base::NoDestructor<std::shared_ptr<unwindstack::MapInfo>>
476*6dbdd20aSAndroid Build Coastguard Worker       kernel_map_info(unwindstack::MapInfo::Create(0, 0, 0, 0, "kernel"));
477*6dbdd20aSAndroid Build Coastguard Worker   std::vector<unwindstack::FrameData> ret;
478*6dbdd20aSAndroid Build Coastguard Worker   if (sample.kernel_ips.empty())
479*6dbdd20aSAndroid Build Coastguard Worker     return ret;
480*6dbdd20aSAndroid Build Coastguard Worker 
481*6dbdd20aSAndroid Build Coastguard Worker   // The list of addresses contains special context marker values (inserted by
482*6dbdd20aSAndroid Build Coastguard Worker   // the kernel's unwinding) to indicate which section of the callchain belongs
483*6dbdd20aSAndroid Build Coastguard Worker   // to the kernel/user mode (if the kernel can successfully unwind user
484*6dbdd20aSAndroid Build Coastguard Worker   // stacks). In our case, we request only the kernel frames.
485*6dbdd20aSAndroid Build Coastguard Worker   if (sample.kernel_ips[0] != PERF_CONTEXT_KERNEL) {
486*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DFATAL_OR_ELOG(
487*6dbdd20aSAndroid Build Coastguard Worker         "Unexpected: 0th frame of callchain is not PERF_CONTEXT_KERNEL.");
488*6dbdd20aSAndroid Build Coastguard Worker     return ret;
489*6dbdd20aSAndroid Build Coastguard Worker   }
490*6dbdd20aSAndroid Build Coastguard Worker 
491*6dbdd20aSAndroid Build Coastguard Worker   auto* kernel_map = kernel_symbolizer_.GetOrCreateKernelSymbolMap();
492*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(kernel_map);
493*6dbdd20aSAndroid Build Coastguard Worker   ret.reserve(sample.kernel_ips.size());
494*6dbdd20aSAndroid Build Coastguard Worker   for (size_t i = 1; i < sample.kernel_ips.size(); i++) {
495*6dbdd20aSAndroid Build Coastguard Worker     std::string function_name = kernel_map->Lookup(sample.kernel_ips[i]);
496*6dbdd20aSAndroid Build Coastguard Worker 
497*6dbdd20aSAndroid Build Coastguard Worker     // Synthesise a partially-valid libunwindstack frame struct for the kernel
498*6dbdd20aSAndroid Build Coastguard Worker     // frame. We reuse the type for convenience. The kernel frames are marked by
499*6dbdd20aSAndroid Build Coastguard Worker     // a magical "kernel" MapInfo object as their containing mapping.
500*6dbdd20aSAndroid Build Coastguard Worker     unwindstack::FrameData frame{};
501*6dbdd20aSAndroid Build Coastguard Worker     frame.function_name = std::move(function_name);
502*6dbdd20aSAndroid Build Coastguard Worker     frame.map_info = kernel_map_info.ref();
503*6dbdd20aSAndroid Build Coastguard Worker     ret.emplace_back(std::move(frame));
504*6dbdd20aSAndroid Build Coastguard Worker   }
505*6dbdd20aSAndroid Build Coastguard Worker   return ret;
506*6dbdd20aSAndroid Build Coastguard Worker }
507*6dbdd20aSAndroid Build Coastguard Worker 
PostInitiateDataSourceStop(DataSourceInstanceID ds_id)508*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostInitiateDataSourceStop(DataSourceInstanceID ds_id) {
509*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostTask([this, ds_id] { InitiateDataSourceStop(ds_id); });
510*6dbdd20aSAndroid Build Coastguard Worker }
511*6dbdd20aSAndroid Build Coastguard Worker 
InitiateDataSourceStop(DataSourceInstanceID ds_id)512*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::InitiateDataSourceStop(DataSourceInstanceID ds_id) {
513*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
514*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwinder::InitiateDataSourceStop(%zu)",
515*6dbdd20aSAndroid Build Coastguard Worker                 static_cast<size_t>(ds_id));
516*6dbdd20aSAndroid Build Coastguard Worker 
517*6dbdd20aSAndroid Build Coastguard Worker   auto it = data_sources_.find(ds_id);
518*6dbdd20aSAndroid Build Coastguard Worker   if (it == data_sources_.end())
519*6dbdd20aSAndroid Build Coastguard Worker     return;
520*6dbdd20aSAndroid Build Coastguard Worker   DataSourceState& ds = it->second;
521*6dbdd20aSAndroid Build Coastguard Worker 
522*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(ds.status == DataSourceState::Status::kActive);
523*6dbdd20aSAndroid Build Coastguard Worker   ds.status = DataSourceState::Status::kShuttingDown;
524*6dbdd20aSAndroid Build Coastguard Worker 
525*6dbdd20aSAndroid Build Coastguard Worker   // Make sure that there's an outstanding task to process the unwinding queue,
526*6dbdd20aSAndroid Build Coastguard Worker   // as it is the point that evaluates the stop condition.
527*6dbdd20aSAndroid Build Coastguard Worker   PostProcessQueue();
528*6dbdd20aSAndroid Build Coastguard Worker }
529*6dbdd20aSAndroid Build Coastguard Worker 
FinishDataSourceStop(DataSourceInstanceID ds_id)530*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::FinishDataSourceStop(DataSourceInstanceID ds_id) {
531*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
532*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwinder::FinishDataSourceStop(%zu)",
533*6dbdd20aSAndroid Build Coastguard Worker                 static_cast<size_t>(ds_id));
534*6dbdd20aSAndroid Build Coastguard Worker 
535*6dbdd20aSAndroid Build Coastguard Worker   auto it = data_sources_.find(ds_id);
536*6dbdd20aSAndroid Build Coastguard Worker   if (it == data_sources_.end())
537*6dbdd20aSAndroid Build Coastguard Worker     return;
538*6dbdd20aSAndroid Build Coastguard Worker   DataSourceState& ds = it->second;
539*6dbdd20aSAndroid Build Coastguard Worker 
540*6dbdd20aSAndroid Build Coastguard Worker   // Drop unwinder's state tied to the source.
541*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(ds.status == DataSourceState::Status::kShuttingDown);
542*6dbdd20aSAndroid Build Coastguard Worker   data_sources_.erase(it);
543*6dbdd20aSAndroid Build Coastguard Worker 
544*6dbdd20aSAndroid Build Coastguard Worker   // Clean up state if there are no more active sources.
545*6dbdd20aSAndroid Build Coastguard Worker   if (data_sources_.empty()) {
546*6dbdd20aSAndroid Build Coastguard Worker     kernel_symbolizer_.Destroy();
547*6dbdd20aSAndroid Build Coastguard Worker     ResetAndEnableUnwindstackCache();
548*6dbdd20aSAndroid Build Coastguard Worker   }
549*6dbdd20aSAndroid Build Coastguard Worker 
550*6dbdd20aSAndroid Build Coastguard Worker   // Inform service thread that the unwinder is done with the source.
551*6dbdd20aSAndroid Build Coastguard Worker   delegate_->PostFinishDataSourceStop(ds_id);
552*6dbdd20aSAndroid Build Coastguard Worker }
553*6dbdd20aSAndroid Build Coastguard Worker 
PostPurgeDataSource(DataSourceInstanceID ds_id)554*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostPurgeDataSource(DataSourceInstanceID ds_id) {
555*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostTask([this, ds_id] { PurgeDataSource(ds_id); });
556*6dbdd20aSAndroid Build Coastguard Worker }
557*6dbdd20aSAndroid Build Coastguard Worker 
PurgeDataSource(DataSourceInstanceID ds_id)558*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PurgeDataSource(DataSourceInstanceID ds_id) {
559*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK_THREAD(thread_checker_);
560*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Unwinder::PurgeDataSource(%zu)", static_cast<size_t>(ds_id));
561*6dbdd20aSAndroid Build Coastguard Worker 
562*6dbdd20aSAndroid Build Coastguard Worker   auto it = data_sources_.find(ds_id);
563*6dbdd20aSAndroid Build Coastguard Worker   if (it == data_sources_.end())
564*6dbdd20aSAndroid Build Coastguard Worker     return;
565*6dbdd20aSAndroid Build Coastguard Worker 
566*6dbdd20aSAndroid Build Coastguard Worker   data_sources_.erase(it);
567*6dbdd20aSAndroid Build Coastguard Worker 
568*6dbdd20aSAndroid Build Coastguard Worker   // Clean up state if there are no more active sources.
569*6dbdd20aSAndroid Build Coastguard Worker   if (data_sources_.empty()) {
570*6dbdd20aSAndroid Build Coastguard Worker     kernel_symbolizer_.Destroy();
571*6dbdd20aSAndroid Build Coastguard Worker     ResetAndEnableUnwindstackCache();
572*6dbdd20aSAndroid Build Coastguard Worker     // Also purge scudo on Android, which would normally be done by the service
573*6dbdd20aSAndroid Build Coastguard Worker     // thread in |FinishDataSourceStop|. This is important as most of the scudo
574*6dbdd20aSAndroid Build Coastguard Worker     // overhead comes from libunwindstack.
575*6dbdd20aSAndroid Build Coastguard Worker     base::MaybeReleaseAllocatorMemToOS();
576*6dbdd20aSAndroid Build Coastguard Worker   }
577*6dbdd20aSAndroid Build Coastguard Worker }
578*6dbdd20aSAndroid Build Coastguard Worker 
PostClearCachedStatePeriodic(DataSourceInstanceID ds_id,uint32_t period_ms)579*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::PostClearCachedStatePeriodic(DataSourceInstanceID ds_id,
580*6dbdd20aSAndroid Build Coastguard Worker                                             uint32_t period_ms) {
581*6dbdd20aSAndroid Build Coastguard Worker   task_runner_->PostDelayedTask(
582*6dbdd20aSAndroid Build Coastguard Worker       [this, ds_id, period_ms] { ClearCachedStatePeriodic(ds_id, period_ms); },
583*6dbdd20aSAndroid Build Coastguard Worker       period_ms);
584*6dbdd20aSAndroid Build Coastguard Worker }
585*6dbdd20aSAndroid Build Coastguard Worker 
586*6dbdd20aSAndroid Build Coastguard Worker // See header for rationale.
ClearCachedStatePeriodic(DataSourceInstanceID ds_id,uint32_t period_ms)587*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::ClearCachedStatePeriodic(DataSourceInstanceID ds_id,
588*6dbdd20aSAndroid Build Coastguard Worker                                         uint32_t period_ms) {
589*6dbdd20aSAndroid Build Coastguard Worker   auto it = data_sources_.find(ds_id);
590*6dbdd20aSAndroid Build Coastguard Worker   if (it == data_sources_.end())
591*6dbdd20aSAndroid Build Coastguard Worker     return;  // stop the periodic task
592*6dbdd20aSAndroid Build Coastguard Worker 
593*6dbdd20aSAndroid Build Coastguard Worker   DataSourceState& ds = it->second;
594*6dbdd20aSAndroid Build Coastguard Worker   if (ds.status != DataSourceState::Status::kActive)
595*6dbdd20aSAndroid Build Coastguard Worker     return;
596*6dbdd20aSAndroid Build Coastguard Worker 
597*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_METATRACE_SCOPED(TAG_PRODUCER, PROFILER_UNWIND_CACHE_CLEAR);
598*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Clearing unwinder's cached state.");
599*6dbdd20aSAndroid Build Coastguard Worker 
600*6dbdd20aSAndroid Build Coastguard Worker   for (auto& pid_and_process : ds.process_states) {
601*6dbdd20aSAndroid Build Coastguard Worker     if (pid_and_process.second.status == ProcessState::Status::kFdsResolved)
602*6dbdd20aSAndroid Build Coastguard Worker       pid_and_process.second.unwind_state->fd_maps.Reset();
603*6dbdd20aSAndroid Build Coastguard Worker   }
604*6dbdd20aSAndroid Build Coastguard Worker   ResetAndEnableUnwindstackCache();
605*6dbdd20aSAndroid Build Coastguard Worker   base::MaybeReleaseAllocatorMemToOS();
606*6dbdd20aSAndroid Build Coastguard Worker 
607*6dbdd20aSAndroid Build Coastguard Worker   PostClearCachedStatePeriodic(ds_id, period_ms);  // repost
608*6dbdd20aSAndroid Build Coastguard Worker }
609*6dbdd20aSAndroid Build Coastguard Worker 
ResetAndEnableUnwindstackCache()610*6dbdd20aSAndroid Build Coastguard Worker void Unwinder::ResetAndEnableUnwindstackCache() {
611*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("Resetting unwindstack cache");
612*6dbdd20aSAndroid Build Coastguard Worker   // Libunwindstack uses an unsynchronized variable for setting/checking whether
613*6dbdd20aSAndroid Build Coastguard Worker   // the cache is enabled. Therefore unwinding and cache toggling should stay on
614*6dbdd20aSAndroid Build Coastguard Worker   // the same thread, but we might be moving unwinding across threads if we're
615*6dbdd20aSAndroid Build Coastguard Worker   // recreating |Unwinder| instances (during a reconnect to traced). Therefore,
616*6dbdd20aSAndroid Build Coastguard Worker   // use our own static lock to synchronize the cache toggling.
617*6dbdd20aSAndroid Build Coastguard Worker   // TODO(rsavitski): consider fixing this in libunwindstack itself.
618*6dbdd20aSAndroid Build Coastguard Worker   static std::mutex* lock = new std::mutex{};
619*6dbdd20aSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> guard{*lock};
620*6dbdd20aSAndroid Build Coastguard Worker   unwindstack::Elf::SetCachingEnabled(false);  // free any existing state
621*6dbdd20aSAndroid Build Coastguard Worker   unwindstack::Elf::SetCachingEnabled(true);   // reallocate a fresh cache
622*6dbdd20aSAndroid Build Coastguard Worker }
623*6dbdd20aSAndroid Build Coastguard Worker 
624*6dbdd20aSAndroid Build Coastguard Worker }  // namespace profiling
625*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
626