Commit d3e07006 authored by Mike Chen's avatar Mike Chen Committed by Chromium LUCI CQ

add perf test for unwinding

This is to enable performance measurements of individual optimisations
on stack tracing.

To provide useful debugging information, Arm's Memory Tagging Extension
(MTE) requires capturing stack traces on each allocation, therefore
unwinding is a performance-sensitive operation.  We're also planning to
change Chrome's unwinders for MTE's complementary technologies (PAC and
BTI). This test will help us measure the impact of these various flags
and changes, check for regressions, and help us find optimizations.

Bug: 1137393

Change-Id: I768c2dcf2cacdc5bba2cdec81d973b87ba3d4ea0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2621832
Commit-Queue: Richard Townsend <richard.townsend@arm.com>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#845185}
parent fb66f617
...@@ -2526,6 +2526,12 @@ test("base_perftests") { ...@@ -2526,6 +2526,12 @@ test("base_perftests") {
deps += [ "//testing/android/native_test:native_test_native_code" ] deps += [ "//testing/android/native_test:native_test_native_code" ]
shard_timeout = 600 shard_timeout = 600
} }
if (!is_official_build) {
# The extra data tables required by stack traces are turned off for official
# build, only do stack trace perftest for unofficial build
sources += [ "debug/stack_trace_perftest.cc" ]
}
} }
test("base_i18n_perftests") { test("base_i18n_perftests") {
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/timer/lap_timer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace base {
namespace debug {
// Change kTimeLimit to something higher if you need more time to capture a
// trace.
constexpr base::TimeDelta kTimeLimit = base::TimeDelta::FromSeconds(3);
constexpr int kWarmupRuns = 100;
constexpr int kTimeCheckInterval = 1000;
constexpr char kMetricStackTraceDuration[] = ".duration_per_run";
constexpr char kMetricStackTraceThroughput[] = ".throughput";
constexpr int kNumTracerObjAllocs = 5000;
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter("StackTracePerf", story_name);
reporter.RegisterImportantMetric(kMetricStackTraceDuration, "ns");
reporter.RegisterImportantMetric(kMetricStackTraceThroughput, "runs/s");
return reporter;
}
class StackTracer {
public:
StackTracer(size_t trace_count) : trace_count(trace_count) {}
void Trace() {
size_t tmp;
base::debug::StackTrace st(trace_count);
const void* addresses = st.Addresses(&tmp);
// make sure a valid array of stack frames is returned
EXPECT_NE(addresses, nullptr);
// make sure the test generates the intended count of stack frames
EXPECT_EQ(trace_count, tmp);
}
private:
const size_t trace_count;
};
void MultiObjTest(size_t trace_count) {
// Measures average stack trace generation (unwinding) performance across
// multiple objects to get a more realistic figure. Calling
// base::debug::StraceTrace() repeatedly from the same object may lead to
// unrealistic performance figures that are optimised by the host (for
// example, CPU caches distorting the results), whereas MTE requires
// unwinding for allocations that occur all over the place.
perf_test::PerfResultReporter reporter =
SetUpReporter(base::StringPrintf("trace_count_%zu", trace_count));
LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval,
LapTimer::TimerMethod::kUseTimeTicks);
std::vector<std::unique_ptr<StackTracer>> tracers;
for (int i = 0; i < kNumTracerObjAllocs; ++i) {
tracers.push_back(std::make_unique<StackTracer>(trace_count));
}
std::vector<std::unique_ptr<StackTracer>>::iterator it = tracers.begin();
timer.Start();
do {
(*it)->Trace();
if (++it == tracers.end())
it = tracers.begin();
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
reporter.AddResult(kMetricStackTraceDuration, timer.TimePerLap());
reporter.AddResult(kMetricStackTraceThroughput, timer.LapsPerSecond());
}
class StackTracePerfTest : public testing::TestWithParam<size_t> {};
INSTANTIATE_TEST_SUITE_P(,
StackTracePerfTest,
::testing::Range(size_t(4), size_t(16), size_t(4)));
TEST_P(StackTracePerfTest, MultiObj) {
size_t parm = GetParam();
MultiObjTest(parm);
}
} // namespace debug
} // namespace base
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