xref: /aosp_15_r20/external/perfetto/src/profiling/perf/unwinding.h (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 #ifndef SRC_PROFILING_PERF_UNWINDING_H_
18*6dbdd20aSAndroid Build Coastguard Worker #define SRC_PROFILING_PERF_UNWINDING_H_
19*6dbdd20aSAndroid Build Coastguard Worker 
20*6dbdd20aSAndroid Build Coastguard Worker #include <stdint.h>
21*6dbdd20aSAndroid Build Coastguard Worker #include <condition_variable>
22*6dbdd20aSAndroid Build Coastguard Worker #include <map>
23*6dbdd20aSAndroid Build Coastguard Worker #include <optional>
24*6dbdd20aSAndroid Build Coastguard Worker #include <thread>
25*6dbdd20aSAndroid Build Coastguard Worker 
26*6dbdd20aSAndroid Build Coastguard Worker #include <linux/perf_event.h>
27*6dbdd20aSAndroid Build Coastguard Worker #include <unwindstack/Error.h>
28*6dbdd20aSAndroid Build Coastguard Worker 
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/flat_set.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_checker.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_task_runner.h"
33*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/tracing/core/basic_types.h"
34*6dbdd20aSAndroid Build Coastguard Worker #include "src/kallsyms/kernel_symbol_map.h"
35*6dbdd20aSAndroid Build Coastguard Worker #include "src/kallsyms/lazy_kernel_symbolizer.h"
36*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/common/unwind_support.h"
37*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/perf/common_types.h"
38*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/perf/unwind_queue.h"
39*6dbdd20aSAndroid Build Coastguard Worker 
40*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
41*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
42*6dbdd20aSAndroid Build Coastguard Worker 
43*6dbdd20aSAndroid Build Coastguard Worker constexpr static uint32_t kUnwindQueueCapacity = 1024;
44*6dbdd20aSAndroid Build Coastguard Worker 
45*6dbdd20aSAndroid Build Coastguard Worker // Unwinds and symbolises callstacks. For userspace this uses the sampled stack
46*6dbdd20aSAndroid Build Coastguard Worker // and register state (see |ParsedSample|). For kernelspace, the kernel itself
47*6dbdd20aSAndroid Build Coastguard Worker // unwinds the stack (recording a list of instruction pointers), so only
48*6dbdd20aSAndroid Build Coastguard Worker // symbolisation using /proc/kallsyms is necessary. Has a single unwinding ring
49*6dbdd20aSAndroid Build Coastguard Worker // queue, shared across all data sources.
50*6dbdd20aSAndroid Build Coastguard Worker //
51*6dbdd20aSAndroid Build Coastguard Worker // Userspace samples cannot be unwound without having /proc/<pid>/{maps,mem}
52*6dbdd20aSAndroid Build Coastguard Worker // file descriptors for that process. This lookup can be asynchronous (e.g. on
53*6dbdd20aSAndroid Build Coastguard Worker // Android), so the unwinder might have to wait before it can process (or
54*6dbdd20aSAndroid Build Coastguard Worker // discard) some of the enqueued samples. To avoid blocking the entire queue,
55*6dbdd20aSAndroid Build Coastguard Worker // the unwinder is allowed to process the entries out of order.
56*6dbdd20aSAndroid Build Coastguard Worker //
57*6dbdd20aSAndroid Build Coastguard Worker // Besides the queue, all interactions between the unwinder and the rest of the
58*6dbdd20aSAndroid Build Coastguard Worker // producer logic are through posted tasks.
59*6dbdd20aSAndroid Build Coastguard Worker //
60*6dbdd20aSAndroid Build Coastguard Worker // As unwinding times are long-tailed (example measurements: median <1ms,
61*6dbdd20aSAndroid Build Coastguard Worker // worst-case ~1000ms), the unwinder runs on a dedicated thread to avoid
62*6dbdd20aSAndroid Build Coastguard Worker // starving the rest of the producer's work (including IPC and consumption of
63*6dbdd20aSAndroid Build Coastguard Worker // records from the kernel ring buffers).
64*6dbdd20aSAndroid Build Coastguard Worker //
65*6dbdd20aSAndroid Build Coastguard Worker // This class should not be instantiated directly, use the |UnwinderHandle|
66*6dbdd20aSAndroid Build Coastguard Worker // below instead.
67*6dbdd20aSAndroid Build Coastguard Worker //
68*6dbdd20aSAndroid Build Coastguard Worker // TODO(rsavitski): while the inputs to the unwinder are batched as a result of
69*6dbdd20aSAndroid Build Coastguard Worker // the reader posting a wakeup only after consuming a batch of kernel samples,
70*6dbdd20aSAndroid Build Coastguard Worker // the Unwinder might be staggering wakeups for the producer thread by posting a
71*6dbdd20aSAndroid Build Coastguard Worker // task every time a sample has been unwound. Evaluate how bad these wakeups are
72*6dbdd20aSAndroid Build Coastguard Worker // in practice, and consider also implementing a batching strategy for the
73*6dbdd20aSAndroid Build Coastguard Worker // unwinder->serialization handoff (which isn't very latency-sensitive).
74*6dbdd20aSAndroid Build Coastguard Worker class Unwinder {
75*6dbdd20aSAndroid Build Coastguard Worker  public:
76*6dbdd20aSAndroid Build Coastguard Worker   friend class UnwinderHandle;
77*6dbdd20aSAndroid Build Coastguard Worker 
78*6dbdd20aSAndroid Build Coastguard Worker   enum class UnwindMode { kUnwindStack, kFramePointer };
79*6dbdd20aSAndroid Build Coastguard Worker 
80*6dbdd20aSAndroid Build Coastguard Worker   // Callbacks from the unwinder to the primary producer thread.
81*6dbdd20aSAndroid Build Coastguard Worker   class Delegate {
82*6dbdd20aSAndroid Build Coastguard Worker    public:
83*6dbdd20aSAndroid Build Coastguard Worker     virtual void PostEmitSample(DataSourceInstanceID ds_id,
84*6dbdd20aSAndroid Build Coastguard Worker                                 CompletedSample sample) = 0;
85*6dbdd20aSAndroid Build Coastguard Worker     virtual void PostEmitUnwinderSkippedSample(DataSourceInstanceID ds_id,
86*6dbdd20aSAndroid Build Coastguard Worker                                                ParsedSample sample) = 0;
87*6dbdd20aSAndroid Build Coastguard Worker     virtual void PostFinishDataSourceStop(DataSourceInstanceID ds_id) = 0;
88*6dbdd20aSAndroid Build Coastguard Worker 
89*6dbdd20aSAndroid Build Coastguard Worker     virtual ~Delegate();
90*6dbdd20aSAndroid Build Coastguard Worker   };
91*6dbdd20aSAndroid Build Coastguard Worker 
~Unwinder()92*6dbdd20aSAndroid Build Coastguard Worker   ~Unwinder() { PERFETTO_DCHECK_THREAD(thread_checker_); }
93*6dbdd20aSAndroid Build Coastguard Worker 
94*6dbdd20aSAndroid Build Coastguard Worker   void PostStartDataSource(DataSourceInstanceID ds_id,
95*6dbdd20aSAndroid Build Coastguard Worker                            bool kernel_frames,
96*6dbdd20aSAndroid Build Coastguard Worker                            UnwindMode unwind_mode);
97*6dbdd20aSAndroid Build Coastguard Worker   void PostAdoptProcDescriptors(DataSourceInstanceID ds_id,
98*6dbdd20aSAndroid Build Coastguard Worker                                 pid_t pid,
99*6dbdd20aSAndroid Build Coastguard Worker                                 base::ScopedFile maps_fd,
100*6dbdd20aSAndroid Build Coastguard Worker                                 base::ScopedFile mem_fd);
101*6dbdd20aSAndroid Build Coastguard Worker   void PostRecordTimedOutProcDescriptors(DataSourceInstanceID ds_id, pid_t pid);
102*6dbdd20aSAndroid Build Coastguard Worker   void PostRecordNoUserspaceProcess(DataSourceInstanceID ds_id, pid_t pid);
103*6dbdd20aSAndroid Build Coastguard Worker   void PostProcessQueue();
104*6dbdd20aSAndroid Build Coastguard Worker   void PostInitiateDataSourceStop(DataSourceInstanceID ds_id);
105*6dbdd20aSAndroid Build Coastguard Worker   void PostPurgeDataSource(DataSourceInstanceID ds_id);
106*6dbdd20aSAndroid Build Coastguard Worker 
107*6dbdd20aSAndroid Build Coastguard Worker   void PostClearCachedStatePeriodic(DataSourceInstanceID ds_id,
108*6dbdd20aSAndroid Build Coastguard Worker                                     uint32_t period_ms);
109*6dbdd20aSAndroid Build Coastguard Worker 
unwind_queue()110*6dbdd20aSAndroid Build Coastguard Worker   UnwindQueue<UnwindEntry, kUnwindQueueCapacity>& unwind_queue() {
111*6dbdd20aSAndroid Build Coastguard Worker     return unwind_queue_;
112*6dbdd20aSAndroid Build Coastguard Worker   }
113*6dbdd20aSAndroid Build Coastguard Worker 
GetEnqueuedFootprint()114*6dbdd20aSAndroid Build Coastguard Worker   uint64_t GetEnqueuedFootprint() {
115*6dbdd20aSAndroid Build Coastguard Worker     uint64_t freed =
116*6dbdd20aSAndroid Build Coastguard Worker         footprint_tracker_.stack_bytes_freed.load(std::memory_order_acquire);
117*6dbdd20aSAndroid Build Coastguard Worker     uint64_t allocated = footprint_tracker_.stack_bytes_allocated.load(
118*6dbdd20aSAndroid Build Coastguard Worker         std::memory_order_relaxed);
119*6dbdd20aSAndroid Build Coastguard Worker 
120*6dbdd20aSAndroid Build Coastguard Worker     // overflow not a concern in practice
121*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DCHECK(allocated >= freed);
122*6dbdd20aSAndroid Build Coastguard Worker     return allocated - freed;
123*6dbdd20aSAndroid Build Coastguard Worker   }
124*6dbdd20aSAndroid Build Coastguard Worker 
IncrementEnqueuedFootprint(uint64_t increment)125*6dbdd20aSAndroid Build Coastguard Worker   void IncrementEnqueuedFootprint(uint64_t increment) {
126*6dbdd20aSAndroid Build Coastguard Worker     footprint_tracker_.stack_bytes_allocated.fetch_add(
127*6dbdd20aSAndroid Build Coastguard Worker         increment, std::memory_order_relaxed);
128*6dbdd20aSAndroid Build Coastguard Worker   }
129*6dbdd20aSAndroid Build Coastguard Worker 
130*6dbdd20aSAndroid Build Coastguard Worker  private:
131*6dbdd20aSAndroid Build Coastguard Worker   struct ProcessState {
132*6dbdd20aSAndroid Build Coastguard Worker     // kInitial: unwinder waiting for more info on the process (proc-fds, their
133*6dbdd20aSAndroid Build Coastguard Worker     //           lookup expiration, or that there is no need for them).
134*6dbdd20aSAndroid Build Coastguard Worker     // kFdsResolved: proc-fds available, can unwind samples.
135*6dbdd20aSAndroid Build Coastguard Worker     // kFdsTimedOut: proc-fd lookup timed out, will discard samples. Can still
136*6dbdd20aSAndroid Build Coastguard Worker     //               transition to kFdsResolved if the fds are received later.
137*6dbdd20aSAndroid Build Coastguard Worker     // kNoUserspace: only handling kernel callchains (the sample might
138*6dbdd20aSAndroid Build Coastguard Worker     //               still be for a userspace process), can process samples.
139*6dbdd20aSAndroid Build Coastguard Worker     enum class Status { kInitial, kFdsResolved, kFdsTimedOut, kNoUserspace };
140*6dbdd20aSAndroid Build Coastguard Worker 
141*6dbdd20aSAndroid Build Coastguard Worker     Status status = Status::kInitial;
142*6dbdd20aSAndroid Build Coastguard Worker     // Present iff status == kFdsResolved.
143*6dbdd20aSAndroid Build Coastguard Worker     std::optional<UnwindingMetadata> unwind_state;
144*6dbdd20aSAndroid Build Coastguard Worker     // Used to distinguish first-time unwinding attempts for a process, for
145*6dbdd20aSAndroid Build Coastguard Worker     // logging purposes.
146*6dbdd20aSAndroid Build Coastguard Worker     bool attempted_unwinding = false;
147*6dbdd20aSAndroid Build Coastguard Worker   };
148*6dbdd20aSAndroid Build Coastguard Worker 
149*6dbdd20aSAndroid Build Coastguard Worker   struct DataSourceState {
150*6dbdd20aSAndroid Build Coastguard Worker     enum class Status { kActive, kShuttingDown };
DataSourceStateDataSourceState151*6dbdd20aSAndroid Build Coastguard Worker     explicit DataSourceState(UnwindMode _unwind_mode)
152*6dbdd20aSAndroid Build Coastguard Worker         : unwind_mode(_unwind_mode) {}
153*6dbdd20aSAndroid Build Coastguard Worker 
154*6dbdd20aSAndroid Build Coastguard Worker     Status status = Status::kActive;
155*6dbdd20aSAndroid Build Coastguard Worker     const UnwindMode unwind_mode;
156*6dbdd20aSAndroid Build Coastguard Worker     std::map<pid_t, ProcessState> process_states;
157*6dbdd20aSAndroid Build Coastguard Worker   };
158*6dbdd20aSAndroid Build Coastguard Worker 
159*6dbdd20aSAndroid Build Coastguard Worker   // Accounting for how much heap memory is attached to the enqueued samples at
160*6dbdd20aSAndroid Build Coastguard Worker   // a given time. Read by the main thread, mutated by both threads.
161*6dbdd20aSAndroid Build Coastguard Worker   // We track just the heap allocated for the sampled stacks, as it dominates
162*6dbdd20aSAndroid Build Coastguard Worker   // the per-sample heap use.
163*6dbdd20aSAndroid Build Coastguard Worker   struct QueueFootprintTracker {
164*6dbdd20aSAndroid Build Coastguard Worker     std::atomic<uint64_t> stack_bytes_allocated;
165*6dbdd20aSAndroid Build Coastguard Worker     std::atomic<uint64_t> stack_bytes_freed;
166*6dbdd20aSAndroid Build Coastguard Worker   };
167*6dbdd20aSAndroid Build Coastguard Worker 
168*6dbdd20aSAndroid Build Coastguard Worker   // Must be instantiated via the |UnwinderHandle|.
169*6dbdd20aSAndroid Build Coastguard Worker   Unwinder(Delegate* delegate, base::UnixTaskRunner* task_runner);
170*6dbdd20aSAndroid Build Coastguard Worker 
171*6dbdd20aSAndroid Build Coastguard Worker   // Marks the data source as valid and active at the unwinding stage.
172*6dbdd20aSAndroid Build Coastguard Worker   // Initializes kernel address symbolization if needed.
173*6dbdd20aSAndroid Build Coastguard Worker   void StartDataSource(DataSourceInstanceID ds_id,
174*6dbdd20aSAndroid Build Coastguard Worker                        bool kernel_frames,
175*6dbdd20aSAndroid Build Coastguard Worker                        UnwindMode unwind_mode);
176*6dbdd20aSAndroid Build Coastguard Worker 
177*6dbdd20aSAndroid Build Coastguard Worker   void AdoptProcDescriptors(DataSourceInstanceID ds_id,
178*6dbdd20aSAndroid Build Coastguard Worker                             pid_t pid,
179*6dbdd20aSAndroid Build Coastguard Worker                             base::ScopedFile maps_fd,
180*6dbdd20aSAndroid Build Coastguard Worker                             base::ScopedFile mem_fd);
181*6dbdd20aSAndroid Build Coastguard Worker   void UpdateProcessStateStatus(DataSourceInstanceID ds_id,
182*6dbdd20aSAndroid Build Coastguard Worker                                 pid_t pid,
183*6dbdd20aSAndroid Build Coastguard Worker                                 ProcessState::Status new_status);
184*6dbdd20aSAndroid Build Coastguard Worker 
185*6dbdd20aSAndroid Build Coastguard Worker   // Primary task. Processes the enqueued samples using
186*6dbdd20aSAndroid Build Coastguard Worker   // |ConsumeAndUnwindReadySamples|, and re-evaluates data source state.
187*6dbdd20aSAndroid Build Coastguard Worker   void ProcessQueue();
188*6dbdd20aSAndroid Build Coastguard Worker 
189*6dbdd20aSAndroid Build Coastguard Worker   // Processes the enqueued samples for which all unwinding inputs are ready.
190*6dbdd20aSAndroid Build Coastguard Worker   // Returns the set of data source instances which still have samples pending
191*6dbdd20aSAndroid Build Coastguard Worker   // (i.e. waiting on the proc-fds).
192*6dbdd20aSAndroid Build Coastguard Worker   base::FlatSet<DataSourceInstanceID> ConsumeAndUnwindReadySamples();
193*6dbdd20aSAndroid Build Coastguard Worker 
194*6dbdd20aSAndroid Build Coastguard Worker   CompletedSample UnwindSample(const ParsedSample& sample,
195*6dbdd20aSAndroid Build Coastguard Worker                                UnwindingMetadata* opt_user_state,
196*6dbdd20aSAndroid Build Coastguard Worker                                bool pid_unwound_before,
197*6dbdd20aSAndroid Build Coastguard Worker                                UnwindMode unwind_mode);
198*6dbdd20aSAndroid Build Coastguard Worker 
199*6dbdd20aSAndroid Build Coastguard Worker   // Returns a list of symbolized kernel frames in the sample (if any).
200*6dbdd20aSAndroid Build Coastguard Worker   std::vector<unwindstack::FrameData> SymbolizeKernelCallchain(
201*6dbdd20aSAndroid Build Coastguard Worker       const ParsedSample& sample);
202*6dbdd20aSAndroid Build Coastguard Worker 
203*6dbdd20aSAndroid Build Coastguard Worker   // Marks the data source as shutting down at the unwinding stage. It is known
204*6dbdd20aSAndroid Build Coastguard Worker   // that no new samples for this source will be pushed into the queue, but we
205*6dbdd20aSAndroid Build Coastguard Worker   // need to delay the unwinder state teardown until all previously-enqueued
206*6dbdd20aSAndroid Build Coastguard Worker   // samples for this source are processed.
207*6dbdd20aSAndroid Build Coastguard Worker   void InitiateDataSourceStop(DataSourceInstanceID ds_id);
208*6dbdd20aSAndroid Build Coastguard Worker 
209*6dbdd20aSAndroid Build Coastguard Worker   // Tears down unwinding state for the data source without any outstanding
210*6dbdd20aSAndroid Build Coastguard Worker   // samples, and informs the service that it can continue the shutdown
211*6dbdd20aSAndroid Build Coastguard Worker   // sequence.
212*6dbdd20aSAndroid Build Coastguard Worker   void FinishDataSourceStop(DataSourceInstanceID ds_id);
213*6dbdd20aSAndroid Build Coastguard Worker 
214*6dbdd20aSAndroid Build Coastguard Worker   // Immediately destroys the data source state, used for abrupt stops.
215*6dbdd20aSAndroid Build Coastguard Worker   void PurgeDataSource(DataSourceInstanceID ds_id);
216*6dbdd20aSAndroid Build Coastguard Worker 
DecrementEnqueuedFootprint(uint64_t decrement)217*6dbdd20aSAndroid Build Coastguard Worker   void DecrementEnqueuedFootprint(uint64_t decrement) {
218*6dbdd20aSAndroid Build Coastguard Worker     footprint_tracker_.stack_bytes_freed.fetch_add(decrement,
219*6dbdd20aSAndroid Build Coastguard Worker                                                    std::memory_order_relaxed);
220*6dbdd20aSAndroid Build Coastguard Worker   }
221*6dbdd20aSAndroid Build Coastguard Worker 
222*6dbdd20aSAndroid Build Coastguard Worker   // Clears the parsed maps for all previously-sampled processes, and resets the
223*6dbdd20aSAndroid Build Coastguard Worker   // libunwindstack cache. This has the effect of deallocating the cached Elf
224*6dbdd20aSAndroid Build Coastguard Worker   // objects within libunwindstack, which take up non-trivial amounts of memory.
225*6dbdd20aSAndroid Build Coastguard Worker   //
226*6dbdd20aSAndroid Build Coastguard Worker   // There are two reasons for having this operation:
227*6dbdd20aSAndroid Build Coastguard Worker   // * over a longer trace, it's desireable to drop heavy state for processes
228*6dbdd20aSAndroid Build Coastguard Worker   //   that haven't been sampled recently.
229*6dbdd20aSAndroid Build Coastguard Worker   // * since libunwindstack's cache is not bounded, it'll tend towards having
230*6dbdd20aSAndroid Build Coastguard Worker   //   state for all processes that are targeted by the profiling config.
231*6dbdd20aSAndroid Build Coastguard Worker   //   Clearing the cache periodically helps keep its footprint closer to the
232*6dbdd20aSAndroid Build Coastguard Worker   //   actual working set (NB: which might still be arbitrarily big, depending
233*6dbdd20aSAndroid Build Coastguard Worker   //   on the profiling config).
234*6dbdd20aSAndroid Build Coastguard Worker   //
235*6dbdd20aSAndroid Build Coastguard Worker   // After this function completes, the next unwind for each process will
236*6dbdd20aSAndroid Build Coastguard Worker   // therefore incur a guaranteed maps reparse.
237*6dbdd20aSAndroid Build Coastguard Worker   //
238*6dbdd20aSAndroid Build Coastguard Worker   // Unwinding for concurrent data sources will *not* be directly affected at
239*6dbdd20aSAndroid Build Coastguard Worker   // the time of writing, as the non-cleared parsed maps will keep the cached
240*6dbdd20aSAndroid Build Coastguard Worker   // Elf objects alive through shared_ptrs.
241*6dbdd20aSAndroid Build Coastguard Worker   //
242*6dbdd20aSAndroid Build Coastguard Worker   // Note that this operation is heavy in terms of cpu%, and should therefore
243*6dbdd20aSAndroid Build Coastguard Worker   // be called only for profiling configs that require it.
244*6dbdd20aSAndroid Build Coastguard Worker   //
245*6dbdd20aSAndroid Build Coastguard Worker   // TODO(rsavitski): dropping the full parsed maps is somewhat excessive, could
246*6dbdd20aSAndroid Build Coastguard Worker   // instead clear just the |MapInfo.elf| shared_ptr, but that's considered too
247*6dbdd20aSAndroid Build Coastguard Worker   // brittle as it's an implementation detail of libunwindstack.
248*6dbdd20aSAndroid Build Coastguard Worker   // TODO(rsavitski): improve libunwindstack cache's architecture (it is still
249*6dbdd20aSAndroid Build Coastguard Worker   // worth having at the moment to speed up unwinds across map reparses).
250*6dbdd20aSAndroid Build Coastguard Worker   void ClearCachedStatePeriodic(DataSourceInstanceID ds_id, uint32_t period_ms);
251*6dbdd20aSAndroid Build Coastguard Worker 
252*6dbdd20aSAndroid Build Coastguard Worker   void ResetAndEnableUnwindstackCache();
253*6dbdd20aSAndroid Build Coastguard Worker 
254*6dbdd20aSAndroid Build Coastguard Worker   base::UnixTaskRunner* const task_runner_;
255*6dbdd20aSAndroid Build Coastguard Worker   Delegate* const delegate_;
256*6dbdd20aSAndroid Build Coastguard Worker   UnwindQueue<UnwindEntry, kUnwindQueueCapacity> unwind_queue_;
257*6dbdd20aSAndroid Build Coastguard Worker   QueueFootprintTracker footprint_tracker_;
258*6dbdd20aSAndroid Build Coastguard Worker   std::map<DataSourceInstanceID, DataSourceState> data_sources_;
259*6dbdd20aSAndroid Build Coastguard Worker   LazyKernelSymbolizer kernel_symbolizer_;
260*6dbdd20aSAndroid Build Coastguard Worker 
261*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_THREAD_CHECKER(thread_checker_)
262*6dbdd20aSAndroid Build Coastguard Worker };
263*6dbdd20aSAndroid Build Coastguard Worker 
264*6dbdd20aSAndroid Build Coastguard Worker // Owning resource handle for an |Unwinder| with a dedicated task thread.
265*6dbdd20aSAndroid Build Coastguard Worker // Ensures that the |Unwinder| is constructed and destructed on the task thread.
266*6dbdd20aSAndroid Build Coastguard Worker // TODO(rsavitski): update base::ThreadTaskRunner to allow for this pattern of
267*6dbdd20aSAndroid Build Coastguard Worker // owned state, and consolidate.
268*6dbdd20aSAndroid Build Coastguard Worker class UnwinderHandle {
269*6dbdd20aSAndroid Build Coastguard Worker  public:
UnwinderHandle(Unwinder::Delegate * delegate)270*6dbdd20aSAndroid Build Coastguard Worker   explicit UnwinderHandle(Unwinder::Delegate* delegate) {
271*6dbdd20aSAndroid Build Coastguard Worker     std::mutex init_lock;
272*6dbdd20aSAndroid Build Coastguard Worker     std::condition_variable init_cv;
273*6dbdd20aSAndroid Build Coastguard Worker 
274*6dbdd20aSAndroid Build Coastguard Worker     std::function<void(base::UnixTaskRunner*, Unwinder*)> initializer =
275*6dbdd20aSAndroid Build Coastguard Worker         [this, &init_lock, &init_cv](base::UnixTaskRunner* task_runner,
276*6dbdd20aSAndroid Build Coastguard Worker                                      Unwinder* unwinder) {
277*6dbdd20aSAndroid Build Coastguard Worker           std::lock_guard<std::mutex> lock(init_lock);
278*6dbdd20aSAndroid Build Coastguard Worker           task_runner_ = task_runner;
279*6dbdd20aSAndroid Build Coastguard Worker           unwinder_ = unwinder;
280*6dbdd20aSAndroid Build Coastguard Worker           // Notify while still holding the lock, as init_cv ceases to exist as
281*6dbdd20aSAndroid Build Coastguard Worker           // soon as the main thread observes a non-null task_runner_, and it
282*6dbdd20aSAndroid Build Coastguard Worker           // can wake up spuriously (i.e. before the notify if we had unlocked
283*6dbdd20aSAndroid Build Coastguard Worker           // before notifying).
284*6dbdd20aSAndroid Build Coastguard Worker           init_cv.notify_one();
285*6dbdd20aSAndroid Build Coastguard Worker         };
286*6dbdd20aSAndroid Build Coastguard Worker 
287*6dbdd20aSAndroid Build Coastguard Worker     thread_ = std::thread(&UnwinderHandle::RunTaskThread, this,
288*6dbdd20aSAndroid Build Coastguard Worker                           std::move(initializer), delegate);
289*6dbdd20aSAndroid Build Coastguard Worker 
290*6dbdd20aSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(init_lock);
291*6dbdd20aSAndroid Build Coastguard Worker     init_cv.wait(lock, [this] { return !!task_runner_ && !!unwinder_; });
292*6dbdd20aSAndroid Build Coastguard Worker   }
293*6dbdd20aSAndroid Build Coastguard Worker 
~UnwinderHandle()294*6dbdd20aSAndroid Build Coastguard Worker   ~UnwinderHandle() {
295*6dbdd20aSAndroid Build Coastguard Worker     if (task_runner_) {
296*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_CHECK(!task_runner_->QuitCalled());
297*6dbdd20aSAndroid Build Coastguard Worker       task_runner_->Quit();
298*6dbdd20aSAndroid Build Coastguard Worker 
299*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DCHECK(thread_.joinable());
300*6dbdd20aSAndroid Build Coastguard Worker     }
301*6dbdd20aSAndroid Build Coastguard Worker     if (thread_.joinable())
302*6dbdd20aSAndroid Build Coastguard Worker       thread_.join();
303*6dbdd20aSAndroid Build Coastguard Worker   }
304*6dbdd20aSAndroid Build Coastguard Worker 
305*6dbdd20aSAndroid Build Coastguard Worker   Unwinder* operator->() { return unwinder_; }
306*6dbdd20aSAndroid Build Coastguard Worker 
307*6dbdd20aSAndroid Build Coastguard Worker  private:
RunTaskThread(std::function<void (base::UnixTaskRunner *,Unwinder *)> initializer,Unwinder::Delegate * delegate)308*6dbdd20aSAndroid Build Coastguard Worker   void RunTaskThread(
309*6dbdd20aSAndroid Build Coastguard Worker       std::function<void(base::UnixTaskRunner*, Unwinder*)> initializer,
310*6dbdd20aSAndroid Build Coastguard Worker       Unwinder::Delegate* delegate) {
311*6dbdd20aSAndroid Build Coastguard Worker     base::UnixTaskRunner task_runner;
312*6dbdd20aSAndroid Build Coastguard Worker     Unwinder unwinder(delegate, &task_runner);
313*6dbdd20aSAndroid Build Coastguard Worker     task_runner.PostTask(
314*6dbdd20aSAndroid Build Coastguard Worker         std::bind(std::move(initializer), &task_runner, &unwinder));
315*6dbdd20aSAndroid Build Coastguard Worker     task_runner.Run();
316*6dbdd20aSAndroid Build Coastguard Worker   }
317*6dbdd20aSAndroid Build Coastguard Worker 
318*6dbdd20aSAndroid Build Coastguard Worker   std::thread thread_;
319*6dbdd20aSAndroid Build Coastguard Worker   base::UnixTaskRunner* task_runner_ = nullptr;
320*6dbdd20aSAndroid Build Coastguard Worker   Unwinder* unwinder_ = nullptr;
321*6dbdd20aSAndroid Build Coastguard Worker };
322*6dbdd20aSAndroid Build Coastguard Worker 
323*6dbdd20aSAndroid Build Coastguard Worker }  // namespace profiling
324*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
325*6dbdd20aSAndroid Build Coastguard Worker 
326*6dbdd20aSAndroid Build Coastguard Worker #endif  // SRC_PROFILING_PERF_UNWINDING_H_
327