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