1 /* 2 * Copyright 2023 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "bench/Benchmark.h" 9 #include "include/core/SkCanvas.h" 10 #include "include/core/SkSurface.h" 11 #include "tools/testrunners/common/surface_manager/SurfaceManager.h" 12 13 #include <memory> 14 #include <tuple> 15 16 // Represents a target against which to time a benchmark. Provides an SkCanvas and all necessary 17 // timing methods. 18 // 19 // Based on nanobench's Target struct: 20 // https://skia.googlesource.com/skia/+/a063eaeaf1e09e4d6f42e0f44a5723622a46d21c/bench/nanobench.h#36. 21 class BenchmarkTarget { 22 public: 23 static std::unique_ptr<BenchmarkTarget> FromConfig(std::string surfaceConfig, 24 Benchmark* benchmark); 25 26 // Prints to standard output overall statistics collected from all benchmark targets 27 // instantiated during the lifetime of the test runner. 28 static void printGlobalStats(); 29 30 virtual ~BenchmarkTarget() = default; 31 32 // Returns the backend used by this benchmark target. 33 virtual Benchmark::Backend getBackend() const = 0; 34 35 // Should be called once, immediately before any timing or drawing. 36 virtual void setup() const; 37 38 // Estimates the number of required benchmark runs to get a meaningful measurement. Returns 39 // the estimated number of runs, and a boolean indicating success or failure. 40 virtual std::tuple<int, bool> autoTuneLoops() const = 0; 41 42 // Should be called once, immediately before any timing or drawing. Implementations may time 43 // the benchmark for the passed in number of loops multiple times until a steady state is 44 // reached. warmUp(int loops)45 virtual void warmUp(int loops) const {} 46 47 // Times the benchmark by drawing for the given number of interations. Returns the number of 48 // milliseconds elapsed. It can be called multiple times between the setup() and tearDown() 49 // calls. 50 double time(int loops) const; 51 52 // Should be called once after the test runner is done with the benchmark. 53 void tearDown() const; 54 55 // Produces statistics that test runner should include in the output JSON file. dumpStats(skia_private::TArray<SkString> * keys,skia_private::TArray<double> * values)56 virtual void dumpStats(skia_private::TArray<SkString>* keys, 57 skia_private::TArray<double>* values) const {} 58 59 // Prints various statistics to standard output. printStats()60 virtual void printStats() const {} 61 62 SkCanvas* getCanvas() const; 63 64 Benchmark* getBenchmark() const; 65 66 // Returns the subset of Perf key/value pairs that are determined by the surface config. The 67 // returned map includes keys "cpu_or_gpu" and "cpu_or_gpu_value", which are populated based 68 // on the cpuName and gpuName arguments, and whether the surface config is CPU or GPU bound. 69 virtual std::map<std::string, std::string> getKeyValuePairs(std::string cpuName, 70 std::string gpuName) const; 71 72 // Returns an enum indicating whether the surface is CPU or GPU bound. 73 virtual SurfaceManager::CpuOrGpu isCpuOrGpuBound() const; 74 75 protected: BenchmarkTarget(std::unique_ptr<SurfaceManager> surfaceManager,Benchmark * benchmark)76 BenchmarkTarget(std::unique_ptr<SurfaceManager> surfaceManager, Benchmark* benchmark) 77 : fSurfaceManager(std::move(surfaceManager)), fBenchmark(benchmark) {} 78 79 // Called *after* the clock timer is started, before the benchmark is drawn. Most backends just 80 // return the canvas passed in, but some may replace it. onBeforeDraw(SkCanvas * canvas)81 virtual SkCanvas* onBeforeDraw(SkCanvas* canvas) const { return canvas; } 82 83 // Called *after* a benchmark is drawn, but before the clock timer is stopped. onAfterDraw()84 virtual void onAfterDraw() const {} 85 86 double nowMs() const; 87 88 std::unique_ptr<SurfaceManager> fSurfaceManager; 89 Benchmark* fBenchmark; 90 }; 91