#include "chrome/common/profiler/thread_profiler_platform_configuration.h"
#include "base/command_line.h"
#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/functional/callback.h"
#include "base/notreached.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "base/rand_util.h"
#include "build/build_config.h"
#include "chrome/common/profiler/process_type.h"
#include "components/sampling_profiler/process_type.h"
BASE_FEATURE(kSamplingProfilerOnWorkerThreads,
base::FEATURE_DISABLED_BY_DEFAULT);
namespace {
class DefaultPlatformConfiguration
: public ThreadProfilerPlatformConfiguration {
public:
explicit DefaultPlatformConfiguration(bool browser_test_mode_enabled);
RelativePopulations GetEnableRates(
std::optional<version_info::Channel> release_channel) const override;
double GetChildProcessPerExecutionEnableFraction(
sampling_profiler::ProfilerProcessType process) const override;
std::optional<sampling_profiler::ProfilerProcessType> ChooseEnabledProcess()
const override;
bool IsEnabledForThread(
sampling_profiler::ProfilerProcessType process,
sampling_profiler::ProfilerThreadType thread,
std::optional<version_info::Channel> release_channel) const override;
protected:
bool IsSupportedForChannel(
std::optional<version_info::Channel> release_channel) const override;
bool browser_test_mode_enabled() const { return browser_test_mode_enabled_; }
private:
const bool browser_test_mode_enabled_;
};
DefaultPlatformConfiguration::DefaultPlatformConfiguration(
bool browser_test_mode_enabled)
: browser_test_mode_enabled_(browser_test_mode_enabled) {}
ThreadProfilerPlatformConfiguration::RelativePopulations
DefaultPlatformConfiguration::GetEnableRates(
std::optional<version_info::Channel> release_channel) const {
CHECK(IsSupportedForChannel(release_channel));
if (!release_channel) {
return RelativePopulations{0.0, 100.0, 0.0};
}
#if BUILDFLAG(IS_CHROMEOS)
if (browser_test_mode_enabled()) {
return RelativePopulations{0.0, 100.0, 0.0};
}
#endif
CHECK_NE(*release_channel, version_info::Channel::UNKNOWN);
switch (*release_channel) {
case version_info::Channel::BETA: {
return RelativePopulations{90.0, 0.0, 10.0};
}
case version_info::Channel::STABLE: {
static constexpr double experiment_rate = 0.006;
return RelativePopulations{100.0 - experiment_rate, 0.0, experiment_rate};
}
default:
return RelativePopulations{0.0, 80.0, 20.0};
}
}
double DefaultPlatformConfiguration::GetChildProcessPerExecutionEnableFraction(
sampling_profiler::ProfilerProcessType process) const {
DCHECK_NE(sampling_profiler::ProfilerProcessType::kBrowser, process);
if (browser_test_mode_enabled()) {
return 1.0;
}
switch (process) {
case sampling_profiler::ProfilerProcessType::kGpu:
case sampling_profiler::ProfilerProcessType::kNetworkService:
return 1.0;
case sampling_profiler::ProfilerProcessType::kRenderer:
return 0.2;
default:
return 0.0;
}
}
std::optional<sampling_profiler::ProfilerProcessType>
DefaultPlatformConfiguration::ChooseEnabledProcess() const {
return std::nullopt;
}
bool DefaultPlatformConfiguration::IsEnabledForThread(
sampling_profiler::ProfilerProcessType process,
sampling_profiler::ProfilerThreadType thread,
std::optional<version_info::Channel> release_channel) const {
if (thread == sampling_profiler::ProfilerThreadType::kThreadPoolWorker) {
return base::FeatureList::IsEnabled(kSamplingProfilerOnWorkerThreads);
}
return true;
}
bool DefaultPlatformConfiguration::IsSupportedForChannel(
std::optional<version_info::Channel> release_channel) const {
if (!release_channel)
return true;
#if BUILDFLAG(IS_CHROMEOS)
if (browser_test_mode_enabled()) {
return true;
}
#endif
return *release_channel != version_info::Channel::UNKNOWN;
}
#if BUILDFLAG(IS_ANDROID)
class AndroidPlatformConfiguration : public DefaultPlatformConfiguration {
public:
explicit AndroidPlatformConfiguration(
bool browser_test_mode_enabled,
base::RepeatingCallback<bool(double)> is_enabled_on_dev_callback);
RelativePopulations GetEnableRates(
std::optional<version_info::Channel> release_channel) const override;
double GetChildProcessPerExecutionEnableFraction(
sampling_profiler::ProfilerProcessType process) const override;
std::optional<sampling_profiler::ProfilerProcessType> ChooseEnabledProcess()
const override;
bool IsEnabledForThread(
sampling_profiler::ProfilerProcessType process,
sampling_profiler::ProfilerThreadType thread,
std::optional<version_info::Channel> release_channel) const override;
bool IsSupportedForChannel(
std::optional<version_info::Channel> release_channel) const override;
private:
const base::flat_map<sampling_profiler::ProfilerThreadType, bool>
thread_enabled_on_dev_;
};
AndroidPlatformConfiguration::AndroidPlatformConfiguration(
bool browser_test_mode_enabled,
base::RepeatingCallback<bool(double)> is_enabled_on_dev_callback)
: DefaultPlatformConfiguration(browser_test_mode_enabled),
thread_enabled_on_dev_(
base::MakeFlatMap<sampling_profiler::ProfilerThreadType, bool>(
[]() {
std::vector<sampling_profiler::ProfilerThreadType> threads;
for (int i = 0;
i <= static_cast<int>(
sampling_profiler::ProfilerThreadType::kMax);
i++) {
threads.push_back(
static_cast<sampling_profiler::ProfilerThreadType>(i));
}
return threads;
}(),
{},
[&](sampling_profiler::ProfilerThreadType thread) {
return std::make_pair(thread,
is_enabled_on_dev_callback.Run(0.25));
})) {}
ThreadProfilerPlatformConfiguration::RelativePopulations
AndroidPlatformConfiguration::GetEnableRates(
std::optional<version_info::Channel> release_channel) const {
if (!release_channel.has_value() || browser_test_mode_enabled()) {
return RelativePopulations{0.0, 100.0, 0.0};
}
CHECK(*release_channel != version_info::Channel::UNKNOWN);
if (*release_channel == version_info::Channel::STABLE) {
#if defined(ARCH_CPU_ARM64)
static constexpr double experiment_rate = 0.0001;
return RelativePopulations{100.0 - experiment_rate, 0.0, experiment_rate};
#else
return RelativePopulations{100.0, 0.0, 0.0};
#endif
}
if (*release_channel == version_info::Channel::BETA) {
return RelativePopulations{0.0, 0.0, 100.0};
}
return RelativePopulations{0.0, 0.0, 100.0};
}
double AndroidPlatformConfiguration::GetChildProcessPerExecutionEnableFraction(
sampling_profiler::ProfilerProcessType process) const {
return 1.0;
}
std::optional<sampling_profiler::ProfilerProcessType>
AndroidPlatformConfiguration::ChooseEnabledProcess() const {
const struct {
sampling_profiler::ProfilerProcessType process;
int weight;
} process_enable_weights[] = {
{sampling_profiler::ProfilerProcessType::kBrowser, 50},
{sampling_profiler::ProfilerProcessType::kGpu, 40},
{sampling_profiler::ProfilerProcessType::kRenderer, 10},
};
int total_weight = 0;
for (const auto& process_enable_weight : process_enable_weights) {
total_weight += process_enable_weight.weight;
}
DCHECK_EQ(100, total_weight);
int chosen = base::RandInt(0, total_weight - 1);
int cumulative_weight = 0;
for (const auto& process_enable_weight : process_enable_weights) {
if (chosen >= cumulative_weight &&
chosen < cumulative_weight + process_enable_weight.weight) {
return process_enable_weight.process;
}
cumulative_weight += process_enable_weight.weight;
}
NOTREACHED();
}
bool AndroidPlatformConfiguration::IsEnabledForThread(
sampling_profiler::ProfilerProcessType process,
sampling_profiler::ProfilerThreadType thread,
std::optional<version_info::Channel> release_channel) const {
if (!DefaultPlatformConfiguration::IsEnabledForThread(process, thread,
release_channel)) {
return false;
}
if (!release_channel.has_value() || browser_test_mode_enabled()) {
return true;
}
switch (*release_channel) {
case version_info::Channel::BETA:
case version_info::Channel::DEV: {
const auto entry = thread_enabled_on_dev_.find(thread);
CHECK(entry != thread_enabled_on_dev_.end());
return entry->second;
}
case version_info::Channel::CANARY:
return true;
default:
return false;
}
}
bool AndroidPlatformConfiguration::IsSupportedForChannel(
std::optional<version_info::Channel> release_channel) const {
if (!release_channel) {
return true;
}
switch (*release_channel) {
case version_info::Channel::CANARY:
case version_info::Channel::DEV:
case version_info::Channel::BETA:
#if defined(ARCH_CPU_ARM64)
case version_info::Channel::STABLE:
#endif
return true;
default:
return false;
}
}
#endif
}
std::unique_ptr<ThreadProfilerPlatformConfiguration>
ThreadProfilerPlatformConfiguration::Create(
bool browser_test_mode_enabled,
base::RepeatingCallback<bool(double)> is_enabled_on_dev_callback) {
#if BUILDFLAG(IS_ANDROID)
return std::make_unique<AndroidPlatformConfiguration>(
browser_test_mode_enabled, is_enabled_on_dev_callback);
#else
return std::make_unique<DefaultPlatformConfiguration>(
browser_test_mode_enabled);
#endif
}
bool ThreadProfilerPlatformConfiguration::IsSupported(
std::optional<version_info::Channel> release_channel) const {
return base::StackSamplingProfiler::IsSupportedForCurrentPlatform() &&
IsSupportedForChannel(release_channel);
}
bool ThreadProfilerPlatformConfiguration::IsEnabled(
double enabled_probability) {
DCHECK_GE(enabled_probability, 0.0);
DCHECK_LE(enabled_probability, 1.0);
return base::RandDouble() < enabled_probability;
}