xref: /aosp_15_r20/external/cronet/base/debug/stack_trace_perftest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <vector>
6 
7 #include "base/containers/span.h"
8 #include "base/debug/stack_trace.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/timer/lap_timer.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "testing/perf/perf_result_reporter.h"
14 
15 namespace base {
16 namespace debug {
17 
18 // Change kTimeLimit to something higher if you need more time to capture a
19 // trace.
20 constexpr base::TimeDelta kTimeLimit = base::Seconds(3);
21 constexpr int kWarmupRuns = 100;
22 constexpr int kTimeCheckInterval = 1000;
23 constexpr char kMetricStackTraceDuration[] = ".duration_per_run";
24 constexpr char kMetricStackTraceThroughput[] = ".throughput";
25 constexpr int kNumTracerObjAllocs = 5000;
26 
SetUpReporter(const std::string & story_name)27 perf_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 
34 class StackTracer {
35  public:
StackTracer(size_t trace_count)36   StackTracer(size_t trace_count) : trace_count_(trace_count) {}
Trace()37   void Trace() {
38     StackTrace st(trace_count_);
39     span<const void* const> addresses = st.addresses();
40     // make sure a valid array of stack frames is returned
41     ASSERT_FALSE(addresses.empty());
42     EXPECT_TRUE(addresses[0]);
43     // make sure the test generates the intended count of stack frames
44     EXPECT_EQ(trace_count_, addresses.size());
45   }
46 
47  private:
48   const size_t trace_count_;
49 };
50 
MultiObjTest(size_t trace_count)51 void 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();
70     if (++it == tracers.end())
71       it = tracers.begin();
72     timer.NextLap();
73   } while (!timer.HasTimeLimitExpired());
74   reporter.AddResult(kMetricStackTraceDuration, timer.TimePerLap());
75   reporter.AddResult(kMetricStackTraceThroughput, timer.LapsPerSecond());
76 }
77 
78 class StackTracePerfTest : public testing::TestWithParam<size_t> {};
79 
80 INSTANTIATE_TEST_SUITE_P(,
81                          StackTracePerfTest,
82                          ::testing::Range(size_t(4), size_t(16), size_t(4)));
83 
TEST_P(StackTracePerfTest,MultiObj)84 TEST_P(StackTracePerfTest, MultiObj) {
85   size_t parm = GetParam();
86   MultiObjTest(parm);
87 }
88 
89 }  // namespace debug
90 }  // namespace base
91