1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
6
7 #include <limits>
8 #include <set>
9
10 #include "base/bind_helpers.h"
11 #include "base/debug/leak_annotations.h"
12 #include "base/hash/hash.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/no_destructor.h"
15 #include "base/process/process.h"
16 #include "base/process/process_handle.h"
17 #include "base/profiler/sampling_profiler_thread_token.h"
18 #include "base/profiler/stack_sampling_profiler.h"
19 #include "base/strings/strcat.h"
20 #include "base/task/thread_pool/thread_pool_instance.h"
21 #include "base/threading/sequence_local_storage_slot.h"
22 #include "base/trace_event/trace_event.h"
23 #include "build/build_config.h"
24 #include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
25 #include "services/tracing/public/cpp/perfetto/producer_client.h"
26 #include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h"
27 #include "third_party/perfetto/protos/perfetto/trace/profiling/profile_common.pbzero.h"
28 #include "third_party/perfetto/protos/perfetto/trace/profiling/profile_packet.pbzero.h"
29 #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
30 #include "third_party/perfetto/protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
31 #include "third_party/perfetto/protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
32
33 #if defined(OS_ANDROID)
34 #include "base/android/reached_code_profiler.h"
35 #endif
36
37 #if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
38 defined(OFFICIAL_BUILD)
39 #include <dlfcn.h>
40
41 #include "base/trace_event/cfi_backtrace_android.h"
42 #include "services/tracing/public/cpp/stack_sampling/stack_sampler_android.h"
43 #endif
44
45 using StreamingProfilePacketHandle =
46 protozero::MessageHandle<perfetto::protos::pbzero::StreamingProfilePacket>;
47
48 namespace tracing {
49
50 namespace {
51
52 class TracingSamplerProfilerDataSource
53 : public PerfettoTracedProcess::DataSourceBase {
54 public:
Get()55 static TracingSamplerProfilerDataSource* Get() {
56 static base::NoDestructor<TracingSamplerProfilerDataSource> instance;
57 return instance.get();
58 }
59
TracingSamplerProfilerDataSource()60 TracingSamplerProfilerDataSource()
61 : DataSourceBase(mojom::kSamplerProfilerSourceName) {}
62
~TracingSamplerProfilerDataSource()63 ~TracingSamplerProfilerDataSource() override { NOTREACHED(); }
64
RegisterProfiler(TracingSamplerProfiler * profiler)65 void RegisterProfiler(TracingSamplerProfiler* profiler) {
66 base::AutoLock lock(lock_);
67 if (!profilers_.insert(profiler).second) {
68 return;
69 }
70
71 if (is_started_) {
72 profiler->StartTracing(
73 producer_->CreateTraceWriter(data_source_config_.target_buffer()),
74 data_source_config_.chrome_config().privacy_filtering_enabled());
75 } else if (is_startup_tracing_) {
76 profiler->StartTracing(nullptr, /*should_enable_filtering=*/true);
77 }
78 }
79
UnregisterProfiler(TracingSamplerProfiler * profiler)80 void UnregisterProfiler(TracingSamplerProfiler* profiler) {
81 base::AutoLock lock(lock_);
82 if (!profilers_.erase(profiler) || !(is_started_ || is_startup_tracing_)) {
83 return;
84 }
85
86 profiler->StopTracing();
87 }
88
89 // PerfettoTracedProcess::DataSourceBase implementation, called by
90 // ProducerClient.
StartTracing(PerfettoProducer * producer,const perfetto::DataSourceConfig & data_source_config)91 void StartTracing(
92 PerfettoProducer* producer,
93 const perfetto::DataSourceConfig& data_source_config) override {
94 base::AutoLock lock(lock_);
95 DCHECK(!is_started_);
96 is_started_ = true;
97 is_startup_tracing_ = false;
98 data_source_config_ = data_source_config;
99
100 bool should_enable_filtering =
101 data_source_config.chrome_config().privacy_filtering_enabled();
102
103 for (auto* profiler : profilers_) {
104 profiler->StartTracing(
105 producer->CreateTraceWriter(data_source_config.target_buffer()),
106 should_enable_filtering);
107 }
108 }
109
StopTracing(base::OnceClosure stop_complete_callback)110 void StopTracing(base::OnceClosure stop_complete_callback) override {
111 base::AutoLock lock(lock_);
112 DCHECK(is_started_);
113 is_started_ = false;
114 is_startup_tracing_ = false;
115 producer_ = nullptr;
116
117 for (auto* profiler : profilers_) {
118 profiler->StopTracing();
119 }
120
121 std::move(stop_complete_callback).Run();
122 }
123
Flush(base::RepeatingClosure flush_complete_callback)124 void Flush(base::RepeatingClosure flush_complete_callback) override {
125 flush_complete_callback.Run();
126 }
127
SetupStartupTracing(PerfettoProducer * producer,const base::trace_event::TraceConfig & trace_config,bool privacy_filtering_enabled)128 void SetupStartupTracing(PerfettoProducer* producer,
129 const base::trace_event::TraceConfig& trace_config,
130 bool privacy_filtering_enabled) override {
131 bool enable_sampler_profiler = trace_config.IsCategoryGroupEnabled(
132 TRACE_DISABLED_BY_DEFAULT("cpu_profiler"));
133 if (!enable_sampler_profiler)
134 return;
135
136 base::AutoLock lock(lock_);
137 if (is_started_) {
138 return;
139 }
140 is_startup_tracing_ = true;
141 for (auto* profiler : profilers_) {
142 // Enable filtering for startup tracing always to be safe.
143 profiler->StartTracing(nullptr, /*should_enable_filtering=*/true);
144 }
145 }
146
AbortStartupTracing()147 void AbortStartupTracing() override {
148 base::AutoLock lock(lock_);
149 if (!is_startup_tracing_) {
150 return;
151 }
152 for (auto* profiler : profilers_) {
153 // Enable filtering for startup tracing always to be safe.
154 profiler->StartTracing(nullptr, /*should_enable_filtering=*/true);
155 }
156 is_startup_tracing_ = false;
157 }
158
ClearIncrementalState()159 void ClearIncrementalState() override {
160 incremental_state_reset_id_.fetch_add(1u, std::memory_order_relaxed);
161 }
162
GetIncrementalStateResetID()163 static uint32_t GetIncrementalStateResetID() {
164 return incremental_state_reset_id_.load(std::memory_order_relaxed);
165 }
166
167 private:
168 base::Lock lock_; // Protects subsequent members.
169 std::set<TracingSamplerProfiler*> profilers_;
170 bool is_startup_tracing_ = false;
171 bool is_started_ = false;
172 perfetto::DataSourceConfig data_source_config_;
173
174 static std::atomic<uint32_t> incremental_state_reset_id_;
175 };
176
177 // static
178 std::atomic<uint32_t>
179 TracingSamplerProfilerDataSource::incremental_state_reset_id_{0};
180
181 base::SequenceLocalStorageSlot<TracingSamplerProfiler>&
GetSequenceLocalStorageProfilerSlot()182 GetSequenceLocalStorageProfilerSlot() {
183 static base::NoDestructor<
184 base::SequenceLocalStorageSlot<TracingSamplerProfiler>>
185 storage;
186 return *storage;
187 }
188
189 } // namespace
190
BufferedSample(base::TimeTicks ts,std::vector<base::Frame> && s)191 TracingSamplerProfiler::TracingProfileBuilder::BufferedSample::BufferedSample(
192 base::TimeTicks ts,
193 std::vector<base::Frame>&& s)
194 : timestamp(ts), sample(std::move(s)) {}
195
196 TracingSamplerProfiler::TracingProfileBuilder::BufferedSample::
197 ~BufferedSample() = default;
198
BufferedSample(TracingSamplerProfiler::TracingProfileBuilder::BufferedSample && other)199 TracingSamplerProfiler::TracingProfileBuilder::BufferedSample::BufferedSample(
200 TracingSamplerProfiler::TracingProfileBuilder::BufferedSample&& other)
201 : BufferedSample(other.timestamp, std::move(other.sample)) {}
202
TracingProfileBuilder(base::PlatformThreadId sampled_thread_id,std::unique_ptr<perfetto::TraceWriter> trace_writer,bool should_enable_filtering,const base::RepeatingClosure & sample_callback_for_testing)203 TracingSamplerProfiler::TracingProfileBuilder::TracingProfileBuilder(
204 base::PlatformThreadId sampled_thread_id,
205 std::unique_ptr<perfetto::TraceWriter> trace_writer,
206 bool should_enable_filtering,
207 const base::RepeatingClosure& sample_callback_for_testing)
208 : sampled_thread_id_(sampled_thread_id),
209 trace_writer_(std::move(trace_writer)),
210 should_enable_filtering_(should_enable_filtering),
211 sample_callback_for_testing_(sample_callback_for_testing) {}
212
~TracingProfileBuilder()213 TracingSamplerProfiler::TracingProfileBuilder::~TracingProfileBuilder() {
214 // Deleting a TraceWriter can end up triggering a Mojo call which calls
215 // TaskRunnerHandle::Get() and isn't safe on thread shutdown, which is when
216 // TracingProfileBuilder gets destructed, so we make sure this happens on
217 // a different sequence.
218 if (base::ThreadPoolInstance::Get()) {
219 PerfettoTracedProcess::GetTaskRunner()->GetOrCreateTaskRunner()->DeleteSoon(
220 FROM_HERE, std::move(trace_writer_));
221 } else {
222 // Intentionally leak; we have no way of safely destroying this at this
223 // point.
224 ANNOTATE_LEAKING_OBJECT_PTR(trace_writer_.get());
225 trace_writer_.release();
226 }
227 }
228
229 base::ModuleCache*
GetModuleCache()230 TracingSamplerProfiler::TracingProfileBuilder::GetModuleCache() {
231 return &module_cache_;
232 }
233
OnSampleCompleted(std::vector<base::Frame> frames,base::TimeTicks sample_timestamp)234 void TracingSamplerProfiler::TracingProfileBuilder::OnSampleCompleted(
235 std::vector<base::Frame> frames,
236 base::TimeTicks sample_timestamp) {
237 base::AutoLock l(trace_writer_lock_);
238 if (!trace_writer_) {
239 if (buffered_samples_.size() < kMaxBufferedSamples) {
240 buffered_samples_.emplace_back(
241 BufferedSample(sample_timestamp, std::move(frames)));
242 }
243 return;
244 }
245 if (!buffered_samples_.empty()) {
246 for (const auto& sample : buffered_samples_) {
247 WriteSampleToTrace(sample);
248 }
249 buffered_samples_.clear();
250 }
251 WriteSampleToTrace(BufferedSample(sample_timestamp, std::move(frames)));
252
253 if (sample_callback_for_testing_) {
254 sample_callback_for_testing_.Run();
255 }
256 }
257
WriteSampleToTrace(const TracingSamplerProfiler::TracingProfileBuilder::BufferedSample & sample)258 void TracingSamplerProfiler::TracingProfileBuilder::WriteSampleToTrace(
259 const TracingSamplerProfiler::TracingProfileBuilder::BufferedSample&
260 sample) {
261 const auto& frames = sample.sample;
262 auto reset_id =
263 TracingSamplerProfilerDataSource::GetIncrementalStateResetID();
264 if (reset_id != last_incremental_state_reset_id_) {
265 reset_incremental_state_ = true;
266 last_incremental_state_reset_id_ = reset_id;
267 }
268
269 if (reset_incremental_state_) {
270 interned_callstacks_.ResetEmittedState();
271 interned_frames_.ResetEmittedState();
272 interned_frame_names_.ResetEmittedState();
273 interned_module_names_.ResetEmittedState();
274 interned_module_ids_.ResetEmittedState();
275 interned_modules_.ResetEmittedState();
276
277 auto trace_packet = trace_writer_->NewTracePacket();
278 trace_packet->set_sequence_flags(
279 perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
280
281 // Note: Make sure ThreadDescriptors we emit here won't cause
282 // metadata events to be emitted from the JSON exporter which conflict
283 // with the metadata events emitted by the regular TrackEventDataSource.
284 auto* thread_descriptor = trace_packet->set_thread_descriptor();
285 thread_descriptor->set_pid(base::GetCurrentProcId());
286 thread_descriptor->set_tid(sampled_thread_id_);
287 last_timestamp_ = sample.timestamp;
288 thread_descriptor->set_reference_timestamp_us(
289 last_timestamp_.since_origin().InMicroseconds());
290 reset_incremental_state_ = false;
291 }
292
293 int32_t current_process_priority = base::Process::Current().GetPriority();
294 if (current_process_priority != last_emitted_process_priority_) {
295 last_emitted_process_priority_ = current_process_priority;
296 auto trace_packet = trace_writer_->NewTracePacket();
297 auto* process_descriptor = trace_packet->set_process_descriptor();
298 process_descriptor->set_pid(base::GetCurrentProcId());
299 process_descriptor->set_process_priority(current_process_priority);
300 }
301
302 auto trace_packet = trace_writer_->NewTracePacket();
303 // Delta encoded timestamps and interned data require incremental state.
304 trace_packet->set_sequence_flags(
305 perfetto::protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
306 auto callstack_id = GetCallstackIDAndMaybeEmit(frames, &trace_packet);
307 auto* streaming_profile_packet = trace_packet->set_streaming_profile_packet();
308 streaming_profile_packet->add_callstack_iid(callstack_id);
309 streaming_profile_packet->add_timestamp_delta_us(
310 (sample.timestamp - last_timestamp_).InMicroseconds());
311 last_timestamp_ = sample.timestamp;
312 }
313
SetTraceWriter(std::unique_ptr<perfetto::TraceWriter> writer)314 void TracingSamplerProfiler::TracingProfileBuilder::SetTraceWriter(
315 std::unique_ptr<perfetto::TraceWriter> writer) {
316 base::AutoLock l(trace_writer_lock_);
317 trace_writer_ = std::move(writer);
318 }
319
320 InterningID
GetCallstackIDAndMaybeEmit(const std::vector<base::Frame> & frames,perfetto::TraceWriter::TracePacketHandle * trace_packet)321 TracingSamplerProfiler::TracingProfileBuilder::GetCallstackIDAndMaybeEmit(
322 const std::vector<base::Frame>& frames,
323 perfetto::TraceWriter::TracePacketHandle* trace_packet) {
324 size_t ip_hash = 0;
325 for (const auto& frame : frames) {
326 ip_hash = base::HashInts(ip_hash, frame.instruction_pointer);
327 }
328
329 InterningIndexEntry interned_callstack =
330 interned_callstacks_.LookupOrAdd(ip_hash);
331
332 if (interned_callstack.was_emitted)
333 return interned_callstack.id;
334
335 auto* interned_data = (*trace_packet)->set_interned_data();
336
337 std::vector<InterningID> frame_ids;
338 for (const auto& frame : frames) {
339 std::string frame_name;
340 std::string module_name;
341 std::string module_id;
342 uintptr_t rel_pc = 0;
343
344 #if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
345 defined(OFFICIAL_BUILD)
346 Dl_info info = {};
347 // For chrome address we do not have symbols on the binary. So, just write
348 // the offset address. For addresses on framework libraries, symbolize
349 // and write the function name.
350 if (frame.instruction_pointer == 0) {
351 frame_name = "Scanned";
352 } else if (base::trace_event::CFIBacktraceAndroid::is_chrome_address(
353 frame.instruction_pointer)) {
354 rel_pc = frame.instruction_pointer -
355 base::trace_event::CFIBacktraceAndroid::executable_start_addr();
356 } else if (dladdr(reinterpret_cast<void*>(frame.instruction_pointer),
357 &info) != 0) {
358 // TODO(ssid): Add offset and module debug id if symbol was not resolved
359 // in case this might be useful to send report to vendors.
360 if (info.dli_sname)
361 frame_name = info.dli_sname;
362 if (info.dli_fname)
363 module_name = info.dli_fname;
364 }
365
366 if (frame.module) {
367 module_id = frame.module->GetId();
368 if (module_name.empty())
369 module_name = frame.module->GetDebugBasename().MaybeAsASCII();
370 }
371
372 // If no module is available, then name it unknown. Adding PC would be
373 // useless anyway.
374 if (module_name.empty()) {
375 DCHECK(!base::trace_event::CFIBacktraceAndroid::is_chrome_address(
376 frame.instruction_pointer));
377 frame_name = "Unknown";
378 rel_pc = 0;
379 }
380 #else
381 if (frame.module) {
382 module_name = frame.module->GetDebugBasename().MaybeAsASCII();
383 module_id = frame.module->GetId();
384 rel_pc = frame.instruction_pointer - frame.module->GetBaseAddress();
385 } else {
386 module_name = module_id = "";
387 frame_name = "Unknown";
388 }
389 #endif
390
391 MangleModuleIDIfNeeded(&module_id);
392
393 // We never emit frame names in privacy filtered mode.
394 bool should_emit_frame_names =
395 !frame_name.empty() && !should_enable_filtering_;
396
397 if (should_enable_filtering_ && !rel_pc && frame.module) {
398 rel_pc = frame.instruction_pointer - frame.module->GetBaseAddress();
399 }
400
401 InterningIndexEntry interned_frame;
402 if (should_emit_frame_names) {
403 interned_frame =
404 interned_frames_.LookupOrAdd(std::make_pair(frame_name, module_id));
405 } else {
406 interned_frame =
407 interned_frames_.LookupOrAdd(std::make_pair(rel_pc, module_id));
408 }
409
410 if (!interned_frame.was_emitted) {
411 InterningIndexEntry interned_frame_name;
412 if (should_emit_frame_names) {
413 interned_frame_name = interned_frame_names_.LookupOrAdd(frame_name);
414 if (!interned_frame_name.was_emitted) {
415 auto* frame_name_entry = interned_data->add_function_names();
416 frame_name_entry->set_iid(interned_frame_name.id);
417 frame_name_entry->set_str(
418 reinterpret_cast<const uint8_t*>(frame_name.data()),
419 frame_name.length());
420 }
421 }
422
423 InterningIndexEntry interned_module;
424 if (frame.module) {
425 interned_module =
426 interned_modules_.LookupOrAdd(frame.module->GetBaseAddress());
427 if (!interned_module.was_emitted) {
428 InterningIndexEntry interned_module_id =
429 interned_module_ids_.LookupOrAdd(module_id);
430 if (!interned_module_id.was_emitted) {
431 auto* module_id_entry = interned_data->add_build_ids();
432 module_id_entry->set_iid(interned_module_id.id);
433 module_id_entry->set_str(
434 reinterpret_cast<const uint8_t*>(module_id.data()),
435 module_id.length());
436 }
437
438 InterningIndexEntry interned_module_name =
439 interned_module_names_.LookupOrAdd(module_name);
440 if (!interned_module_name.was_emitted) {
441 auto* module_name_entry = interned_data->add_mapping_paths();
442 module_name_entry->set_iid(interned_module_name.id);
443 module_name_entry->set_str(
444 reinterpret_cast<const uint8_t*>(module_name.data()),
445 module_name.length());
446 }
447 auto* module_entry = interned_data->add_mappings();
448 module_entry->set_iid(interned_module.id);
449 module_entry->set_build_id(interned_module_id.id);
450 module_entry->add_path_string_ids(interned_module_name.id);
451 }
452 }
453
454 auto* frame_entry = interned_data->add_frames();
455 frame_entry->set_iid(interned_frame.id);
456 if (should_emit_frame_names) {
457 frame_entry->set_function_name_id(interned_frame_name.id);
458 } else {
459 frame_entry->set_rel_pc(rel_pc);
460 }
461 if (frame.module) {
462 frame_entry->set_mapping_id(interned_module.id);
463 }
464 }
465
466 frame_ids.push_back(interned_frame.id);
467 }
468
469 auto* callstack_entry = interned_data->add_callstacks();
470 callstack_entry->set_iid(interned_callstack.id);
471 for (auto& frame_id : frame_ids)
472 callstack_entry->add_frame_ids(frame_id);
473
474 return interned_callstack.id;
475 }
476
477 // static
MangleModuleIDIfNeeded(std::string * module_id)478 void TracingSamplerProfiler::MangleModuleIDIfNeeded(std::string* module_id) {
479 #if defined(OS_ANDROID) || defined(OS_LINUX)
480 // Linux ELF module IDs are 160bit integers, which we need to mangle
481 // down to 128bit integers to match the id that Breakpad outputs.
482 // Example on version '66.0.3359.170' x64:
483 // Build-ID: "7f0715c2 86f8 b16c 10e4ad349cda3b9b 56c7a773
484 // Debug-ID "C215077F F886 6CB1 10E4AD349CDA3B9B 0"
485 if (module_id->size() >= 32) {
486 *module_id =
487 base::StrCat({module_id->substr(6, 2), module_id->substr(4, 2),
488 module_id->substr(2, 2), module_id->substr(0, 2),
489 module_id->substr(10, 2), module_id->substr(8, 2),
490 module_id->substr(14, 2), module_id->substr(12, 2),
491 module_id->substr(16, 16), "0"});
492 }
493 #endif
494 }
495
496 // static
497 std::unique_ptr<TracingSamplerProfiler>
CreateOnMainThread()498 TracingSamplerProfiler::CreateOnMainThread() {
499 return std::make_unique<TracingSamplerProfiler>(
500 base::GetSamplingProfilerCurrentThreadToken());
501 }
502
503 // static
CreateOnChildThread()504 void TracingSamplerProfiler::CreateOnChildThread() {
505 base::SequenceLocalStorageSlot<TracingSamplerProfiler>& slot =
506 GetSequenceLocalStorageProfilerSlot();
507 if (slot)
508 return;
509
510 slot.emplace(base::GetSamplingProfilerCurrentThreadToken());
511 }
512
513 // static
DeleteOnChildThreadForTesting()514 void TracingSamplerProfiler::DeleteOnChildThreadForTesting() {
515 GetSequenceLocalStorageProfilerSlot().reset();
516 }
517
518 // static
RegisterDataSource()519 void TracingSamplerProfiler::RegisterDataSource() {
520 PerfettoTracedProcess::Get()->AddDataSource(
521 TracingSamplerProfilerDataSource::Get());
522 }
523
524 // static
StartTracingForTesting(PerfettoProducer * producer)525 void TracingSamplerProfiler::StartTracingForTesting(
526 PerfettoProducer* producer) {
527 TracingSamplerProfilerDataSource::Get()->StartTracingWithID(
528 1, producer, perfetto::DataSourceConfig());
529 }
530
531 // static
SetupStartupTracingForTesting()532 void TracingSamplerProfiler::SetupStartupTracingForTesting() {
533 base::trace_event::TraceConfig config(
534 TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
535 base::trace_event::TraceRecordMode::RECORD_UNTIL_FULL);
536 TracingSamplerProfilerDataSource::Get()->SetupStartupTracing(
537 /*producer=*/nullptr, config, /*privacy_filtering_enabled=*/false);
538 }
539
540 // static
StopTracingForTesting()541 void TracingSamplerProfiler::StopTracingForTesting() {
542 TracingSamplerProfilerDataSource::Get()->StopTracing(base::DoNothing());
543 }
544
TracingSamplerProfiler(base::SamplingProfilerThreadToken sampled_thread_token)545 TracingSamplerProfiler::TracingSamplerProfiler(
546 base::SamplingProfilerThreadToken sampled_thread_token)
547 : sampled_thread_token_(sampled_thread_token) {
548 DCHECK_NE(sampled_thread_token_.id, base::kInvalidThreadId);
549 TracingSamplerProfilerDataSource::Get()->RegisterProfiler(this);
550 }
551
~TracingSamplerProfiler()552 TracingSamplerProfiler::~TracingSamplerProfiler() {
553 TracingSamplerProfilerDataSource::Get()->UnregisterProfiler(this);
554 }
555
SetSampleCallbackForTesting(const base::RepeatingClosure & sample_callback_for_testing)556 void TracingSamplerProfiler::SetSampleCallbackForTesting(
557 const base::RepeatingClosure& sample_callback_for_testing) {
558 base::AutoLock lock(lock_);
559 sample_callback_for_testing_ = sample_callback_for_testing;
560 }
561
StartTracing(std::unique_ptr<perfetto::TraceWriter> trace_writer,bool should_enable_filtering)562 void TracingSamplerProfiler::StartTracing(
563 std::unique_ptr<perfetto::TraceWriter> trace_writer,
564 bool should_enable_filtering) {
565 base::AutoLock lock(lock_);
566 if (profiler_) {
567 if (trace_writer) {
568 profile_builder_->SetTraceWriter(std::move(trace_writer));
569 }
570 return;
571 }
572
573 #if defined(OS_ANDROID)
574 // The sampler profiler would conflict with the reached code profiler if they
575 // run at the same time because they use the same signal to suspend threads.
576 if (base::android::IsReachedCodeProfilerEnabled())
577 return;
578 #endif
579
580 base::StackSamplingProfiler::SamplingParams params;
581 params.samples_per_profile = std::numeric_limits<int>::max();
582 params.sampling_interval = base::TimeDelta::FromMilliseconds(50);
583 // If the sampled thread is stopped for too long for sampling then it is ok to
584 // get next sample at a later point of time. We do not want very accurate
585 // metrics when looking at traces.
586 params.keep_consistent_sampling_interval = false;
587
588 auto profile_builder = std::make_unique<TracingProfileBuilder>(
589 sampled_thread_token_.id, std::move(trace_writer),
590 should_enable_filtering, sample_callback_for_testing_);
591 profile_builder_ = profile_builder.get();
592 // Create and start the stack sampling profiler.
593 #if defined(OS_ANDROID)
594 #if BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && defined(OFFICIAL_BUILD)
595 auto* module_cache = profile_builder->GetModuleCache();
596 profiler_ = std::make_unique<base::StackSamplingProfiler>(
597 params, std::move(profile_builder),
598 std::make_unique<StackSamplerAndroid>(sampled_thread_token_,
599 module_cache));
600 profiler_->Start();
601 #endif // BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && defined(OFFICIAL_BUILD)
602 #else // defined(OS_ANDROID)
603 profiler_ = std::make_unique<base::StackSamplingProfiler>(
604 sampled_thread_token_, params, std::move(profile_builder));
605 profiler_->Start();
606 #endif // defined(OS_ANDROID)
607 }
608
StopTracing()609 void TracingSamplerProfiler::StopTracing() {
610 base::AutoLock lock(lock_);
611 if (!profiler_) {
612 return;
613 }
614
615 // Stop and release the stack sampling profiler.
616 profiler_->Stop();
617 profile_builder_ = nullptr;
618 profiler_.reset();
619 }
620
621 } // namespace tracing
622