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