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