xref: /aosp_15_r20/external/skia/tools/testrunners/benchmark/target/RasterBenchmarkTarget.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2023 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "bench/Benchmark.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "tools/flags/CommandLineFlags.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "tools/testrunners/benchmark/target/BenchmarkTarget.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "tools/testrunners/common/TestRunner.h"
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker static DEFINE_int(maxCalibrationAttempts,
14*c8dee2aaSAndroid Build Coastguard Worker                   3,
15*c8dee2aaSAndroid Build Coastguard Worker                   "Try up to this many times to guess loops for a benchmark, or skip the "
16*c8dee2aaSAndroid Build Coastguard Worker                   "benchmark.");
17*c8dee2aaSAndroid Build Coastguard Worker static DEFINE_double(overheadGoal,
18*c8dee2aaSAndroid Build Coastguard Worker                      0.0001,
19*c8dee2aaSAndroid Build Coastguard Worker                      "Loop until timer overhead is at most this fraction of our measurements.");
20*c8dee2aaSAndroid Build Coastguard Worker static DEFINE_int(overheadLoops, 100000, "Loops to estimate timer overhead.");
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker // Defined in BazelBenchmarkTestRunner.cpp.
23*c8dee2aaSAndroid Build Coastguard Worker SkString humanize(double ms);
24*c8dee2aaSAndroid Build Coastguard Worker 
printGlobalStats()25*c8dee2aaSAndroid Build Coastguard Worker void BenchmarkTarget::printGlobalStats() {}
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker class RasterBenchmarkTarget : public BenchmarkTarget {
28*c8dee2aaSAndroid Build Coastguard Worker public:
RasterBenchmarkTarget(std::unique_ptr<SurfaceManager> surfaceManager,Benchmark * benchmark)29*c8dee2aaSAndroid Build Coastguard Worker     RasterBenchmarkTarget(std::unique_ptr<SurfaceManager> surfaceManager, Benchmark* benchmark)
30*c8dee2aaSAndroid Build Coastguard Worker             : BenchmarkTarget(std::move(surfaceManager), benchmark) {}
31*c8dee2aaSAndroid Build Coastguard Worker 
getBackend() const32*c8dee2aaSAndroid Build Coastguard Worker     Benchmark::Backend getBackend() const override { return Benchmark::Backend::kRaster; }
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker     // Based on nanobench's setup_cpu_bench():
35*c8dee2aaSAndroid Build Coastguard Worker     // https://skia.googlesource.com/skia/+/a063eaeaf1e09e4d6f42e0f44a5723622a46d21c/bench/nanobench.cpp#466.
autoTuneLoops() const36*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<int, bool> autoTuneLoops() const override {
37*c8dee2aaSAndroid Build Coastguard Worker         // Estimate timer overhead. Based on:
38*c8dee2aaSAndroid Build Coastguard Worker         // https://skia.googlesource.com/skia/+/a063eaeaf1e09e4d6f42e0f44a5723622a46d21c/bench/nanobench.cpp#402.
39*c8dee2aaSAndroid Build Coastguard Worker         double overhead = 0;
40*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < FLAGS_overheadLoops; i++) {
41*c8dee2aaSAndroid Build Coastguard Worker             double start = nowMs();
42*c8dee2aaSAndroid Build Coastguard Worker             overhead += nowMs() - start;
43*c8dee2aaSAndroid Build Coastguard Worker         }
44*c8dee2aaSAndroid Build Coastguard Worker         overhead /= FLAGS_overheadLoops;
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker         // First figure out approximately how many loops of bench it takes to make overhead
47*c8dee2aaSAndroid Build Coastguard Worker         // negligible.
48*c8dee2aaSAndroid Build Coastguard Worker         double bench_plus_overhead = 0.0;
49*c8dee2aaSAndroid Build Coastguard Worker         int round = 0;
50*c8dee2aaSAndroid Build Coastguard Worker         while (bench_plus_overhead < overhead) {
51*c8dee2aaSAndroid Build Coastguard Worker             if (round++ == FLAGS_maxCalibrationAttempts) {
52*c8dee2aaSAndroid Build Coastguard Worker                 TestRunner::Log("Warning: Cannot estimate loops for %s (%s vs. %s); skipping.",
53*c8dee2aaSAndroid Build Coastguard Worker                                 fBenchmark->getUniqueName(),
54*c8dee2aaSAndroid Build Coastguard Worker                                 humanize(bench_plus_overhead).c_str(),
55*c8dee2aaSAndroid Build Coastguard Worker                                 humanize(overhead).c_str());
56*c8dee2aaSAndroid Build Coastguard Worker                 return std::make_tuple(0, false);
57*c8dee2aaSAndroid Build Coastguard Worker             }
58*c8dee2aaSAndroid Build Coastguard Worker             bench_plus_overhead = time(1);
59*c8dee2aaSAndroid Build Coastguard Worker         }
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker         // Later we'll just start and stop the timer once but loop N times.
62*c8dee2aaSAndroid Build Coastguard Worker         // We'll pick N to make timer overhead negligible:
63*c8dee2aaSAndroid Build Coastguard Worker         //
64*c8dee2aaSAndroid Build Coastguard Worker         //          overhead
65*c8dee2aaSAndroid Build Coastguard Worker         //  -------------------------  < FLAGS_overheadGoal
66*c8dee2aaSAndroid Build Coastguard Worker         //  overhead + N * Bench Time
67*c8dee2aaSAndroid Build Coastguard Worker         //
68*c8dee2aaSAndroid Build Coastguard Worker         // where bench_plus_overhead ~=~ overhead + Bench Time.
69*c8dee2aaSAndroid Build Coastguard Worker         //
70*c8dee2aaSAndroid Build Coastguard Worker         // Doing some math, we get:
71*c8dee2aaSAndroid Build Coastguard Worker         //
72*c8dee2aaSAndroid Build Coastguard Worker         //  (overhead / FLAGS_overheadGoal) - overhead
73*c8dee2aaSAndroid Build Coastguard Worker         //  ------------------------------------------  < N
74*c8dee2aaSAndroid Build Coastguard Worker         //       bench_plus_overhead - overhead)
75*c8dee2aaSAndroid Build Coastguard Worker         //
76*c8dee2aaSAndroid Build Coastguard Worker         // Luckily, this also works well in practice. :)
77*c8dee2aaSAndroid Build Coastguard Worker         const double numer = overhead / FLAGS_overheadGoal - overhead;
78*c8dee2aaSAndroid Build Coastguard Worker         const double denom = bench_plus_overhead - overhead;
79*c8dee2aaSAndroid Build Coastguard Worker         int loops = (int)ceil(numer / denom);
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker         return std::make_tuple(loops, true);
82*c8dee2aaSAndroid Build Coastguard Worker     }
83*c8dee2aaSAndroid Build Coastguard Worker };
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker class NonRenderingBenchmarkTarget : public RasterBenchmarkTarget {
86*c8dee2aaSAndroid Build Coastguard Worker public:
NonRenderingBenchmarkTarget(Benchmark * benchmark)87*c8dee2aaSAndroid Build Coastguard Worker     NonRenderingBenchmarkTarget(Benchmark* benchmark) : RasterBenchmarkTarget(nullptr, benchmark) {}
88*c8dee2aaSAndroid Build Coastguard Worker 
getBackend() const89*c8dee2aaSAndroid Build Coastguard Worker     Benchmark::Backend getBackend() const override { return Benchmark::Backend::kNonRendering; }
90*c8dee2aaSAndroid Build Coastguard Worker 
isCpuOrGpuBound() const91*c8dee2aaSAndroid Build Coastguard Worker     SurfaceManager::CpuOrGpu isCpuOrGpuBound() const override {
92*c8dee2aaSAndroid Build Coastguard Worker         return SurfaceManager::CpuOrGpu::kCPU;
93*c8dee2aaSAndroid Build Coastguard Worker     }
94*c8dee2aaSAndroid Build Coastguard Worker 
getKeyValuePairs(std::string cpuName,std::string gpuName) const95*c8dee2aaSAndroid Build Coastguard Worker     std::map<std::string, std::string> getKeyValuePairs(std::string cpuName,
96*c8dee2aaSAndroid Build Coastguard Worker                                                         std::string gpuName) const override {
97*c8dee2aaSAndroid Build Coastguard Worker         if (cpuName == "") {
98*c8dee2aaSAndroid Build Coastguard Worker             return std::map<std::string, std::string>();
99*c8dee2aaSAndroid Build Coastguard Worker         }
100*c8dee2aaSAndroid Build Coastguard Worker         return {
101*c8dee2aaSAndroid Build Coastguard Worker                 {"cpu_or_gpu", "CPU"},
102*c8dee2aaSAndroid Build Coastguard Worker                 {"cpu_or_gpu_value", cpuName},
103*c8dee2aaSAndroid Build Coastguard Worker         };
104*c8dee2aaSAndroid Build Coastguard Worker     }
105*c8dee2aaSAndroid Build Coastguard Worker };
106*c8dee2aaSAndroid Build Coastguard Worker 
FromConfig(std::string surfaceConfig,Benchmark * benchmark)107*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<BenchmarkTarget> BenchmarkTarget::FromConfig(std::string surfaceConfig,
108*c8dee2aaSAndroid Build Coastguard Worker                                                              Benchmark* benchmark) {
109*c8dee2aaSAndroid Build Coastguard Worker     if (surfaceConfig == "nonrendering") {
110*c8dee2aaSAndroid Build Coastguard Worker         return std::make_unique<NonRenderingBenchmarkTarget>(benchmark);
111*c8dee2aaSAndroid Build Coastguard Worker     }
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SurfaceManager> surfaceManager = SurfaceManager::FromConfig(
114*c8dee2aaSAndroid Build Coastguard Worker             surfaceConfig, {benchmark->getSize().width(), benchmark->getSize().height()});
115*c8dee2aaSAndroid Build Coastguard Worker     if (surfaceManager == nullptr) {
116*c8dee2aaSAndroid Build Coastguard Worker         SK_ABORT("Unknown --surfaceConfig flag value: %s.", surfaceConfig.c_str());
117*c8dee2aaSAndroid Build Coastguard Worker     }
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<RasterBenchmarkTarget>(std::move(surfaceManager), benchmark);
120*c8dee2aaSAndroid Build Coastguard Worker }
121