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