blob: d971189dc2a89f2beb9c906b020bad0786ad3cc1 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2021 The Chromium Authors
Mike Chend3e070062021-01-20 17:07:072// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Peter Kasting134ef9af2024-12-28 02:30:095#include "base/debug/stack_trace.h"
6
Mike Chend3e070062021-01-20 17:07:077#include <vector>
8
Daniel Chenga0e290d2023-10-16 18:47:249#include "base/containers/span.h"
Mike Chend3e070062021-01-20 17:07:0710#include "base/logging.h"
11#include "base/strings/stringprintf.h"
12#include "base/timer/lap_timer.h"
13#include "testing/gtest/include/gtest/gtest.h"
14#include "testing/perf/perf_result_reporter.h"
15
Peter Kasting811504a72025-01-09 03:18:5016namespace base::debug {
Mike Chend3e070062021-01-20 17:07:0717
18// Change kTimeLimit to something higher if you need more time to capture a
19// trace.
Peter Kastinge5a38ed2021-10-02 03:06:3520constexpr base::TimeDelta kTimeLimit = base::Seconds(3);
Mike Chend3e070062021-01-20 17:07:0721constexpr int kWarmupRuns = 100;
22constexpr int kTimeCheckInterval = 1000;
23constexpr char kMetricStackTraceDuration[] = ".duration_per_run";
24constexpr char kMetricStackTraceThroughput[] = ".throughput";
25constexpr int kNumTracerObjAllocs = 5000;
26
27perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
28 perf_test::PerfResultReporter reporter("StackTracePerf", story_name);
29 reporter.RegisterImportantMetric(kMetricStackTraceDuration, "ns");
30 reporter.RegisterImportantMetric(kMetricStackTraceThroughput, "runs/s");
31 return reporter;
32}
33
34class StackTracer {
35 public:
Peter Kasting811504a72025-01-09 03:18:5036 explicit StackTracer(size_t trace_count) : trace_count_(trace_count) {}
Mike Chend3e070062021-01-20 17:07:0737 void Trace() {
Daniel Chenga0e290d2023-10-16 18:47:2438 StackTrace st(trace_count_);
39 span<const void* const> addresses = st.addresses();
Mike Chend3e070062021-01-20 17:07:0740 // make sure a valid array of stack frames is returned
Daniel Chenga0e290d2023-10-16 18:47:2441 ASSERT_FALSE(addresses.empty());
Peter Kasting654bb6252024-11-16 02:29:0842 EXPECT_NE(nullptr, addresses[0]);
Mike Chend3e070062021-01-20 17:07:0743 // make sure the test generates the intended count of stack frames
Daniel Chenga0e290d2023-10-16 18:47:2444 EXPECT_EQ(trace_count_, addresses.size());
Mike Chend3e070062021-01-20 17:07:0745 }
46
47 private:
Daniel Chenga0e290d2023-10-16 18:47:2448 const size_t trace_count_;
Mike Chend3e070062021-01-20 17:07:0749};
50
51void MultiObjTest(size_t trace_count) {
52 // Measures average stack trace generation (unwinding) performance across
53 // multiple objects to get a more realistic figure. Calling
54 // base::debug::StraceTrace() repeatedly from the same object may lead to
55 // unrealistic performance figures that are optimised by the host (for
56 // example, CPU caches distorting the results), whereas MTE requires
57 // unwinding for allocations that occur all over the place.
58 perf_test::PerfResultReporter reporter =
59 SetUpReporter(base::StringPrintf("trace_count_%zu", trace_count));
60 LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval,
61 LapTimer::TimerMethod::kUseTimeTicks);
62 std::vector<std::unique_ptr<StackTracer>> tracers;
63 for (int i = 0; i < kNumTracerObjAllocs; ++i) {
64 tracers.push_back(std::make_unique<StackTracer>(trace_count));
65 }
66 std::vector<std::unique_ptr<StackTracer>>::iterator it = tracers.begin();
67 timer.Start();
68 do {
69 (*it)->Trace();
Peter Kasting134ef9af2024-12-28 02:30:0970 if (++it == tracers.end()) {
Mike Chend3e070062021-01-20 17:07:0771 it = tracers.begin();
Peter Kasting134ef9af2024-12-28 02:30:0972 }
Mike Chend3e070062021-01-20 17:07:0773 timer.NextLap();
74 } while (!timer.HasTimeLimitExpired());
75 reporter.AddResult(kMetricStackTraceDuration, timer.TimePerLap());
76 reporter.AddResult(kMetricStackTraceThroughput, timer.LapsPerSecond());
77}
78
79class StackTracePerfTest : public testing::TestWithParam<size_t> {};
80
81INSTANTIATE_TEST_SUITE_P(,
82 StackTracePerfTest,
83 ::testing::Range(size_t(4), size_t(16), size_t(4)));
84
85TEST_P(StackTracePerfTest, MultiObj) {
86 size_t parm = GetParam();
87 MultiObjTest(parm);
88}
89
Peter Kasting811504a72025-01-09 03:18:5090} // namespace base::debug