#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "base/profiler/stack_sampler.h"
#include <algorithm>
#include <cstring>
#include <iterator>
#include <memory>
#include <numeric>
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/profiler/module_cache.h"
#include "base/profiler/profile_builder.h"
#include "base/profiler/stack_buffer.h"
#include "base/profiler/stack_copier.h"
#include "base/profiler/stack_sampling_profiler_test_util.h"
#include "base/profiler/suspendable_thread_delegate.h"
#include "base/profiler/unwinder.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
ElementsAre;
class StackSamplerTest : public ::testing::Test { … };
class TestProfileBuilder : public ProfileBuilder { … };
class TestStackCopier : public StackCopier { … };
class DelegateInvokingStackCopier : public StackCopier { … };
class TestUnwinder : public Unwinder { … };
class CallRecordingUnwinder : public Unwinder { … };
std::vector<std::unique_ptr<const ModuleCache::Module>> ToModuleVector(
std::unique_ptr<const ModuleCache::Module> module) { … }
void InjectModuleForContextInstructionPointer(
const std::vector<uintptr_t>& stack,
ModuleCache* module_cache) { … }
uintptr_t GetTestInstructionPointer() { … }
class FakeTestUnwinder : public Unwinder { … };
StackSampler::UnwindersFactory MakeUnwindersFactory(
std::unique_ptr<Unwinder> unwinder) { … }
std::vector<UnwinderCapture> MakeUnwinderStateVector(Unwinder* native_unwinder,
Unwinder* aux_unwinder) { … }
}
TEST_F(StackSamplerTest, CopyStack) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(StackSamplerTest, RecordStackFramesUMAMetric) {
base::test::TestFuture<void> sample_completed;
HistogramTester histogram_tester;
auto unwind_data = std::make_unique<StackUnwindData>(
std::make_unique<TestProfileBuilder>(&module_cache_));
std::vector<uintptr_t> stack;
constexpr size_t UIntPtrsPerKilobyte = 1024 / sizeof(uintptr_t);
constexpr int kExpectedSizeKB = 2048;
for (uintptr_t i = 0; i <= (kExpectedSizeKB * UIntPtrsPerKilobyte) + 1; i++) {
stack.push_back(i);
}
InjectModuleForContextInstructionPointer(stack, &module_cache_);
std::vector<uintptr_t> stack_copy;
std::unique_ptr<StackSampler> stack_sampler = StackSampler::CreateForTesting(
std::make_unique<TestStackCopier>(stack), std::move(unwind_data),
MakeUnwindersFactory(std::make_unique<TestUnwinder>(&stack_copy)));
stack_sampler->Initialize();
std::unique_ptr<StackBuffer> stack_buffer =
std::make_unique<StackBuffer>(stack.size() * sizeof(uintptr_t));
for (uint32_t i = 0; i < StackSampler::kUMAHistogramDownsampleAmount - 1;
i++) {
stack_sampler->RecordStackFrames(stack_buffer.get(),
PlatformThread::CurrentId(), DoNothing());
histogram_tester.ExpectUniqueSample(
"Memory.StackSamplingProfiler.StackSampleSize2", kExpectedSizeKB, 0);
}
stack_sampler->RecordStackFrames(stack_buffer.get(),
PlatformThread::CurrentId(),
sample_completed.GetCallback());
ASSERT_TRUE(sample_completed.Wait());
histogram_tester.ExpectUniqueSample(
"Memory.StackSamplingProfiler.StackSampleSize2", kExpectedSizeKB, 1);
}
#endif
TEST_F(StackSamplerTest, CopyStackTimestamp) { … }
TEST_F(StackSamplerTest, UnwinderInvokedWhileRecordingStackFrames) { … }
TEST_F(StackSamplerTest, AuxUnwinderInvokedWhileRecordingStackFrames) { … }
TEST_F(StackSamplerTest, WalkStack_Completed) { … }
TEST_F(StackSamplerTest, WalkStack_Aborted) { … }
TEST_F(StackSamplerTest, WalkStack_NotUnwound) { … }
TEST_F(StackSamplerTest, WalkStack_AuxUnwind) { … }
TEST_F(StackSamplerTest, WalkStack_AuxThenNative) { … }
TEST_F(StackSamplerTest, WalkStack_NativeThenAux) { … }
}