xref: /aosp_15_r20/external/cronet/base/debug/allocation_trace_perftest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include <thread>
6*6777b538SAndroid Build Coastguard Worker #include <vector>
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include "base/allocator/dispatcher/notification_data.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/allocator/dispatcher/subsystem.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/debug/allocation_trace.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/timer/lap_timer.h"
13*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
14*6777b538SAndroid Build Coastguard Worker #include "testing/perf/perf_result_reporter.h"
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker namespace base {
17*6777b538SAndroid Build Coastguard Worker namespace debug {
18*6777b538SAndroid Build Coastguard Worker namespace {
19*6777b538SAndroid Build Coastguard Worker // Change kTimeLimit to something higher if you need more time to capture a
20*6777b538SAndroid Build Coastguard Worker // trace.
21*6777b538SAndroid Build Coastguard Worker constexpr base::TimeDelta kTimeLimit = base::Seconds(3);
22*6777b538SAndroid Build Coastguard Worker constexpr int kWarmupRuns = 100;
23*6777b538SAndroid Build Coastguard Worker constexpr int kTimeCheckInterval = 1000;
24*6777b538SAndroid Build Coastguard Worker constexpr char kMetricStackTraceDuration[] = ".duration_per_run";
25*6777b538SAndroid Build Coastguard Worker constexpr char kMetricStackTraceThroughput[] = ".throughput";
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker enum class HandlerFunctionSelector { OnAllocation, OnFree };
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker // An executor to perform the actual notification of the recorder. The correct
30*6777b538SAndroid Build Coastguard Worker // handler function is selected using template specialization based on the
31*6777b538SAndroid Build Coastguard Worker // HandlerFunctionSelector.
32*6777b538SAndroid Build Coastguard Worker template <HandlerFunctionSelector HandlerFunction>
33*6777b538SAndroid Build Coastguard Worker struct HandlerFunctionExecutor {
34*6777b538SAndroid Build Coastguard Worker   void operator()(base::debug::tracer::AllocationTraceRecorder& recorder) const;
35*6777b538SAndroid Build Coastguard Worker };
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker template <>
38*6777b538SAndroid Build Coastguard Worker struct HandlerFunctionExecutor<HandlerFunctionSelector::OnAllocation> {
operator ()base::debug::__anon6276e8950111::HandlerFunctionExecutor39*6777b538SAndroid Build Coastguard Worker   void operator()(
40*6777b538SAndroid Build Coastguard Worker       base::debug::tracer::AllocationTraceRecorder& recorder) const {
41*6777b538SAndroid Build Coastguard Worker     // Since the recorder just stores the value, we can use any value for
42*6777b538SAndroid Build Coastguard Worker     // address and size that we want.
43*6777b538SAndroid Build Coastguard Worker     recorder.OnAllocation(
44*6777b538SAndroid Build Coastguard Worker         base::allocator::dispatcher::AllocationNotificationData(
45*6777b538SAndroid Build Coastguard Worker             &recorder, sizeof(recorder), nullptr,
46*6777b538SAndroid Build Coastguard Worker             base::allocator::dispatcher::AllocationSubsystem::
47*6777b538SAndroid Build Coastguard Worker                 kPartitionAllocator));
48*6777b538SAndroid Build Coastguard Worker   }
49*6777b538SAndroid Build Coastguard Worker };
50*6777b538SAndroid Build Coastguard Worker 
51*6777b538SAndroid Build Coastguard Worker template <>
52*6777b538SAndroid Build Coastguard Worker struct HandlerFunctionExecutor<HandlerFunctionSelector::OnFree> {
operator ()base::debug::__anon6276e8950111::HandlerFunctionExecutor53*6777b538SAndroid Build Coastguard Worker   void operator()(
54*6777b538SAndroid Build Coastguard Worker       base::debug::tracer::AllocationTraceRecorder& recorder) const {
55*6777b538SAndroid Build Coastguard Worker     recorder.OnFree(base::allocator::dispatcher::FreeNotificationData(
56*6777b538SAndroid Build Coastguard Worker         &recorder,
57*6777b538SAndroid Build Coastguard Worker         base::allocator::dispatcher::AllocationSubsystem::kPartitionAllocator));
58*6777b538SAndroid Build Coastguard Worker   }
59*6777b538SAndroid Build Coastguard Worker };
60*6777b538SAndroid Build Coastguard Worker }  // namespace
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker class AllocationTraceRecorderPerfTest
63*6777b538SAndroid Build Coastguard Worker     : public testing::TestWithParam<
64*6777b538SAndroid Build Coastguard Worker           std::tuple<HandlerFunctionSelector, size_t>> {
65*6777b538SAndroid Build Coastguard Worker  protected:
66*6777b538SAndroid Build Coastguard Worker   // The result data of a single thread. From the results of all the single
67*6777b538SAndroid Build Coastguard Worker   // threads the final results will be calculated.
68*6777b538SAndroid Build Coastguard Worker   struct ResultData {
69*6777b538SAndroid Build Coastguard Worker     TimeDelta time_per_lap;
70*6777b538SAndroid Build Coastguard Worker     float laps_per_second = 0.0;
71*6777b538SAndroid Build Coastguard Worker     int number_of_laps = 0;
72*6777b538SAndroid Build Coastguard Worker   };
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker   // The data of a single test thread.
75*6777b538SAndroid Build Coastguard Worker   struct ThreadRunnerData {
76*6777b538SAndroid Build Coastguard Worker     std::thread thread;
77*6777b538SAndroid Build Coastguard Worker     ResultData result_data;
78*6777b538SAndroid Build Coastguard Worker   };
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker   // Create and setup the result reporter.
81*6777b538SAndroid Build Coastguard Worker   const char* GetHandlerDescriptor(HandlerFunctionSelector handler_function);
82*6777b538SAndroid Build Coastguard Worker   perf_test::PerfResultReporter SetUpReporter(
83*6777b538SAndroid Build Coastguard Worker       HandlerFunctionSelector handler_function,
84*6777b538SAndroid Build Coastguard Worker       size_t number_of_allocating_threads);
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker   // Select the correct test function which shall be used for the current test.
87*6777b538SAndroid Build Coastguard Worker   using TestFunction =
88*6777b538SAndroid Build Coastguard Worker       void (*)(base::debug::tracer::AllocationTraceRecorder& recorder,
89*6777b538SAndroid Build Coastguard Worker                ResultData& result_data);
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker   static TestFunction GetTestFunction(HandlerFunctionSelector handler_function);
92*6777b538SAndroid Build Coastguard Worker   template <HandlerFunctionSelector HandlerFunction>
93*6777b538SAndroid Build Coastguard Worker   static void TestFunctionImplementation(
94*6777b538SAndroid Build Coastguard Worker       base::debug::tracer::AllocationTraceRecorder& recorder,
95*6777b538SAndroid Build Coastguard Worker       ResultData& result_data);
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker   // The test management function. Using the the above auxiliary functions it is
98*6777b538SAndroid Build Coastguard Worker   // responsible to setup the result reporter, select the correct test function,
99*6777b538SAndroid Build Coastguard Worker   // spawn the specified number of worker threads and post process the results.
100*6777b538SAndroid Build Coastguard Worker   void PerformTest(HandlerFunctionSelector handler_function,
101*6777b538SAndroid Build Coastguard Worker                    size_t number_of_allocating_threads);
102*6777b538SAndroid Build Coastguard Worker };
103*6777b538SAndroid Build Coastguard Worker 
GetHandlerDescriptor(HandlerFunctionSelector handler_function)104*6777b538SAndroid Build Coastguard Worker const char* AllocationTraceRecorderPerfTest::GetHandlerDescriptor(
105*6777b538SAndroid Build Coastguard Worker     HandlerFunctionSelector handler_function) {
106*6777b538SAndroid Build Coastguard Worker   switch (handler_function) {
107*6777b538SAndroid Build Coastguard Worker     case HandlerFunctionSelector::OnAllocation:
108*6777b538SAndroid Build Coastguard Worker       return "OnAllocation";
109*6777b538SAndroid Build Coastguard Worker     case HandlerFunctionSelector::OnFree:
110*6777b538SAndroid Build Coastguard Worker       return "OnFree";
111*6777b538SAndroid Build Coastguard Worker   }
112*6777b538SAndroid Build Coastguard Worker }
113*6777b538SAndroid Build Coastguard Worker 
SetUpReporter(HandlerFunctionSelector handler_function,size_t number_of_allocating_threads)114*6777b538SAndroid Build Coastguard Worker perf_test::PerfResultReporter AllocationTraceRecorderPerfTest::SetUpReporter(
115*6777b538SAndroid Build Coastguard Worker     HandlerFunctionSelector handler_function,
116*6777b538SAndroid Build Coastguard Worker     size_t number_of_allocating_threads) {
117*6777b538SAndroid Build Coastguard Worker   const std::string story_name = base::StringPrintf(
118*6777b538SAndroid Build Coastguard Worker       "(%s;%zu-threads)", GetHandlerDescriptor(handler_function),
119*6777b538SAndroid Build Coastguard Worker       number_of_allocating_threads);
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   perf_test::PerfResultReporter reporter("AllocationRecorderPerf", story_name);
122*6777b538SAndroid Build Coastguard Worker   reporter.RegisterImportantMetric(kMetricStackTraceDuration, "ns");
123*6777b538SAndroid Build Coastguard Worker   reporter.RegisterImportantMetric(kMetricStackTraceThroughput, "runs/s");
124*6777b538SAndroid Build Coastguard Worker   return reporter;
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorderPerfTest::TestFunction
GetTestFunction(HandlerFunctionSelector handler_function)128*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorderPerfTest::GetTestFunction(
129*6777b538SAndroid Build Coastguard Worker     HandlerFunctionSelector handler_function) {
130*6777b538SAndroid Build Coastguard Worker   switch (handler_function) {
131*6777b538SAndroid Build Coastguard Worker     case HandlerFunctionSelector::OnAllocation:
132*6777b538SAndroid Build Coastguard Worker       return TestFunctionImplementation<HandlerFunctionSelector::OnAllocation>;
133*6777b538SAndroid Build Coastguard Worker     case HandlerFunctionSelector::OnFree:
134*6777b538SAndroid Build Coastguard Worker       return TestFunctionImplementation<HandlerFunctionSelector::OnFree>;
135*6777b538SAndroid Build Coastguard Worker   }
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker 
PerformTest(HandlerFunctionSelector handler_function,size_t number_of_allocating_threads)138*6777b538SAndroid Build Coastguard Worker void AllocationTraceRecorderPerfTest::PerformTest(
139*6777b538SAndroid Build Coastguard Worker     HandlerFunctionSelector handler_function,
140*6777b538SAndroid Build Coastguard Worker     size_t number_of_allocating_threads) {
141*6777b538SAndroid Build Coastguard Worker   perf_test::PerfResultReporter reporter =
142*6777b538SAndroid Build Coastguard Worker       SetUpReporter(handler_function, number_of_allocating_threads);
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker   TestFunction test_function = GetTestFunction(handler_function);
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker   base::debug::tracer::AllocationTraceRecorder the_recorder;
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker   std::vector<ThreadRunnerData> notifying_threads;
149*6777b538SAndroid Build Coastguard Worker   notifying_threads.reserve(number_of_allocating_threads);
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker   // Setup the threads. After creation, each thread immediately starts running.
152*6777b538SAndroid Build Coastguard Worker   // We expect the creation of the threads to be so quick that the delay from
153*6777b538SAndroid Build Coastguard Worker   // first to last thread is negligible.
154*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < number_of_allocating_threads; ++i) {
155*6777b538SAndroid Build Coastguard Worker     auto& last_item = notifying_threads.emplace_back();
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker     last_item.thread = std::thread{test_function, std::ref(the_recorder),
158*6777b538SAndroid Build Coastguard Worker                                    std::ref(last_item.result_data)};
159*6777b538SAndroid Build Coastguard Worker   }
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker   TimeDelta average_time_per_lap;
162*6777b538SAndroid Build Coastguard Worker   float average_laps_per_second = 0;
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   // Wait for each thread to finish and collect its result data.
165*6777b538SAndroid Build Coastguard Worker   for (auto& item : notifying_threads) {
166*6777b538SAndroid Build Coastguard Worker     item.thread.join();
167*6777b538SAndroid Build Coastguard Worker     // When finishing, each threads writes its results into result_data. So,
168*6777b538SAndroid Build Coastguard Worker     // from here we gather its performance statistics.
169*6777b538SAndroid Build Coastguard Worker     average_time_per_lap += item.result_data.time_per_lap;
170*6777b538SAndroid Build Coastguard Worker     average_laps_per_second += item.result_data.laps_per_second;
171*6777b538SAndroid Build Coastguard Worker   }
172*6777b538SAndroid Build Coastguard Worker 
173*6777b538SAndroid Build Coastguard Worker   average_time_per_lap /= number_of_allocating_threads;
174*6777b538SAndroid Build Coastguard Worker   average_laps_per_second /= number_of_allocating_threads;
175*6777b538SAndroid Build Coastguard Worker 
176*6777b538SAndroid Build Coastguard Worker   reporter.AddResult(kMetricStackTraceDuration, average_time_per_lap);
177*6777b538SAndroid Build Coastguard Worker   reporter.AddResult(kMetricStackTraceThroughput, average_laps_per_second);
178*6777b538SAndroid Build Coastguard Worker }
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker template <HandlerFunctionSelector HandlerFunction>
TestFunctionImplementation(base::debug::tracer::AllocationTraceRecorder & recorder,ResultData & result_data)181*6777b538SAndroid Build Coastguard Worker void AllocationTraceRecorderPerfTest::TestFunctionImplementation(
182*6777b538SAndroid Build Coastguard Worker     base::debug::tracer::AllocationTraceRecorder& recorder,
183*6777b538SAndroid Build Coastguard Worker     ResultData& result_data) {
184*6777b538SAndroid Build Coastguard Worker   LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval,
185*6777b538SAndroid Build Coastguard Worker                  LapTimer::TimerMethod::kUseTimeTicks);
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker   HandlerFunctionExecutor<HandlerFunction> handler_executor;
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker   timer.Start();
190*6777b538SAndroid Build Coastguard Worker   do {
191*6777b538SAndroid Build Coastguard Worker     handler_executor(recorder);
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker     timer.NextLap();
194*6777b538SAndroid Build Coastguard Worker   } while (!timer.HasTimeLimitExpired());
195*6777b538SAndroid Build Coastguard Worker 
196*6777b538SAndroid Build Coastguard Worker   result_data.time_per_lap = timer.TimePerLap();
197*6777b538SAndroid Build Coastguard Worker   result_data.laps_per_second = timer.LapsPerSecond();
198*6777b538SAndroid Build Coastguard Worker   result_data.number_of_laps = timer.NumLaps();
199*6777b538SAndroid Build Coastguard Worker }
200*6777b538SAndroid Build Coastguard Worker 
201*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(
202*6777b538SAndroid Build Coastguard Worker     ,
203*6777b538SAndroid Build Coastguard Worker     AllocationTraceRecorderPerfTest,
204*6777b538SAndroid Build Coastguard Worker     ::testing::Combine(::testing::Values(HandlerFunctionSelector::OnAllocation,
205*6777b538SAndroid Build Coastguard Worker                                          HandlerFunctionSelector::OnFree),
206*6777b538SAndroid Build Coastguard Worker                        ::testing::Values(1, 5, 10, 20, 40, 80)));
207*6777b538SAndroid Build Coastguard Worker 
TEST_P(AllocationTraceRecorderPerfTest,TestNotification)208*6777b538SAndroid Build Coastguard Worker TEST_P(AllocationTraceRecorderPerfTest, TestNotification) {
209*6777b538SAndroid Build Coastguard Worker   const auto parameters = GetParam();
210*6777b538SAndroid Build Coastguard Worker   const HandlerFunctionSelector handler_function = std::get<0>(parameters);
211*6777b538SAndroid Build Coastguard Worker   const size_t number_of_threads = std::get<1>(parameters);
212*6777b538SAndroid Build Coastguard Worker   PerformTest(handler_function, number_of_threads);
213*6777b538SAndroid Build Coastguard Worker }
214*6777b538SAndroid Build Coastguard Worker 
215*6777b538SAndroid Build Coastguard Worker }  // namespace debug
216*6777b538SAndroid Build Coastguard Worker }  // namespace base
217