Commit fb87b8ba authored by Mike Wittman's avatar Mike Wittman Committed by Commit Bot

[Sampling profiler] Factor out platform config 2/4

Second in a series factoring the ThreadProfiler platform specific
configuration state from the code that takes action on the
state. Defines functions to handle runtime module state, which is
necessary for Android profiling.

The end goal is to reduce the configuration complexity, to support
enabling per-thread on Android.

Bug: 1129939
Change-Id: I4cb619ce15c94ec0b5d05d99de2b02eda6dab199
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2425184
Commit-Queue: Mike Wittman <wittman@chromium.org>
Reviewed-by: default avatarEtienne Pierre-Doray <etiennep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811584}
parent bcec2acd
...@@ -17,10 +17,6 @@ ...@@ -17,10 +17,6 @@
#include "extensions/buildflags/buildflags.h" #include "extensions/buildflags/buildflags.h"
#include "sandbox/policy/sandbox.h" #include "sandbox/policy/sandbox.h"
#if defined(OS_ANDROID)
#include "chrome/android/modules/stack_unwinder/public/module.h"
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/win/static_constants.h" #include "base/win/static_constants.h"
#endif #endif
...@@ -221,28 +217,20 @@ ThreadProfilerConfiguration::GenerateConfiguration( ...@@ -221,28 +217,20 @@ ThreadProfilerConfiguration::GenerateConfiguration(
return PROFILE_DISABLED; return PROFILE_DISABLED;
} }
#if defined(OS_ANDROID) using RuntimeModuleState =
// Allow profiling if the Android Java/native unwinder module is available at ThreadProfilerPlatformConfiguration::RuntimeModuleState;
// initialization time. Otherwise request that it be installed for use on the switch (platform_configuration.GetRuntimeModuleState(
// next run of Chrome and disable profiling. BUILDFLAG(GOOGLE_CHROME_BRANDING), channel)) {
if (!stack_unwinder::Module::IsInstalled()) { case RuntimeModuleState::kModuleAbsentButAvailable:
#if BUILDFLAG(GOOGLE_CHROME_BRANDING) platform_configuration.RequestRuntimeModuleInstall();
// We only want to incur the cost of universally downloading the module in FALLTHROUGH;
// early channels, where profiling will occur over substantially all of the case RuntimeModuleState::kModuleNotAvailable:
// population. When supporting later channels in the future we will enable
// profiling for only a fraction of users and only download for those users.
const version_info::Channel channel = chrome::GetChannel();
if (channel == version_info::Channel::CANARY ||
channel == version_info::Channel::DEV) {
stack_unwinder::Module::RequestInstallation();
}
#else
// This is a development build. The module is only available in the Play
// Store for releases so don't try to install it.
#endif
return PROFILE_DISABLED_MODULE_NOT_INSTALLED; return PROFILE_DISABLED_MODULE_NOT_INSTALLED;
case RuntimeModuleState::kModuleNotRequired:
case RuntimeModuleState::kModulePresent:
break;
} }
#endif
switch (chrome::GetChannel()) { switch (chrome::GetChannel()) {
// Enable the profiler unconditionally for development/waterfall builds. // Enable the profiler unconditionally for development/waterfall builds.
......
...@@ -4,8 +4,14 @@ ...@@ -4,8 +4,14 @@
#include "chrome/common/profiler/thread_profiler_platform_configuration.h" #include "chrome/common/profiler/thread_profiler_platform_configuration.h"
#include "base/command_line.h"
#include "base/profiler/stack_sampling_profiler.h" #include "base/profiler/stack_sampling_profiler.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/public/common/content_switches.h"
#if defined(OS_ANDROID)
#include "chrome/android/modules/stack_unwinder/public/module.h"
#endif
namespace { namespace {
...@@ -16,6 +22,11 @@ class DefaultPlatformConfiguration ...@@ -16,6 +22,11 @@ class DefaultPlatformConfiguration
public: public:
explicit DefaultPlatformConfiguration(bool browser_test_mode_enabled); explicit DefaultPlatformConfiguration(bool browser_test_mode_enabled);
// ThreadProfilerPlatformConfiguration:
RuntimeModuleState GetRuntimeModuleState(
bool is_chrome_branded,
version_info::Channel channel) const override;
protected: protected:
bool IsSupportedForChannel(bool is_chrome_branded, bool IsSupportedForChannel(bool is_chrome_branded,
version_info::Channel channel) const override; version_info::Channel channel) const override;
...@@ -30,6 +41,13 @@ DefaultPlatformConfiguration::DefaultPlatformConfiguration( ...@@ -30,6 +41,13 @@ DefaultPlatformConfiguration::DefaultPlatformConfiguration(
bool browser_test_mode_enabled) bool browser_test_mode_enabled)
: browser_test_mode_enabled_(browser_test_mode_enabled) {} : browser_test_mode_enabled_(browser_test_mode_enabled) {}
ThreadProfilerPlatformConfiguration::RuntimeModuleState
DefaultPlatformConfiguration::GetRuntimeModuleState(
bool is_chrome_branded,
version_info::Channel channel) const {
return RuntimeModuleState::kModuleNotRequired;
}
bool DefaultPlatformConfiguration::IsSupportedForChannel( bool DefaultPlatformConfiguration::IsSupportedForChannel(
bool is_chrome_branded, bool is_chrome_branded,
version_info::Channel channel) const { version_info::Channel channel) const {
...@@ -44,6 +62,12 @@ bool DefaultPlatformConfiguration::IsSupportedForChannel( ...@@ -44,6 +62,12 @@ bool DefaultPlatformConfiguration::IsSupportedForChannel(
} }
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
bool IsBrowserProcess() {
return base::CommandLine::ForCurrentProcess()
->GetSwitchValueASCII(switches::kProcessType)
.empty();
}
// The configuration to use for the Android platform. Applies to ARM32 which is // The configuration to use for the Android platform. Applies to ARM32 which is
// the only Android architecture currently supported by StackSamplingProfiler. // the only Android architecture currently supported by StackSamplingProfiler.
// Defined in terms of DefaultPlatformConfiguration where Android does not // Defined in terms of DefaultPlatformConfiguration where Android does not
...@@ -52,6 +76,13 @@ class AndroidPlatformConfiguration : public DefaultPlatformConfiguration { ...@@ -52,6 +76,13 @@ class AndroidPlatformConfiguration : public DefaultPlatformConfiguration {
public: public:
explicit AndroidPlatformConfiguration(bool browser_test_mode_enabled); explicit AndroidPlatformConfiguration(bool browser_test_mode_enabled);
// DefaultPlatformConfiguration:
RuntimeModuleState GetRuntimeModuleState(
bool is_chrome_branded,
version_info::Channel channel) const override;
void RequestRuntimeModuleInstall() const override;
protected: protected:
bool IsSupportedForChannel(bool is_chrome_branded, bool IsSupportedForChannel(bool is_chrome_branded,
version_info::Channel channel) const override; version_info::Channel channel) const override;
...@@ -61,6 +92,46 @@ AndroidPlatformConfiguration::AndroidPlatformConfiguration( ...@@ -61,6 +92,46 @@ AndroidPlatformConfiguration::AndroidPlatformConfiguration(
bool browser_test_mode_enabled) bool browser_test_mode_enabled)
: DefaultPlatformConfiguration(browser_test_mode_enabled) {} : DefaultPlatformConfiguration(browser_test_mode_enabled) {}
ThreadProfilerPlatformConfiguration::RuntimeModuleState
AndroidPlatformConfiguration::GetRuntimeModuleState(
bool is_chrome_branded,
version_info::Channel channel) const {
// The module will be present in releases due to having been installed via
// RequestRuntimeModuleInstall(), and in local/CQ builds of bundle targets
// where the module was installed with the bundle.
if (stack_unwinder::Module::IsInstalled())
return RuntimeModuleState::kModulePresent;
if (is_chrome_branded) {
// We only want to incur the cost of universally downloading the module in
// early channels, where profiling will occur over substantially all of
// the population. When supporting later channels in the future we will
// enable profiling for only a fraction of users and only download for
// those users.
if (channel == version_info::Channel::CANARY ||
channel == version_info::Channel::DEV) {
return RuntimeModuleState::kModuleAbsentButAvailable;
}
return RuntimeModuleState::kModuleNotAvailable;
}
// This is a local or CQ build of a bundle where the module was not
// installed with the bundle, or an apk where the module is not included.
// The module is installable from the Play Store only for released Chrome so
// is not available in this build.
return RuntimeModuleState::kModuleNotAvailable;
}
void AndroidPlatformConfiguration::RequestRuntimeModuleInstall() const {
// The install can only be done in the browser process.
CHECK(IsBrowserProcess());
// The install occurs asynchronously, with the module available at the first
// run of Chrome following install.
stack_unwinder::Module::RequestInstallation();
}
bool AndroidPlatformConfiguration::IsSupportedForChannel( bool AndroidPlatformConfiguration::IsSupportedForChannel(
bool is_chrome_branded, bool is_chrome_branded,
version_info::Channel channel) const { version_info::Channel channel) const {
......
...@@ -23,6 +23,19 @@ ...@@ -23,6 +23,19 @@
// overall enable/disable state should be reported to UMA in this case. // overall enable/disable state should be reported to UMA in this case.
class ThreadProfilerPlatformConfiguration { class ThreadProfilerPlatformConfiguration {
public: public:
// State of the runtime module used by the profiler on the platform (if any).
// Android in particular requires use of a dynamic feature modules to provide
// the native unwinder.
enum class RuntimeModuleState {
// States that allow profiling.
kModuleNotRequired, // No module is required.
kModulePresent, // The module is present for use.
// States that don't allow profiling in this run of Chrome.
kModuleAbsentButAvailable, // A module is not present but is installable.
kModuleNotAvailable, // A module is necessary but not available.
};
virtual ~ThreadProfilerPlatformConfiguration() = default; virtual ~ThreadProfilerPlatformConfiguration() = default;
// Create the platform configuration. // Create the platform configuration.
...@@ -33,6 +46,17 @@ class ThreadProfilerPlatformConfiguration { ...@@ -33,6 +46,17 @@ class ThreadProfilerPlatformConfiguration {
// to be run for the channel/chrome branding. // to be run for the channel/chrome branding.
bool IsSupported(bool is_chrome_branded, version_info::Channel channel) const; bool IsSupported(bool is_chrome_branded, version_info::Channel channel) const;
// Returns the current state of the runtime support module for the
// channel/chrome branding on the platform. Runtime module state is valid only
// if IsSupported().
virtual RuntimeModuleState GetRuntimeModuleState(
bool is_chrome_branded,
version_info::Channel channel) const = 0;
// Request install of the runtime support module. May be invoked only if
// GetRuntimeModuleState() returns kModuleAbsentButAvailable.
virtual void RequestRuntimeModuleInstall() const {}
protected: protected:
// True if the profiler is to be run for the channel/chrome branding on the // True if the profiler is to be run for the channel/chrome branding on the
// platform. Does not need to check whether the StackSamplingProfiler is // platform. Does not need to check whether the StackSamplingProfiler is
......
...@@ -17,53 +17,117 @@ ...@@ -17,53 +17,117 @@
#define THREAD_PROFILER_SUPPORTED_ON_PLATFORM false #define THREAD_PROFILER_SUPPORTED_ON_PLATFORM false
#endif #endif
// The browser_test_mode_enabled=true scenario is already covered by the browser class ThreadProfilerPlatformConfigurationTest : public ::testing::Test {
// tests so doesn't require separate testing here. public:
TEST(ThreadProfilerPlatformConfigurationTest, IsSupported) { // The browser_test_mode_enabled=true scenario is already covered by the
const std::unique_ptr<ThreadProfilerPlatformConfiguration> config = // browser tests so doesn't require separate testing here.
ThreadProfilerPlatformConfiguration::Create( ThreadProfilerPlatformConfigurationTest()
/*browser_test_mode_enabled=*/false); : config_(ThreadProfilerPlatformConfiguration::Create(
/*browser_test_mode_enabled=*/false)) {}
const std::unique_ptr<ThreadProfilerPlatformConfiguration>& config() {
return config_;
}
private:
const std::unique_ptr<ThreadProfilerPlatformConfiguration> config_;
};
#if THREAD_PROFILER_SUPPORTED_ON_PLATFORM
#define MAYBE_PLATFORM_CONFIG_TEST_F(suite, test) TEST_F(suite, test)
#else
#define MAYBE_PLATFORM_CONFIG_TEST_F(suite, test) TEST_F(suite, DISABLED_##test)
#endif
TEST_F(ThreadProfilerPlatformConfigurationTest, IsSupported) {
#if !THREAD_PROFILER_SUPPORTED_ON_PLATFORM #if !THREAD_PROFILER_SUPPORTED_ON_PLATFORM
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::CANARY)); version_info::Channel::CANARY));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::DEV)); version_info::Channel::DEV));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::BETA)); version_info::Channel::BETA));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::STABLE)); version_info::Channel::STABLE));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/false, EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/false,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN));
#elif defined(OS_ANDROID) #elif defined(OS_ANDROID)
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::UNKNOWN));
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::CANARY));
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::DEV));
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::BETA));
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::STABLE));
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/false,
version_info::Channel::UNKNOWN));
#else
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::UNKNOWN));
EXPECT_TRUE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::CANARY));
EXPECT_TRUE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::DEV));
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::BETA));
EXPECT_FALSE(config()->IsSupported(/*is_chrome_branded=*/true,
version_info::Channel::STABLE));
EXPECT_TRUE(config()->IsSupported(/*is_chrome_branded=*/false,
version_info::Channel::UNKNOWN));
#endif
}
MAYBE_PLATFORM_CONFIG_TEST_F(ThreadProfilerPlatformConfigurationTest,
GetRuntimeModuleState) {
using RuntimeModuleState =
ThreadProfilerPlatformConfiguration::RuntimeModuleState;
#if defined(OS_ANDROID)
EXPECT_EQ(RuntimeModuleState::kModuleNotAvailable,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleAbsentButAvailable,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::CANARY)); version_info::Channel::CANARY));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleAbsentButAvailable,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::DEV)); version_info::Channel::DEV));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleNotAvailable,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::BETA)); version_info::Channel::BETA));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleNotAvailable,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::STABLE)); version_info::Channel::STABLE));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/false, EXPECT_EQ(RuntimeModuleState::kModuleNotAvailable,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN));
#else #else
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleNotRequired,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN));
EXPECT_TRUE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleNotRequired,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::CANARY)); version_info::Channel::CANARY));
EXPECT_TRUE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleNotRequired,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::DEV)); version_info::Channel::DEV));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleNotRequired,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::BETA)); version_info::Channel::BETA));
EXPECT_FALSE(config->IsSupported(/*is_chrome_branded=*/true, EXPECT_EQ(RuntimeModuleState::kModuleNotRequired,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::STABLE)); version_info::Channel::STABLE));
EXPECT_TRUE(config->IsSupported(/*is_chrome_branded=*/false, EXPECT_EQ(RuntimeModuleState::kModuleNotRequired,
config()->GetRuntimeModuleState(/*is_chrome_branded=*/true,
version_info::Channel::UNKNOWN)); version_info::Channel::UNKNOWN));
#endif #endif
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment