#ifndef SERVICES_TRACING_PUBLIC_CPP_STACK_SAMPLING_TRACING_SAMPLER_PROFILER_H_
#define SERVICES_TRACING_PUBLIC_CPP_STACK_SAMPLING_TRACING_SAMPLER_PROFILER_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/component_export.h"
#include "base/debug/debugging_buildflags.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/profiler/sampling_profiler_thread_token.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "base/profiler/unwinder.h"
#include "base/sequence_checker.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "services/tracing/public/cpp/buildflags.h"
#include "services/tracing/public/cpp/perfetto/interning_index.h"
#include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h"
#include "third_party/perfetto/include/perfetto/tracing/data_source.h"
#if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_ARM64) && \
BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
#define ANDROID_ARM64_UNWINDING_SUPPORTED 1
#else
#define ANDROID_ARM64_UNWINDING_SUPPORTED 0
#endif
#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
defined(OFFICIAL_BUILD)
#define ANDROID_CFI_UNWINDING_SUPPORTED 1
#else
#define ANDROID_CFI_UNWINDING_SUPPORTED 0
#endif
namespace tracing {
#if BUILDFLAG(ENABLE_LOADER_LOCK_SAMPLING)
class LoaderLockSamplingThread;
#endif
class COMPONENT_EXPORT(TRACING_CPP) TracingSamplerProfiler {
public:
class COMPONENT_EXPORT(TRACING_CPP) DataSource
: public perfetto::DataSource<DataSource> {
public:
static constexpr bool kSupportsMultipleInstances = false;
static constexpr bool kRequiresCallbacksUnderLock = false;
using TraceContext = perfetto::DataSource<DataSource>::TraceContext;
DataSource();
~DataSource() override;
void OnSetup(const SetupArgs& args) override;
void OnStart(const StartArgs&) override;
void OnStop(const StopArgs&) override;
void WillClearIncrementalState(
const ClearIncrementalStateArgs& args) override;
std::unique_ptr<perfetto::TraceWriterBase> CreateTraceWriter();
bool privacy_filtering_enabled() const {
return privacy_filtering_enabled_;
}
private:
bool privacy_filtering_enabled_ = false;
};
using TracePacketHandle = DataSource::TraceContext::TracePacketHandle;
class COMPONENT_EXPORT(TRACING_CPP) StackProfileWriter {
public:
explicit StackProfileWriter(bool should_enable_filtering);
~StackProfileWriter();
StackProfileWriter(const StackProfileWriter&) = delete;
StackProfileWriter& operator=(const StackProfileWriter&) = delete;
InterningID GetCallstackIDAndMaybeEmit(std::vector<base::Frame>& frames,
TracePacketHandle* trace_packet);
void ResetEmittedState();
private:
const bool should_enable_filtering_;
InterningIndex<TypeList<size_t>, SizeList<1024>> interned_callstacks_{};
InterningIndex<TypeList<std::pair<std::string, std::string>,
std::pair<uintptr_t, std::string>>,
SizeList<1024, 1024>>
interned_frames_{};
InterningIndex<TypeList<std::string>, SizeList<1024>>
interned_frame_names_{};
InterningIndex<TypeList<std::string>, SizeList<1024>>
interned_module_names_{};
InterningIndex<TypeList<std::string>, SizeList<1024>>
interned_module_ids_{};
InterningIndex<TypeList<uintptr_t>, SizeList<1024>> interned_modules_{};
};
enum class UnwinderType {
kUnknown,
kCustomAndroid,
kDefault,
kLibunwindstackUnwinderAndroid
};
class COMPONENT_EXPORT(TRACING_CPP) TracingProfileBuilder
: public base::ProfileBuilder {
public:
TracingProfileBuilder(
base::PlatformThreadId sampled_thread_id,
std::unique_ptr<perfetto::TraceWriterBase> trace_writer,
bool should_enable_filtering,
const base::RepeatingClosure& sample_callback_for_testing =
base::RepeatingClosure());
~TracingProfileBuilder() override;
base::ModuleCache* GetModuleCache() override;
void OnSampleCompleted(std::vector<base::Frame> frames,
base::TimeTicks sample_timestamp) override;
void OnProfileCompleted(base::TimeDelta profile_duration,
base::TimeDelta sampling_period) override {}
void SetUnwinderType(TracingSamplerProfiler::UnwinderType unwinder_type);
private:
void WriteSampleToTrace(std::vector<base::Frame> frames,
base::TimeTicks sample_timestamp);
base::ModuleCache module_cache_;
const base::PlatformThreadId sampled_thread_id_;
std::unique_ptr<perfetto::TraceWriterBase> trace_writer_;
StackProfileWriter stack_profile_writer_;
uint32_t last_incremental_state_reset_id_ = 0;
base::TimeTicks last_timestamp_;
base::RepeatingClosure sample_callback_for_testing_;
UnwinderType unwinder_type_ = UnwinderType::kUnknown;
};
using CoreUnwindersCallback =
base::RepeatingCallback<base::StackSamplingProfiler::UnwindersFactory()>;
static std::unique_ptr<TracingSamplerProfiler> CreateOnMainThread(
CoreUnwindersCallback core_unwinders_factory_function =
CoreUnwindersCallback(),
UnwinderType unwinder_type = UnwinderType::kUnknown);
TracingSamplerProfiler(const TracingSamplerProfiler&) = delete;
TracingSamplerProfiler& operator=(const TracingSamplerProfiler&) = delete;
static void CreateOnChildThread();
static void CreateOnChildThreadWithCustomUnwinders(
CoreUnwindersCallback core_unwinders_factory_function);
static void RegisterDataSource();
static void SetAuxUnwinderFactoryOnMainThread(
const base::RepeatingCallback<std::unique_ptr<base::Unwinder>()>&
factory);
static void DeleteOnChildThreadForTesting();
static bool IsStackUnwindingSupportedForTesting();
explicit TracingSamplerProfiler(
base::SamplingProfilerThreadToken sampled_thread_token,
CoreUnwindersCallback core_unwinders_factory_function,
UnwinderType unwinder_type = UnwinderType::kUnknown);
virtual ~TracingSamplerProfiler();
void SetAuxUnwinderFactory(
const base::RepeatingCallback<std::unique_ptr<base::Unwinder>()>&
factory);
void SetSampleCallbackForTesting(
const base::RepeatingClosure& sample_callback_for_testing);
void StartTracing(std::unique_ptr<perfetto::TraceWriterBase> trace_writer,
bool should_enable_filtering);
void StopTracing();
private:
const base::SamplingProfilerThreadToken sampled_thread_token_;
CoreUnwindersCallback core_unwinders_factory_function_;
base::RepeatingCallback<std::unique_ptr<base::Unwinder>()>
aux_unwinder_factory_;
UnwinderType unwinder_type_;
base::Lock lock_;
std::unique_ptr<base::StackSamplingProfiler> profiler_ GUARDED_BY(lock_);
raw_ptr<TracingProfileBuilder, FlakyDanglingUntriaged> profile_builder_ =
nullptr;
base::RepeatingClosure sample_callback_for_testing_;
#if BUILDFLAG(ENABLE_LOADER_LOCK_SAMPLING)
std::unique_ptr<LoaderLockSamplingThread> loader_lock_sampling_thread_;
#endif
};
}
#endif