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