Commit 983f291e authored by Etienne Pierre-doray's avatar Etienne Pierre-doray Committed by Commit Bot

[Clank SSM]: Enable stack sampling profiler tests on android

Bug: 989102
Change-Id: If733b62f4e5b2b3044c20935ef443748b47399b5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2201658
Commit-Queue: Etienne Pierre-Doray <etiennep@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Reviewed-by: default avatarMike Wittman <wittman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#775231}
parent 21869271
...@@ -91,6 +91,11 @@ dep_libevent = ...@@ -91,6 +91,11 @@ dep_libevent =
# Determines whether message_pump_libevent should be used. # Determines whether message_pump_libevent should be used.
use_libevent = dep_libevent && !is_ios use_libevent = dep_libevent && !is_ios
# Whether or not cfi table should be enabled on arm.
# TODO(crbug.com/1090409): Replace can_unwind_with_cfi_table once sampling
# profiler is enabled on android.
enable_arm_cfi_table = is_android && !is_component_build && current_cpu == "arm"
if (is_android) { if (is_android) {
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
} }
...@@ -2186,6 +2191,7 @@ buildflag_header("debugging_buildflags") { ...@@ -2186,6 +2191,7 @@ buildflag_header("debugging_buildflags") {
"CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers", "CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers",
"UNSAFE_DEVELOPER_BUILD=$is_unsafe_developer_build", "UNSAFE_DEVELOPER_BUILD=$is_unsafe_developer_build",
"CAN_UNWIND_WITH_CFI_TABLE=$can_unwind_with_cfi_table", "CAN_UNWIND_WITH_CFI_TABLE=$can_unwind_with_cfi_table",
"ENABLE_ARM_CFI_TABLE=$enable_arm_cfi_table",
"ENABLE_GDBINIT_WARNING=$enable_gdbinit_warning", "ENABLE_GDBINIT_WARNING=$enable_gdbinit_warning",
"ENABLE_LLDBINIT_WARNING=$enable_lldbinit_warning", "ENABLE_LLDBINIT_WARNING=$enable_lldbinit_warning",
] ]
...@@ -2505,6 +2511,9 @@ source_set("base_stack_sampling_profiler_test_util") { ...@@ -2505,6 +2511,9 @@ source_set("base_stack_sampling_profiler_test_util") {
"//base/test:test_support", "//base/test:test_support",
"//testing/gtest", "//testing/gtest",
] ]
if (is_android) {
deps += [ ":native_unwinder_android" ]
}
} }
bundle_data("base_unittests_bundle_data") { bundle_data("base_unittests_bundle_data") {
...@@ -3010,7 +3019,7 @@ test("base_unittests") { ...@@ -3010,7 +3019,7 @@ test("base_unittests") {
# generated from debug info in the binary. Removing "default_symbols" and # generated from debug info in the binary. Removing "default_symbols" and
# adding symbols config removes the "strip_debug" config that strips the # adding symbols config removes the "strip_debug" config that strips the
# debug info, on base unittests apk. # debug info, on base unittests apk.
if (can_unwind_with_cfi_table) { if (can_unwind_with_cfi_table || enable_arm_cfi_table) {
configs -= [ "//build/config/compiler:default_symbols" ] configs -= [ "//build/config/compiler:default_symbols" ]
if (symbol_level == 2) { if (symbol_level == 2) {
configs += [ "//build/config/compiler:symbols" ] configs += [ "//build/config/compiler:symbols" ]
...@@ -3018,6 +3027,8 @@ test("base_unittests") { ...@@ -3018,6 +3027,8 @@ test("base_unittests") {
configs += [ "//build/config/compiler:minimal_symbols" ] configs += [ "//build/config/compiler:minimal_symbols" ]
} }
add_unwind_tables_in_apk = true add_unwind_tables_in_apk = true
}
if (can_unwind_with_cfi_table) {
sources += [ "trace_event/cfi_backtrace_android_unittest.cc" ] sources += [ "trace_event/cfi_backtrace_android_unittest.cc" ]
} }
if (current_cpu == "arm") { if (current_cpu == "arm") {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/profiler/register_context.h" #include "base/profiler/register_context.h"
#include "base/profiler/stack_buffer.h" #include "base/profiler/stack_buffer.h"
#include "base/profiler/stack_copier_signal.h" #include "base/profiler/stack_copier_signal.h"
#include "base/profiler/stack_sampler.h"
#include "base/profiler/stack_sampling_profiler_test_util.h" #include "base/profiler/stack_sampling_profiler_test_util.h"
#include "base/profiler/thread_delegate_posix.h" #include "base/profiler/thread_delegate_posix.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
......
...@@ -18,6 +18,13 @@ ...@@ -18,6 +18,13 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
#include "base/android/apk_assets.h"
#include "base/files/memory_mapped_file.h"
#include "base/profiler/chrome_unwinder_android.h"
#include "base/profiler/native_unwinder_android.h"
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
// Windows doesn't provide an alloca function like Linux does. // Windows doesn't provide an alloca function like Linux does.
// Fortunately, it provides _alloca, which functions identically. // Fortunately, it provides _alloca, which functions identically.
...@@ -27,6 +34,13 @@ ...@@ -27,6 +34,13 @@
#include <alloca.h> #include <alloca.h>
#endif #endif
extern "C" {
// The address of |__executable_start| gives the start address of the
// executable or shared library. This value is used to find the offset address
// of the instruction in binary from PC.
extern char __executable_start;
}
namespace base { namespace base {
namespace { namespace {
...@@ -79,6 +93,69 @@ void OtherLibraryCallback(void* arg) { ...@@ -79,6 +93,69 @@ void OtherLibraryCallback(void* arg) {
ALLOW_UNUSED_LOCAL(i); ALLOW_UNUSED_LOCAL(i);
} }
#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
std::unique_ptr<NativeUnwinderAndroid> CreateNativeUnwinderAndroidForTesting(
uintptr_t exclude_module_with_base_address) {
class NativeUnwinderAndroidForTesting : public NativeUnwinderAndroid {
public:
explicit NativeUnwinderAndroidForTesting(
std::unique_ptr<unwindstack::Maps> memory_regions_map,
std::unique_ptr<unwindstack::Memory> process_memory,
uintptr_t exclude_module_with_base_address)
: NativeUnwinderAndroid(memory_regions_map.get(),
process_memory.get(),
exclude_module_with_base_address),
memory_regions_map_(std::move(memory_regions_map)),
process_memory_(std::move(process_memory)) {}
~NativeUnwinderAndroidForTesting() override = default;
private:
std::unique_ptr<unwindstack::Maps> memory_regions_map_;
std::unique_ptr<unwindstack::Memory> process_memory_;
};
auto maps = NativeUnwinderAndroid::CreateMaps();
auto memory = NativeUnwinderAndroid::CreateProcessMemory();
return std::make_unique<NativeUnwinderAndroidForTesting>(
std::move(maps), std::move(memory), exclude_module_with_base_address);
}
std::unique_ptr<Unwinder> CreateChromeUnwinderAndroidForTesting(
ModuleCache* module_cache) {
static constexpr char kCfiFileName[] = "assets/unwind_cfi_32";
class ChromeUnwinderAndroidForTesting : public ChromeUnwinderAndroid {
public:
ChromeUnwinderAndroidForTesting(std::unique_ptr<MemoryMappedFile> cfi_file,
std::unique_ptr<ArmCFITable> cfi_table,
const ModuleCache::Module* chrome_module)
: ChromeUnwinderAndroid(cfi_table.get(), chrome_module),
cfi_file_(std::move(cfi_file)),
cfi_table_(std::move(cfi_table)) {}
~ChromeUnwinderAndroidForTesting() override = default;
private:
std::unique_ptr<MemoryMappedFile> cfi_file_;
std::unique_ptr<ArmCFITable> cfi_table_;
};
MemoryMappedFile::Region cfi_region;
int fd = base::android::OpenApkAsset(kCfiFileName, &cfi_region);
if (fd < 0)
return nullptr;
auto cfi_file = std::make_unique<MemoryMappedFile>();
if (!cfi_file->Initialize(base::File(fd), cfi_region))
return nullptr;
std::unique_ptr<ArmCFITable> cfi_table =
ArmCFITable::Parse({cfi_file->data(), cfi_file->length()});
if (!cfi_table)
return nullptr;
return std::make_unique<ChromeUnwinderAndroidForTesting>(
std::move(cfi_file), std::move(cfi_table),
module_cache->GetModuleForAddress(
reinterpret_cast<uintptr_t>(&__executable_start)));
}
#endif // #if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
} // namespace } // namespace
TargetThread::TargetThread(OnceClosure to_run) : to_run_(std::move(to_run)) {} TargetThread::TargetThread(OnceClosure to_run) : to_run_(std::move(to_run)) {}
...@@ -240,7 +317,8 @@ std::vector<Frame> SampleScenario(UnwindScenario* scenario, ...@@ -240,7 +317,8 @@ std::vector<Frame> SampleScenario(UnwindScenario* scenario,
std::vector<Frame> result_sample) { std::vector<Frame> result_sample) {
sample = std::move(result_sample); sample = std::move(result_sample);
sampling_thread_completed.Signal(); sampling_thread_completed.Signal();
}))); })),
CreateCoreUnwindersForTesting(module_cache));
if (aux_unwinder_factory) if (aux_unwinder_factory)
profiler.AddAuxUnwinder(std::move(aux_unwinder_factory).Run()); profiler.AddAuxUnwinder(std::move(aux_unwinder_factory).Run());
profiler.Start(); profiler.Start();
...@@ -338,4 +416,17 @@ uintptr_t GetAddressInOtherLibrary(NativeLibrary library) { ...@@ -338,4 +416,17 @@ uintptr_t GetAddressInOtherLibrary(NativeLibrary library) {
return address; return address;
} }
std::vector<std::unique_ptr<Unwinder>> CreateCoreUnwindersForTesting(
ModuleCache* module_cache) {
#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
std::vector<std::unique_ptr<Unwinder>> unwinders;
unwinders.push_back(CreateNativeUnwinderAndroidForTesting(
reinterpret_cast<uintptr_t>(&__executable_start)));
unwinders.push_back(CreateChromeUnwinderAndroidForTesting(module_cache));
return unwinders;
#else
return {};
#endif
}
} // namespace base } // namespace base
...@@ -12,13 +12,13 @@ ...@@ -12,13 +12,13 @@
#include "base/native_library.h" #include "base/native_library.h"
#include "base/profiler/frame.h" #include "base/profiler/frame.h"
#include "base/profiler/sampling_profiler_thread_token.h" #include "base/profiler/sampling_profiler_thread_token.h"
#include "base/profiler/stack_sampler.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
namespace base { namespace base {
class Unwinder; class Unwinder;
class ModuleCache;
// A thread to target for profiling that will run the supplied closure. // A thread to target for profiling that will run the supplied closure.
class TargetThread : public PlatformThread::Delegate { class TargetThread : public PlatformThread::Delegate {
...@@ -140,6 +140,12 @@ NativeLibrary LoadOtherLibrary(); ...@@ -140,6 +140,12 @@ NativeLibrary LoadOtherLibrary();
uintptr_t GetAddressInOtherLibrary(NativeLibrary library); uintptr_t GetAddressInOtherLibrary(NativeLibrary library);
// Creates a list of core unwinders required for StackSamplingProfilerTest.
// This is useful notably on Android, which requires ChromeUnwinderAndroid in
// addition to the native one.
std::vector<std::unique_ptr<Unwinder>> CreateCoreUnwindersForTesting(
ModuleCache* module_cache);
} // namespace base } // namespace base
#endif // BASE_PROFILER_STACK_SAMPLING_PROFILER_TEST_UTIL_H_ #endif // BASE_PROFILER_STACK_SAMPLING_PROFILER_TEST_UTIL_H_
...@@ -47,7 +47,8 @@ ...@@ -47,7 +47,8 @@
// STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests // STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests
// below for supported platforms (currently Win x64 and Mac x64). // below for supported platforms (currently Win x64 and Mac x64).
#if defined(_WIN64) || (defined(OS_MACOSX) && !defined(OS_IOS)) #if defined(_WIN64) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
(defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE))
#define STACK_SAMPLING_PROFILER_SUPPORTED 1 #define STACK_SAMPLING_PROFILER_SUPPORTED 1
#endif #endif
...@@ -186,8 +187,8 @@ void SynchronousUnloadNativeLibrary(NativeLibrary library) { ...@@ -186,8 +187,8 @@ void SynchronousUnloadNativeLibrary(NativeLibrary library) {
::GetLastError() != ERROR_MOD_NOT_FOUND) { ::GetLastError() != ERROR_MOD_NOT_FOUND) {
PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
} }
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX) || defined(OS_ANDROID)
// Unloading a library on the Mac is synchronous. // Unloading a library on Mac and Android is synchronous.
#else #else
NOTIMPLEMENTED(); NOTIMPLEMENTED();
#endif #endif
...@@ -213,7 +214,7 @@ struct TestProfilerInfo { ...@@ -213,7 +214,7 @@ struct TestProfilerInfo {
profile = std::move(result_profile); profile = std::move(result_profile);
completed.Signal(); completed.Signal();
})), })),
{}, CreateCoreUnwindersForTesting(module_cache),
delegate) {} delegate) {}
// The order here is important to ensure objects being referenced don't get // The order here is important to ensure objects being referenced don't get
...@@ -347,7 +348,7 @@ void TestLibraryUnload(bool wait_until_unloaded, ModuleCache* module_cache) { ...@@ -347,7 +348,7 @@ void TestLibraryUnload(bool wait_until_unloaded, ModuleCache* module_cache) {
profile = std::move(result_profile); profile = std::move(result_profile);
sampling_thread_completed.Signal(); sampling_thread_completed.Signal();
})), })),
{}, &test_delegate); CreateCoreUnwindersForTesting(module_cache), &test_delegate);
profiler.Start(); profiler.Start();
...@@ -488,7 +489,9 @@ class TestAuxUnwinder : public Unwinder { ...@@ -488,7 +489,9 @@ class TestAuxUnwinder : public Unwinder {
// Checks that the profiler handles stacks containing dynamically-allocated // Checks that the profiler handles stacks containing dynamically-allocated
// stack memory. // stack memory.
// macOS ASAN is not yet supported - crbug.com/718628. // macOS ASAN is not yet supported - crbug.com/718628.
#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) // Android is not supported since Chrome unwind tables don't support dynamic
// frames.
#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) && !defined(OS_ANDROID)
#define MAYBE_Alloca Alloca #define MAYBE_Alloca Alloca
#else #else
#define MAYBE_Alloca DISABLED_Alloca #define MAYBE_Alloca DISABLED_Alloca
...@@ -538,7 +541,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) { ...@@ -538,7 +541,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) {
// Checks that a stack that runs through a library that has been unloaded // Checks that a stack that runs through a library that has been unloaded
// produces a stack, and doesn't crash. // produces a stack, and doesn't crash.
// macOS ASAN is not yet supported - crbug.com/718628. // macOS ASAN is not yet supported - crbug.com/718628.
#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) // Android is not supported since modules are found before unwinding.
#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) && !defined(OS_ANDROID)
#define MAYBE_UnloadedLibrary UnloadedLibrary #define MAYBE_UnloadedLibrary UnloadedLibrary
#else #else
#define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary #define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
...@@ -568,7 +572,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, StopWithoutStarting) { ...@@ -568,7 +572,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, StopWithoutStarting) {
[&profile, &sampling_completed](Profile result_profile) { [&profile, &sampling_completed](Profile result_profile) {
profile = std::move(result_profile); profile = std::move(result_profile);
sampling_completed.Signal(); sampling_completed.Signal();
}))); })),
CreateCoreUnwindersForTesting(module_cache()));
profiler.Stop(); // Constructed but never started. profiler.Stop(); // Constructed but never started.
EXPECT_FALSE(sampling_completed.IsSignaled()); EXPECT_FALSE(sampling_completed.IsSignaled());
...@@ -787,8 +792,9 @@ PROFILER_TEST_F(StackSamplingProfilerTest, DestroyProfilerWhileProfiling) { ...@@ -787,8 +792,9 @@ PROFILER_TEST_F(StackSamplingProfilerTest, DestroyProfilerWhileProfiling) {
BindLambdaForTesting([&profile](Profile result_profile) { BindLambdaForTesting([&profile](Profile result_profile) {
profile = std::move(result_profile); profile = std::move(result_profile);
})); }));
profiler.reset(new StackSamplingProfiler(target_thread_token, params, profiler.reset(new StackSamplingProfiler(
std::move(profile_builder))); target_thread_token, params, std::move(profile_builder),
CreateCoreUnwindersForTesting(module_cache())));
profiler->Start(); profiler->Start();
profiler.reset(); profiler.reset();
...@@ -1139,7 +1145,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) { ...@@ -1139,7 +1145,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) {
[&profile1, &sampling_thread_completed1](Profile result_profile) { [&profile1, &sampling_thread_completed1](Profile result_profile) {
profile1 = std::move(result_profile); profile1 = std::move(result_profile);
sampling_thread_completed1.Signal(); sampling_thread_completed1.Signal();
}))); })),
CreateCoreUnwindersForTesting(module_cache()));
WaitableEvent sampling_thread_completed2( WaitableEvent sampling_thread_completed2(
WaitableEvent::ResetPolicy::MANUAL, WaitableEvent::ResetPolicy::MANUAL,
...@@ -1152,7 +1159,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) { ...@@ -1152,7 +1159,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) {
[&profile2, &sampling_thread_completed2](Profile result_profile) { [&profile2, &sampling_thread_completed2](Profile result_profile) {
profile2 = std::move(result_profile); profile2 = std::move(result_profile);
sampling_thread_completed2.Signal(); sampling_thread_completed2.Signal();
}))); })),
CreateCoreUnwindersForTesting(module_cache()));
// Finally the real work. // Finally the real work.
profiler1.Start(); profiler1.Start();
...@@ -1187,8 +1195,8 @@ class ProfilerThread : public SimpleThread { ...@@ -1187,8 +1195,8 @@ class ProfilerThread : public SimpleThread {
BindLambdaForTesting([this](Profile result_profile) { BindLambdaForTesting([this](Profile result_profile) {
profile_ = std::move(result_profile); profile_ = std::move(result_profile);
completed_.Signal(); completed_.Signal();
}))) {} })),
CreateCoreUnwindersForTesting(module_cache)) {}
void Run() override { void Run() override {
run_.Wait(); run_.Wait();
profiler_.Start(); profiler_.Start();
...@@ -1273,7 +1281,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_BeforeStart) { ...@@ -1273,7 +1281,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_BeforeStart) {
Profile result_profile) { Profile result_profile) {
profile = std::move(result_profile); profile = std::move(result_profile);
sampling_thread_completed.Signal(); sampling_thread_completed.Signal();
}))); })),
CreateCoreUnwindersForTesting(module_cache()));
profiler.AddAuxUnwinder( profiler.AddAuxUnwinder(
std::make_unique<TestAuxUnwinder>(Frame(23, nullptr))); std::make_unique<TestAuxUnwinder>(Frame(23, nullptr)));
profiler.Start(); profiler.Start();
...@@ -1313,7 +1322,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_AfterStart) { ...@@ -1313,7 +1322,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_AfterStart) {
Profile result_profile) { Profile result_profile) {
profile = std::move(result_profile); profile = std::move(result_profile);
sampling_thread_completed.Signal(); sampling_thread_completed.Signal();
}))); })),
CreateCoreUnwindersForTesting(module_cache()));
profiler.Start(); profiler.Start();
profiler.AddAuxUnwinder( profiler.AddAuxUnwinder(
std::make_unique<TestAuxUnwinder>(Frame(23, nullptr))); std::make_unique<TestAuxUnwinder>(Frame(23, nullptr)));
...@@ -1353,7 +1363,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_AfterStop) { ...@@ -1353,7 +1363,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_AfterStop) {
Profile result_profile) { Profile result_profile) {
profile = std::move(result_profile); profile = std::move(result_profile);
sampling_thread_completed.Signal(); sampling_thread_completed.Signal();
}))); })),
CreateCoreUnwindersForTesting(module_cache()));
profiler.Start(); profiler.Start();
profiler.Stop(); profiler.Stop();
profiler.AddAuxUnwinder( profiler.AddAuxUnwinder(
...@@ -1427,7 +1438,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest, ...@@ -1427,7 +1438,8 @@ PROFILER_TEST_F(StackSamplingProfilerTest,
BindLambdaForTesting([&profile](Profile result_profile) { BindLambdaForTesting([&profile](Profile result_profile) {
profile = std::move(result_profile); profile = std::move(result_profile);
})), })),
{}, &post_sample_invoker); CreateCoreUnwindersForTesting(module_cache()),
&post_sample_invoker);
profiler.Start(); profiler.Start();
// Wait for 5 samples to be collected. // Wait for 5 samples to be collected.
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
......
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