blob: b4d0035c756bd58569836fb6c433ec9b0b4ad0d1 [file] [log] [blame]
mtkleinf3723212014-06-25 14:08:00 -07001/*
2 * Copyright 2014 Google Inc.
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
mtkleinbb6a0282014-07-01 08:43:42 -07008#include <ctype.h>
9
tomhudsond968a6f2015-03-26 11:28:06 -070010#include "nanobench.h"
11
msarett84451022016-02-11 06:45:51 -080012#include "AndroidCodecBench.h"
mtkleinf3723212014-06-25 14:08:00 -070013#include "Benchmark.h"
msarett7f691442015-09-22 11:56:16 -070014#include "BitmapRegionDecoderBench.h"
scroggo60869a42015-04-01 12:09:17 -070015#include "CodecBench.h"
msarett7f691442015-09-22 11:56:16 -070016#include "CodecBenchPriv.h"
mtkleinf3723212014-06-25 14:08:00 -070017#include "CrashHandler.h"
mtkleine714e752014-07-31 12:13:48 -070018#include "GMBench.h"
mtkleinafb43792014-08-19 15:55:55 -070019#include "ProcStats.h"
mtkleinfd731ce2014-09-10 12:19:30 -070020#include "RecordingBench.h"
Brian Salomondcbb9d92017-07-19 10:53:20 -040021#include "ResultsWriter.h"
joshualitt261c3ad2015-04-27 09:16:57 -070022#include "SKPAnimationBench.h"
mtklein92007582014-08-01 07:46:52 -070023#include "SKPBench.h"
msarett84451022016-02-11 06:45:51 -080024#include "SkAndroidCodec.h"
Hal Canary95e3c052017-01-11 12:44:43 -050025#include "SkAutoMalloc.h"
Kevin Lubickc456b732017-01-11 17:21:57 +000026#include "SkBBoxHierarchy.h"
Hal Canary95e3c052017-01-11 12:44:43 -050027#include "SkBitmapRegionDecoder.h"
mtkleinf3723212014-06-25 14:08:00 -070028#include "SkCanvas.h"
scroggo60869a42015-04-01 12:09:17 -070029#include "SkCodec.h"
Mike Klein0e4041f2018-06-19 16:00:40 -040030#include "SkColorSpacePriv.h"
caryclark17f0b6d2014-07-22 10:15:34 -070031#include "SkCommonFlags.h"
kkinnunen3e980c32015-12-23 01:33:00 -080032#include "SkCommonFlagsConfig.h"
Chris Dalton040238b2017-12-18 14:22:34 -070033#include "SkCommonFlagsGpu.h"
msarett95f192d2015-02-13 09:05:41 -080034#include "SkData.h"
Brian Salomondcbb9d92017-07-19 10:53:20 -040035#include "SkDebugfTracer.h"
Brian Osman53136aa2017-07-20 15:43:35 -040036#include "SkEventTracingPriv.h"
mtkleinf3723212014-06-25 14:08:00 -070037#include "SkGraphics.h"
Brian Osman8c0a1ca2019-01-28 14:24:29 -050038#include "SkJSONWriter.h"
halcanary4dbbd042016-06-07 17:21:10 -070039#include "SkLeanWindows.h"
mtklein20840502014-08-21 15:51:22 -070040#include "SkOSFile.h"
Ben Wagnerbf111d72016-11-07 18:05:29 -050041#include "SkOSPath.h"
mtklein20840502014-08-21 15:51:22 -070042#include "SkPictureRecorder.h"
Hal Canary95e3c052017-01-11 12:44:43 -050043#include "SkScan.h"
mtkleinf3723212014-06-25 14:08:00 -070044#include "SkString.h"
45#include "SkSurface.h"
robertphillips5b693772014-11-21 06:19:36 -080046#include "SkTaskGroup.h"
Brian Osmanc3cdef52017-08-31 14:09:22 -040047#include "SkTraceEvent.h"
Brian Salomondcbb9d92017-07-19 10:53:20 -040048#include "Stats.h"
Brian Salomondcbb9d92017-07-19 10:53:20 -040049#include "ios_utils.h"
mtkleinf3723212014-06-25 14:08:00 -070050
Hal Canary0f666812018-03-22 15:21:12 -040051#ifdef SK_XML
52#include "SkSVGDOM.h"
53#endif // SK_XML
54
bungeman60e0fee2015-08-26 05:15:46 -070055#include <stdlib.h>
Mike Klein03141d22017-10-30 11:57:15 -040056#include <thread>
bungeman60e0fee2015-08-26 05:15:46 -070057
Mike Reedc928fe22017-06-05 10:20:31 -040058extern bool gSkForceRasterPipelineBlitter;
59
Mike Klein8f11d4d2018-01-24 12:42:55 -050060#ifndef SK_BUILD_FOR_WIN
scroggo38ce0a72016-01-07 07:28:47 -080061 #include <unistd.h>
Brian Salomon032aaae2018-03-23 16:10:36 -040062
scroggo38ce0a72016-01-07 07:28:47 -080063#endif
64
Brian Osmanc7ad40f2018-05-31 14:27:17 -040065#include "GrCaps.h"
66#include "GrContextFactory.h"
67#include "GrContextPriv.h"
68#include "SkGr.h"
69#include "gl/GrGLDefines.h"
70#include "gl/GrGLGpu.h"
71#include "gl/GrGLUtil.h"
Brian Salomon032aaae2018-03-23 16:10:36 -040072
Brian Osmanc7ad40f2018-05-31 14:27:17 -040073using sk_gpu_test::ContextInfo;
74using sk_gpu_test::GrContextFactory;
75using sk_gpu_test::TestContext;
Brian Salomon032aaae2018-03-23 16:10:36 -040076
Brian Osmanc7ad40f2018-05-31 14:27:17 -040077GrContextOptions grContextOpts;
bsalomon682c2692015-05-22 14:01:46 -070078
reed53249782014-10-10 09:09:52 -070079static const int kAutoTuneLoops = 0;
bsalomon6eb03cc2014-08-07 14:28:50 -070080
Mike Kleind8ee67c2017-01-19 12:14:50 -050081#if !defined(__has_feature)
82 #define __has_feature(x) 0
83#endif
84
mtkleinb5110422014-08-07 15:20:02 -070085static const int kDefaultLoops =
Mike Klein7a002c32018-03-30 16:22:13 +000086#if defined(SK_DEBUG) || __has_feature(address_sanitizer)
bsalomon6eb03cc2014-08-07 14:28:50 -070087 1;
mtkleina189ccd2014-07-14 12:28:47 -070088#else
bsalomon6eb03cc2014-08-07 14:28:50 -070089 kAutoTuneLoops;
mtkleina189ccd2014-07-14 12:28:47 -070090#endif
91
bsalomon6eb03cc2014-08-07 14:28:50 -070092static SkString loops_help_txt() {
93 SkString help;
94 help.printf("Number of times to run each bench. Set this to %d to auto-"
95 "tune for each bench. Timings are only reported when auto-tuning.",
96 kAutoTuneLoops);
97 return help;
98}
99
cdaltone1b89582015-06-25 19:17:08 -0700100static SkString to_string(int n) {
101 SkString str;
102 str.appendS32(n);
103 return str;
104}
105
bsalomon6eb03cc2014-08-07 14:28:50 -0700106DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str());
107
mtkleinf3723212014-06-25 14:08:00 -0700108DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
mtkleinbbba1682015-10-28 11:36:30 -0700109DEFINE_int32(ms, 0, "If >0, run each bench for this many ms instead of obeying --samples.");
mtkleinf3723212014-06-25 14:08:00 -0700110DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
111DEFINE_double(overheadGoal, 0.0001,
112 "Loop until timer overhead is at most this fraction of our measurments.");
mtkleinbb6a0282014-07-01 08:43:42 -0700113DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
cdaltond416a5b2015-06-23 13:23:44 -0700114DEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag.");
mtkleinf3723212014-06-25 14:08:00 -0700115
mtklein60317d0f2014-07-14 11:30:37 -0700116DEFINE_string(outResultsFile, "", "If given, write results here as JSON.");
mtklein55b0ffc2014-07-17 08:38:23 -0700117DEFINE_int32(maxCalibrationAttempts, 3,
118 "Try up to this many times to guess loops for a bench, or skip the bench.");
119DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this.");
mtklein92007582014-08-01 07:46:52 -0700120DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs.");
121DEFINE_string(scales, "1.0", "Space-separated scales for SKPs.");
cdalton63a82852015-06-29 14:06:10 -0700122DEFINE_string(zoom, "1.0,0", "Comma-separated zoomMax,zoomPeriodMs factors for a periodic SKP zoom "
123 "function that ping-pongs between 1.0 and zoomMax.");
mtklein20840502014-08-21 15:51:22 -0700124DEFINE_bool(bbh, true, "Build a BBH for SKPs?");
mtklein8c1a4f82016-08-08 06:56:22 -0700125DEFINE_bool(lite, false, "Use SkLiteRecorder in recording benchmarks?");
robertphillips5b693772014-11-21 06:19:36 -0800126DEFINE_bool(mpd, true, "Use MultiPictureDraw for the SKPs?");
cdaltonb4022962015-06-25 10:51:56 -0700127DEFINE_bool(loopSKP, true, "Loop SKPs like we do for micro benches?");
mtkleine070c2b2014-10-14 08:40:43 -0700128DEFINE_int32(flushEvery, 10, "Flush --outResultsFile every Nth run.");
bsalomonb12ea412015-02-02 21:19:50 -0800129DEFINE_bool(gpuStats, false, "Print GPU stats after each gpu benchmark?");
joshualitte45c81c2015-12-02 09:05:37 -0800130DEFINE_bool(gpuStatsDump, false, "Dump GPU states after each benchmark to json");
msarettc149f0e2016-01-04 11:35:43 -0800131DEFINE_bool(keepAlive, false, "Print a message every so often so that we don't time out");
Mike Reedc665e5b2017-07-04 22:56:06 -0400132DEFINE_bool(csv, false, "Print status in CSV format");
mtklein65dfd2f2016-02-03 10:40:54 -0800133DEFINE_string(sourceType, "",
134 "Apply usual --match rules to source type: bench, gm, skp, image, etc.");
135DEFINE_string(benchType, "",
Mike Reed9cdd2ab2016-10-21 10:43:36 -0400136 "Apply usual --match rules to bench type: micro, recording, piping, playback, skcodec, etc.");
mtklein65dfd2f2016-02-03 10:40:54 -0800137
Mike Reedc928fe22017-06-05 10:20:31 -0400138DEFINE_bool(forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter");
139
mtkleinbbba1682015-10-28 11:36:30 -0700140static double now_ms() { return SkTime::GetNSecs() * 1e-6; }
141
mtkleinf3723212014-06-25 14:08:00 -0700142static SkString humanize(double ms) {
mtkleindc5bbab2014-09-24 06:34:09 -0700143 if (FLAGS_verbose) return SkStringPrintf("%llu", (uint64_t)(ms*1e6));
mtklein748ca3b2015-01-15 10:56:12 -0800144 return HumanizeMs(ms);
mtkleinf3723212014-06-25 14:08:00 -0700145}
mtklein55b0ffc2014-07-17 08:38:23 -0700146#define HUMANIZE(ms) humanize(ms).c_str()
mtkleinf3723212014-06-25 14:08:00 -0700147
tomhudsond968a6f2015-03-26 11:28:06 -0700148bool Target::init(SkImageInfo info, Benchmark* bench) {
149 if (Benchmark::kRaster_Backend == config.backend) {
reede8f30622016-03-23 18:59:25 -0700150 this->surface = SkSurface::MakeRaster(info);
151 if (!this->surface) {
tomhudsond968a6f2015-03-26 11:28:06 -0700152 return false;
153 }
154 }
155 return true;
156}
157bool Target::capturePixels(SkBitmap* bmp) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700158 SkCanvas* canvas = this->getCanvas();
tomhudsond968a6f2015-03-26 11:28:06 -0700159 if (!canvas) {
160 return false;
161 }
Mike Reed12e946b2017-04-17 10:53:29 -0400162 bmp->allocPixels(canvas->imageInfo());
163 if (!canvas->readPixels(*bmp, 0, 0)) {
tomhudsond968a6f2015-03-26 11:28:06 -0700164 SkDebugf("Can't read canvas pixels.\n");
165 return false;
166 }
167 return true;
168}
169
tomhudsond968a6f2015-03-26 11:28:06 -0700170struct GPUTarget : public Target {
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400171 explicit GPUTarget(const Config& c) : Target(c) {}
172 ContextInfo contextInfo;
173 std::unique_ptr<GrContextFactory> factory;
tomhudsond968a6f2015-03-26 11:28:06 -0700174
175 void setup() override {
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400176 this->contextInfo.testContext()->makeCurrent();
tomhudsond968a6f2015-03-26 11:28:06 -0700177 // Make sure we're done with whatever came before.
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400178 this->contextInfo.testContext()->finish();
tomhudsond968a6f2015-03-26 11:28:06 -0700179 }
180 void endTiming() override {
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400181 if (this->contextInfo.testContext()) {
182 this->contextInfo.testContext()->waitOnSyncOrSwap();
tomhudsond968a6f2015-03-26 11:28:06 -0700183 }
184 }
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400185 void fence() override { this->contextInfo.testContext()->finish(); }
mtkleind75c4662015-04-30 07:11:22 -0700186
cdaltond416a5b2015-06-23 13:23:44 -0700187 bool needsFrameTiming(int* maxFrameLag) const override {
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400188 if (!this->contextInfo.testContext()->getMaxGpuFrameLag(maxFrameLag)) {
cdaltond416a5b2015-06-23 13:23:44 -0700189 // Frame lag is unknown.
190 *maxFrameLag = FLAGS_gpuFrameLag;
191 }
192 return true;
193 }
tomhudsond968a6f2015-03-26 11:28:06 -0700194 bool init(SkImageInfo info, Benchmark* bench) override {
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400195 GrContextOptions options = grContextOpts;
196 bench->modifyGrContextOptions(&options);
197 this->factory.reset(new GrContextFactory(options));
bsalomonafcd7cd2015-08-31 12:39:41 -0700198 uint32_t flags = this->config.useDFText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag :
199 0;
tomhudsond968a6f2015-03-26 11:28:06 -0700200 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400201 this->surface = SkSurface::MakeRenderTarget(
202 this->factory->get(this->config.ctxType, this->config.ctxOverrides),
203 SkBudgeted::kNo, info, this->config.samples, &props);
204 this->contextInfo =
205 this->factory->getContextInfo(this->config.ctxType, this->config.ctxOverrides);
tomhudsond968a6f2015-03-26 11:28:06 -0700206 if (!this->surface.get()) {
207 return false;
208 }
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400209 if (!this->contextInfo.testContext()->fenceSyncSupport()) {
cdaltond416a5b2015-06-23 13:23:44 -0700210 SkDebugf("WARNING: GL context for config \"%s\" does not support fence sync. "
svaisanenc47635e2016-01-28 06:05:43 -0800211 "Timings might not be accurate.\n", this->config.name.c_str());
cdaltond416a5b2015-06-23 13:23:44 -0700212 }
tomhudsond968a6f2015-03-26 11:28:06 -0700213 return true;
214 }
Brian Osman8c0a1ca2019-01-28 14:24:29 -0500215 void fillOptions(NanoJSONResultsWriter& log) override {
tomhudsond968a6f2015-03-26 11:28:06 -0700216 const GrGLubyte* version;
Greg Danielbdf12ad2018-10-12 09:31:11 -0400217 if (this->contextInfo.backend() == GrBackendApi::kOpenGL) {
Brian Salomon032aaae2018-03-23 16:10:36 -0400218 const GrGLInterface* gl =
Robert Phillips9da87e02019-02-04 13:26:26 -0500219 static_cast<GrGLGpu*>(this->contextInfo.grContext()->priv().getGpu())
Brian Salomon032aaae2018-03-23 16:10:36 -0400220 ->glInterface();
bsalomonc8699322016-05-11 11:55:36 -0700221 GR_GL_CALL_RET(gl, version, GetString(GR_GL_VERSION));
Brian Osman8c0a1ca2019-01-28 14:24:29 -0500222 log.appendString("GL_VERSION", (const char*)(version));
tomhudsond968a6f2015-03-26 11:28:06 -0700223
bsalomonc8699322016-05-11 11:55:36 -0700224 GR_GL_CALL_RET(gl, version, GetString(GR_GL_RENDERER));
Brian Osman8c0a1ca2019-01-28 14:24:29 -0500225 log.appendString("GL_RENDERER", (const char*) version);
tomhudsond968a6f2015-03-26 11:28:06 -0700226
bsalomonc8699322016-05-11 11:55:36 -0700227 GR_GL_CALL_RET(gl, version, GetString(GR_GL_VENDOR));
Brian Osman8c0a1ca2019-01-28 14:24:29 -0500228 log.appendString("GL_VENDOR", (const char*) version);
tomhudsond968a6f2015-03-26 11:28:06 -0700229
bsalomonc8699322016-05-11 11:55:36 -0700230 GR_GL_CALL_RET(gl, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
Brian Osman8c0a1ca2019-01-28 14:24:29 -0500231 log.appendString("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
bsalomonc8699322016-05-11 11:55:36 -0700232 }
tomhudsond968a6f2015-03-26 11:28:06 -0700233 }
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400234
235 void dumpStats() override {
Robert Phillips9da87e02019-02-04 13:26:26 -0500236 this->contextInfo.grContext()->priv().printCacheStats();
237 this->contextInfo.grContext()->priv().printGpuStats();
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400238 }
tomhudsond968a6f2015-03-26 11:28:06 -0700239};
mtkleind75c4662015-04-30 07:11:22 -0700240
tomhudson75a0ebb2015-03-27 12:11:44 -0700241static double time(int loops, Benchmark* bench, Target* target) {
242 SkCanvas* canvas = target->getCanvas();
bsalomon6eb03cc2014-08-07 14:28:50 -0700243 if (canvas) {
244 canvas->clear(SK_ColorWHITE);
245 }
joshualitt8a6697a2015-09-30 12:11:07 -0700246 bench->preDraw(canvas);
mtkleinbbba1682015-10-28 11:36:30 -0700247 double start = now_ms();
tomhudson75a0ebb2015-03-27 12:11:44 -0700248 canvas = target->beginTiming(canvas);
249 bench->draw(loops, canvas);
mtkleinbb6a0282014-07-01 08:43:42 -0700250 if (canvas) {
251 canvas->flush();
252 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700253 target->endTiming();
mtkleinbbba1682015-10-28 11:36:30 -0700254 double elapsed = now_ms() - start;
joshualitt8a6697a2015-09-30 12:11:07 -0700255 bench->postDraw(canvas);
mtkleinbbba1682015-10-28 11:36:30 -0700256 return elapsed;
mtkleinbb6a0282014-07-01 08:43:42 -0700257}
258
mtkleinf3723212014-06-25 14:08:00 -0700259static double estimate_timer_overhead() {
260 double overhead = 0;
mtkleinf3723212014-06-25 14:08:00 -0700261 for (int i = 0; i < FLAGS_overheadLoops; i++) {
mtkleinbbba1682015-10-28 11:36:30 -0700262 double start = now_ms();
263 overhead += now_ms() - start;
mtkleinf3723212014-06-25 14:08:00 -0700264 }
265 return overhead / FLAGS_overheadLoops;
266}
267
reed53249782014-10-10 09:09:52 -0700268static int detect_forever_loops(int loops) {
269 // look for a magic run-forever value
270 if (loops < 0) {
271 loops = SK_MaxS32;
272 }
273 return loops;
274}
275
mtklein55b0ffc2014-07-17 08:38:23 -0700276static int clamp_loops(int loops) {
277 if (loops < 1) {
mtklein527930f2014-11-06 08:04:34 -0800278 SkDebugf("ERROR: clamping loops from %d to 1. "
279 "There's probably something wrong with the bench.\n", loops);
mtklein55b0ffc2014-07-17 08:38:23 -0700280 return 1;
281 }
282 if (loops > FLAGS_maxLoops) {
283 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops);
284 return FLAGS_maxLoops;
285 }
286 return loops;
287}
288
tomhudsond968a6f2015-03-26 11:28:06 -0700289static bool write_canvas_png(Target* target, const SkString& filename) {
290
bsalomon6eb03cc2014-08-07 14:28:50 -0700291 if (filename.isEmpty()) {
292 return false;
293 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700294 if (target->getCanvas() &&
295 kUnknown_SkColorType == target->getCanvas()->imageInfo().colorType()) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700296 return false;
297 }
tomhudsond968a6f2015-03-26 11:28:06 -0700298
bsalomon6eb03cc2014-08-07 14:28:50 -0700299 SkBitmap bmp;
tomhudsond968a6f2015-03-26 11:28:06 -0700300
301 if (!target->capturePixels(&bmp)) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700302 return false;
303 }
tomhudsond968a6f2015-03-26 11:28:06 -0700304
bsalomon6eb03cc2014-08-07 14:28:50 -0700305 SkString dir = SkOSPath::Dirname(filename.c_str());
306 if (!sk_mkdir(dir.c_str())) {
307 SkDebugf("Can't make dir %s.\n", dir.c_str());
308 return false;
309 }
310 SkFILEWStream stream(filename.c_str());
311 if (!stream.isValid()) {
312 SkDebugf("Can't write %s.\n", filename.c_str());
313 return false;
314 }
Hal Canarydb683012016-11-23 08:55:18 -0700315 if (!SkEncodeImage(&stream, bmp, SkEncodedImageFormat::kPNG, 100)) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700316 SkDebugf("Can't encode a PNG.\n");
317 return false;
318 }
319 return true;
320}
321
322static int kFailedLoops = -2;
cdaltone1b89582015-06-25 19:17:08 -0700323static int setup_cpu_bench(const double overhead, Target* target, Benchmark* bench) {
mtkleinbb6a0282014-07-01 08:43:42 -0700324 // First figure out approximately how many loops of bench it takes to make overhead negligible.
mtklein2069e222014-08-04 13:57:39 -0700325 double bench_plus_overhead = 0.0;
mtklein55b0ffc2014-07-17 08:38:23 -0700326 int round = 0;
cdaltonb4022962015-06-25 10:51:56 -0700327 int loops = bench->calculateLoops(FLAGS_loops);
328 if (kAutoTuneLoops == loops) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700329 while (bench_plus_overhead < overhead) {
330 if (round++ == FLAGS_maxCalibrationAttempts) {
331 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
mtklein96289052014-09-10 12:05:59 -0700332 bench->getUniqueName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
bsalomon6eb03cc2014-08-07 14:28:50 -0700333 return kFailedLoops;
334 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700335 bench_plus_overhead = time(1, bench, target);
mtklein55b0ffc2014-07-17 08:38:23 -0700336 }
mtklein2069e222014-08-04 13:57:39 -0700337 }
mtkleinf3723212014-06-25 14:08:00 -0700338
mtkleinbb6a0282014-07-01 08:43:42 -0700339 // Later we'll just start and stop the timer once but loop N times.
mtkleinf3723212014-06-25 14:08:00 -0700340 // We'll pick N to make timer overhead negligible:
341 //
mtkleinbb6a0282014-07-01 08:43:42 -0700342 // overhead
343 // ------------------------- < FLAGS_overheadGoal
344 // overhead + N * Bench Time
mtkleinf3723212014-06-25 14:08:00 -0700345 //
Hal Canary55325b72017-01-03 10:36:17 -0500346 // where bench_plus_overhead ~=~ overhead + Bench Time.
mtkleinf3723212014-06-25 14:08:00 -0700347 //
348 // Doing some math, we get:
349 //
mtkleinbb6a0282014-07-01 08:43:42 -0700350 // (overhead / FLAGS_overheadGoal) - overhead
351 // ------------------------------------------ < N
352 // bench_plus_overhead - overhead)
mtkleinf3723212014-06-25 14:08:00 -0700353 //
354 // Luckily, this also works well in practice. :)
bsalomon6eb03cc2014-08-07 14:28:50 -0700355 if (kAutoTuneLoops == loops) {
356 const double numer = overhead / FLAGS_overheadGoal - overhead;
357 const double denom = bench_plus_overhead - overhead;
358 loops = (int)ceil(numer / denom);
reed53249782014-10-10 09:09:52 -0700359 loops = clamp_loops(loops);
360 } else {
361 loops = detect_forever_loops(loops);
bsalomon6eb03cc2014-08-07 14:28:50 -0700362 }
mtkleinbb6a0282014-07-01 08:43:42 -0700363
mtkleinbb6a0282014-07-01 08:43:42 -0700364 return loops;
mtkleinf3723212014-06-25 14:08:00 -0700365}
366
cdaltone1b89582015-06-25 19:17:08 -0700367static int setup_gpu_bench(Target* target, Benchmark* bench, int maxGpuFrameLag) {
mtkleinbb6a0282014-07-01 08:43:42 -0700368 // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
cdaltonb4022962015-06-25 10:51:56 -0700369 int loops = bench->calculateLoops(FLAGS_loops);
bsalomon6eb03cc2014-08-07 14:28:50 -0700370 if (kAutoTuneLoops == loops) {
371 loops = 1;
mtkleina189ccd2014-07-14 12:28:47 -0700372 double elapsed = 0;
373 do {
mtklein527930f2014-11-06 08:04:34 -0800374 if (1<<30 == loops) {
375 // We're about to wrap. Something's wrong with the bench.
376 loops = 0;
377 break;
378 }
mtkleina189ccd2014-07-14 12:28:47 -0700379 loops *= 2;
380 // If the GPU lets frames lag at all, we need to make sure we're timing
cdaltond416a5b2015-06-23 13:23:44 -0700381 // _this_ round, not still timing last round.
382 for (int i = 0; i < maxGpuFrameLag; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700383 elapsed = time(loops, bench, target);
mtkleina189ccd2014-07-14 12:28:47 -0700384 }
385 } while (elapsed < FLAGS_gpuMs);
mtkleinbb6a0282014-07-01 08:43:42 -0700386
mtkleina189ccd2014-07-14 12:28:47 -0700387 // We've overshot at least a little. Scale back linearly.
388 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed);
reed53249782014-10-10 09:09:52 -0700389 loops = clamp_loops(loops);
mtkleinbb6a0282014-07-01 08:43:42 -0700390
tomhudsond968a6f2015-03-26 11:28:06 -0700391 // Make sure we're not still timing our calibration.
392 target->fence();
reed53249782014-10-10 09:09:52 -0700393 } else {
394 loops = detect_forever_loops(loops);
mtkleina189ccd2014-07-14 12:28:47 -0700395 }
mtkleinbb6a0282014-07-01 08:43:42 -0700396 // Pretty much the same deal as the calibration: do some warmup to make
397 // sure we're timing steady-state pipelined frames.
Brian Osman01776982017-10-10 15:41:03 -0400398 for (int i = 0; i < maxGpuFrameLag; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700399 time(loops, bench, target);
mtkleinf3723212014-06-25 14:08:00 -0700400 }
mtkleinbb6a0282014-07-01 08:43:42 -0700401
mtkleinbb6a0282014-07-01 08:43:42 -0700402 return loops;
403}
mtkleinbb6a0282014-07-01 08:43:42 -0700404
Brian Salomon6405e712017-03-20 08:54:16 -0400405#define kBogusContextType GrContextFactory::kGL_ContextType
csmartdaltone812d492017-02-21 12:36:05 -0700406#define kBogusContextOverrides GrContextFactory::ContextOverrides::kNone
bsalomonc2553372014-07-22 13:09:05 -0700407
svaisanenc47635e2016-01-28 06:05:43 -0800408static void create_config(const SkCommandLineConfig* config, SkTArray<Config>* configs) {
svaisanenc47635e2016-01-28 06:05:43 -0800409 if (const auto* gpuConfig = config->asConfigGpu()) {
Ben Wagner32fa5102017-08-10 21:25:55 -0400410 if (!FLAGS_gpu) {
411 SkDebugf("Skipping config '%s' as requested.\n", config->getTag().c_str());
svaisanenc47635e2016-01-28 06:05:43 -0800412 return;
Ben Wagner32fa5102017-08-10 21:25:55 -0400413 }
svaisanenc47635e2016-01-28 06:05:43 -0800414
svaisanenc47635e2016-01-28 06:05:43 -0800415 const auto ctxType = gpuConfig->getContextType();
csmartdaltone812d492017-02-21 12:36:05 -0700416 const auto ctxOverrides = gpuConfig->getContextOverrides();
svaisanenc47635e2016-01-28 06:05:43 -0800417 const auto sampleCount = gpuConfig->getSamples();
Greg Daniel81e7bf82017-07-19 14:47:42 -0400418 const auto colorType = gpuConfig->getColorType();
419 auto colorSpace = gpuConfig->getColorSpace();
Brian Salomonf865b052018-03-09 09:01:53 -0500420 if (gpuConfig->getSurfType() != SkCommandLineConfigGpu::SurfType::kDefault) {
421 SkDebugf("This tool only supports the default surface type.");
422 return;
423 }
svaisanenc47635e2016-01-28 06:05:43 -0800424
Brian Salomon0b4d8aa2017-10-11 15:34:27 -0400425 GrContextFactory factory(grContextOpts);
426 if (const GrContext* ctx = factory.get(ctxType, ctxOverrides)) {
Brian Osman2b23c4b2018-06-01 12:25:08 -0400427 GrPixelConfig grPixConfig = SkColorType2GrPixelConfig(colorType);
Brian Salomonbdecacf2018-02-02 20:32:49 -0500428 int supportedSampleCount =
Robert Phillips9da87e02019-02-04 13:26:26 -0500429 ctx->priv().caps()->getRenderTargetSampleCount(sampleCount, grPixConfig);
Greg Daniel81e7bf82017-07-19 14:47:42 -0400430 if (sampleCount != supportedSampleCount) {
Ben Wagner32fa5102017-08-10 21:25:55 -0400431 SkDebugf("Configuration '%s' sample count %d is not a supported sample count.\n",
432 config->getTag().c_str(), sampleCount);
svaisanenc47635e2016-01-28 06:05:43 -0800433 return;
434 }
435 } else {
Ben Wagner32fa5102017-08-10 21:25:55 -0400436 SkDebugf("No context was available matching config '%s'.\n",
437 config->getTag().c_str());
svaisanenc47635e2016-01-28 06:05:43 -0800438 return;
439 }
440
441 Config target = {
kkinnunend4e1c352016-03-01 23:41:26 -0800442 gpuConfig->getTag(),
svaisanenc47635e2016-01-28 06:05:43 -0800443 Benchmark::kGPU_Backend,
Greg Daniel81e7bf82017-07-19 14:47:42 -0400444 colorType,
svaisanenc47635e2016-01-28 06:05:43 -0800445 kPremul_SkAlphaType,
Greg Daniel81e7bf82017-07-19 14:47:42 -0400446 sk_ref_sp(colorSpace),
svaisanenc47635e2016-01-28 06:05:43 -0800447 sampleCount,
448 ctxType,
csmartdaltone812d492017-02-21 12:36:05 -0700449 ctxOverrides,
kkinnunend4e1c352016-03-01 23:41:26 -0800450 gpuConfig->getUseDIText()
451 };
svaisanenc47635e2016-01-28 06:05:43 -0800452
453 configs->push_back(target);
454 return;
455 }
svaisanenc47635e2016-01-28 06:05:43 -0800456
brianosmanb109b8c2016-06-16 13:03:24 -0700457 #define CPU_CONFIG(name, backend, color, alpha, colorSpace) \
458 if (config->getTag().equals(#name)) { \
Ben Wagner32fa5102017-08-10 21:25:55 -0400459 if (!FLAGS_cpu) { \
460 SkDebugf("Skipping config '%s' as requested.\n", \
461 config->getTag().c_str()); \
462 return; \
463 } \
brianosmanb109b8c2016-06-16 13:03:24 -0700464 Config config = { \
465 SkString(#name), Benchmark::backend, color, alpha, colorSpace, \
csmartdaltone812d492017-02-21 12:36:05 -0700466 0, kBogusContextType, kBogusContextOverrides, false \
brianosmanb109b8c2016-06-16 13:03:24 -0700467 }; \
468 configs->push_back(config); \
469 return; \
mtkleinbb6a0282014-07-01 08:43:42 -0700470 }
mtkleine714e752014-07-31 12:13:48 -0700471
Ben Wagner32fa5102017-08-10 21:25:55 -0400472 CPU_CONFIG(nonrendering, kNonRendering_Backend,
473 kUnknown_SkColorType, kUnpremul_SkAlphaType, nullptr)
mtkleinbb6c41b2016-03-08 11:31:11 -0800474
Mike Klein0e4041f2018-06-19 16:00:40 -0400475 CPU_CONFIG(a8, kRaster_Backend, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr)
476 CPU_CONFIG(8888, kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType, nullptr)
477 CPU_CONFIG(565, kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType, nullptr)
478
479 // 'narrow' has a gamut narrower than sRGB, and different transfer function.
Brian Osman82ebe042019-01-04 17:03:00 -0500480 auto narrow = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gNarrow_toXYZD50),
Mike Klein0e4041f2018-06-19 16:00:40 -0400481 srgb = SkColorSpace::MakeSRGB(),
482 srgbLinear = SkColorSpace::MakeSRGBLinear();
483
484 CPU_CONFIG( f16, kRaster_Backend, kRGBA_F16_SkColorType, kPremul_SkAlphaType, srgbLinear)
485 CPU_CONFIG( srgb, kRaster_Backend, kRGBA_8888_SkColorType, kPremul_SkAlphaType, srgb )
486 CPU_CONFIG( esrgb, kRaster_Backend, kRGBA_F16_SkColorType, kPremul_SkAlphaType, srgb )
487 CPU_CONFIG( narrow, kRaster_Backend, kRGBA_8888_SkColorType, kPremul_SkAlphaType, narrow )
488 CPU_CONFIG(enarrow, kRaster_Backend, kRGBA_F16_SkColorType, kPremul_SkAlphaType, narrow )
mtkleinbb6a0282014-07-01 08:43:42 -0700489
svaisanenc47635e2016-01-28 06:05:43 -0800490 #undef CPU_CONFIG
Ben Wagner32fa5102017-08-10 21:25:55 -0400491
492 SkDebugf("Unknown config '%s'.\n", config->getTag().c_str());
mtkleinf3723212014-06-25 14:08:00 -0700493}
494
svaisanenc47635e2016-01-28 06:05:43 -0800495// Append all configs that are enabled and supported.
496void create_configs(SkTArray<Config>* configs) {
497 SkCommandLineConfigArray array;
498 ParseConfigs(FLAGS_config, &array);
499 for (int i = 0; i < array.count(); ++i) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400500 create_config(array[i].get(), configs);
svaisanenc47635e2016-01-28 06:05:43 -0800501 }
Ben Wagner32fa5102017-08-10 21:25:55 -0400502
503 // If no just default configs were requested, then we're okay.
504 if (array.count() == 0 || FLAGS_config.count() == 0 ||
Ben Wagner32fa5102017-08-10 21:25:55 -0400505 // Otherwise, make sure that all specified configs have been created.
506 array.count() == configs->count()) {
507 return;
508 }
Ben Wagner32fa5102017-08-10 21:25:55 -0400509 exit(1);
svaisanenc47635e2016-01-28 06:05:43 -0800510}
511
brianosman9f1f6e22016-09-15 08:33:02 -0700512// disable warning : switch statement contains default but no 'case' labels
513#if defined _WIN32
514#pragma warning ( push )
515#pragma warning ( disable : 4065 )
516#endif
517
halcanary96fcdcc2015-08-27 07:41:13 -0700518// If bench is enabled for config, returns a Target* for it, otherwise nullptr.
bsalomonc2553372014-07-22 13:09:05 -0700519static Target* is_enabled(Benchmark* bench, const Config& config) {
520 if (!bench->isSuitableFor(config.backend)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700521 return nullptr;
bsalomonc2553372014-07-22 13:09:05 -0700522 }
523
reede5ea5002014-09-03 11:54:58 -0700524 SkImageInfo info = SkImageInfo::Make(bench->getSize().fX, bench->getSize().fY,
brianosmanb109b8c2016-06-16 13:03:24 -0700525 config.color, config.alpha, config.colorSpace);
bsalomonc2553372014-07-22 13:09:05 -0700526
halcanary96fcdcc2015-08-27 07:41:13 -0700527 Target* target = nullptr;
bsalomonc2553372014-07-22 13:09:05 -0700528
tomhudsond968a6f2015-03-26 11:28:06 -0700529 switch (config.backend) {
tomhudsond968a6f2015-03-26 11:28:06 -0700530 case Benchmark::kGPU_Backend:
531 target = new GPUTarget(config);
532 break;
tomhudsond968a6f2015-03-26 11:28:06 -0700533 default:
534 target = new Target(config);
535 break;
536 }
bsalomonc2553372014-07-22 13:09:05 -0700537
tomhudsond968a6f2015-03-26 11:28:06 -0700538 if (!target->init(info, bench)) {
bsalomonc2553372014-07-22 13:09:05 -0700539 delete target;
halcanary96fcdcc2015-08-27 07:41:13 -0700540 return nullptr;
bsalomonc2553372014-07-22 13:09:05 -0700541 }
542 return target;
543}
544
brianosman9f1f6e22016-09-15 08:33:02 -0700545#if defined _WIN32
546#pragma warning ( pop )
547#endif
548
reed42943c82016-09-12 12:01:44 -0700549static bool valid_brd_bench(sk_sp<SkData> encoded, SkColorType colorType, uint32_t sampleSize,
msarettd1227a72016-05-18 06:23:57 -0700550 uint32_t minOutputSize, int* width, int* height) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400551 std::unique_ptr<SkBitmapRegionDecoder> brd(
msarettd1227a72016-05-18 06:23:57 -0700552 SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy));
msarett7f691442015-09-22 11:56:16 -0700553 if (nullptr == brd.get()) {
554 // This is indicates that subset decoding is not supported for a particular image format.
555 return false;
556 }
557
msarett7f691442015-09-22 11:56:16 -0700558 if (sampleSize * minOutputSize > (uint32_t) brd->width() || sampleSize * minOutputSize >
559 (uint32_t) brd->height()) {
560 // This indicates that the image is not large enough to decode a
561 // minOutputSize x minOutputSize subset at the given sampleSize.
562 return false;
563 }
564
565 // Set the image width and height. The calling code will use this to choose subsets to decode.
566 *width = brd->width();
567 *height = brd->height();
568 return true;
569}
570
egdaniel3bf92062015-06-26 08:12:46 -0700571static void cleanup_run(Target* target) {
halcanary385fe4d2015-08-26 13:07:48 -0700572 delete target;
egdaniel3bf92062015-06-26 08:12:46 -0700573}
574
fmalita6519c212016-09-14 08:05:17 -0700575static void collect_files(const SkCommandLineFlags::StringArray& paths, const char* ext,
576 SkTArray<SkString>* list) {
577 for (int i = 0; i < paths.count(); ++i) {
578 if (SkStrEndsWith(paths[i], ext)) {
579 list->push_back(SkString(paths[i]));
580 } else {
581 SkOSFile::Iter it(paths[i], ext);
582 SkString path;
583 while (it.next(&path)) {
584 list->push_back(SkOSPath::Join(paths[i], path.c_str()));
585 }
586 }
587 }
588}
589
mtkleine714e752014-07-31 12:13:48 -0700590class BenchmarkStream {
591public:
mtklein92007582014-08-01 07:46:52 -0700592 BenchmarkStream() : fBenches(BenchRegistry::Head())
593 , fGMs(skiagm::GMRegistry::Head())
mtkleinfd731ce2014-09-10 12:19:30 -0700594 , fCurrentRecording(0)
Mike Reede45ff462017-12-06 10:47:03 -0500595 , fCurrentDeserialPicture(0)
mtklein92007582014-08-01 07:46:52 -0700596 , fCurrentScale(0)
robertphillips5b693772014-11-21 06:19:36 -0800597 , fCurrentSKP(0)
fmalita6519c212016-09-14 08:05:17 -0700598 , fCurrentSVG(0)
msarett95f192d2015-02-13 09:05:41 -0800599 , fCurrentUseMPD(0)
scroggo60869a42015-04-01 12:09:17 -0700600 , fCurrentCodec(0)
msarett84451022016-02-11 06:45:51 -0800601 , fCurrentAndroidCodec(0)
msarett7f691442015-09-22 11:56:16 -0700602 , fCurrentBRDImage(0)
msarett95f192d2015-02-13 09:05:41 -0800603 , fCurrentColorType(0)
msarettc7796b92016-01-07 14:20:20 -0800604 , fCurrentAlphaType(0)
msarettb23e6aa2015-06-09 13:56:10 -0700605 , fCurrentSubsetType(0)
msarett84451022016-02-11 06:45:51 -0800606 , fCurrentSampleSize(0)
msarettb23e6aa2015-06-09 13:56:10 -0700607 , fCurrentAnimSKP(0) {
fmalita6519c212016-09-14 08:05:17 -0700608 collect_files(FLAGS_skps, ".skp", &fSKPs);
609 collect_files(FLAGS_svgs, ".svg", &fSVGs);
mtkleine714e752014-07-31 12:13:48 -0700610
mtklein92007582014-08-01 07:46:52 -0700611 if (4 != sscanf(FLAGS_clip[0], "%d,%d,%d,%d",
612 &fClip.fLeft, &fClip.fTop, &fClip.fRight, &fClip.fBottom)) {
613 SkDebugf("Can't parse %s from --clip as an SkIRect.\n", FLAGS_clip[0]);
614 exit(1);
615 }
616
617 for (int i = 0; i < FLAGS_scales.count(); i++) {
618 if (1 != sscanf(FLAGS_scales[i], "%f", &fScales.push_back())) {
619 SkDebugf("Can't parse %s from --scales as an SkScalar.\n", FLAGS_scales[i]);
620 exit(1);
621 }
622 }
robertphillips5b693772014-11-21 06:19:36 -0800623
cdalton63a82852015-06-29 14:06:10 -0700624 if (2 != sscanf(FLAGS_zoom[0], "%f,%lf", &fZoomMax, &fZoomPeriodMs)) {
625 SkDebugf("Can't parse %s from --zoom as a zoomMax,zoomPeriodMs.\n", FLAGS_zoom[0]);
joshualitt261c3ad2015-04-27 09:16:57 -0700626 exit(1);
627 }
628
robertphillips5b693772014-11-21 06:19:36 -0800629 if (FLAGS_mpd) {
630 fUseMPDs.push_back() = true;
631 }
mtkleinc751ecb2015-06-15 08:56:38 -0700632 fUseMPDs.push_back() = false;
mtklein95553d92015-03-12 08:24:21 -0700633
msarett95f192d2015-02-13 09:05:41 -0800634 // Prepare the images for decoding
msarett69deca82016-04-29 09:38:40 -0700635 if (!CollectImages(FLAGS_images, &fImages)) {
scroggo86737142016-02-03 12:19:11 -0800636 exit(1);
msarett95f192d2015-02-13 09:05:41 -0800637 }
mtklein95553d92015-03-12 08:24:21 -0700638
msarett95f192d2015-02-13 09:05:41 -0800639 // Choose the candidate color types for image decoding
msarett67cb6662016-06-21 08:49:26 -0700640 fColorTypes.push_back(kN32_SkColorType);
641 if (!FLAGS_simpleCodec) {
642 fColorTypes.push_back(kRGB_565_SkColorType);
643 fColorTypes.push_back(kAlpha_8_SkColorType);
msarett67cb6662016-06-21 08:49:26 -0700644 fColorTypes.push_back(kGray_8_SkColorType);
645 }
mtklein92007582014-08-01 07:46:52 -0700646 }
647
reedca2622b2016-03-18 07:25:55 -0700648 static sk_sp<SkPicture> ReadPicture(const char* path) {
mtkleinfd731ce2014-09-10 12:19:30 -0700649 // Not strictly necessary, as it will be checked again later,
650 // but helps to avoid a lot of pointless work if we're going to skip it.
cdalton91e457d2016-02-17 11:10:16 -0800651 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, SkOSPath::Basename(path).c_str())) {
reedca2622b2016-03-18 07:25:55 -0700652 return nullptr;
mtkleinfd731ce2014-09-10 12:19:30 -0700653 }
654
bungemanf93d7112016-09-16 06:24:20 -0700655 std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
656 if (!stream) {
mtkleinfd731ce2014-09-10 12:19:30 -0700657 SkDebugf("Could not read %s.\n", path);
reedca2622b2016-03-18 07:25:55 -0700658 return nullptr;
mtkleinfd731ce2014-09-10 12:19:30 -0700659 }
660
reedca2622b2016-03-18 07:25:55 -0700661 return SkPicture::MakeFromStream(stream.get());
mtkleinfd731ce2014-09-10 12:19:30 -0700662 }
663
fmalita6519c212016-09-14 08:05:17 -0700664 static sk_sp<SkPicture> ReadSVGPicture(const char* path) {
Brian Osman133823d2018-09-19 14:14:15 -0400665 sk_sp<SkData> data(SkData::MakeFromFileName(path));
666 if (!data) {
fmalita6519c212016-09-14 08:05:17 -0700667 SkDebugf("Could not read %s.\n", path);
668 return nullptr;
669 }
670
Hal Canary0f666812018-03-22 15:21:12 -0400671#ifdef SK_XML
Brian Osman133823d2018-09-19 14:14:15 -0400672 SkMemoryStream stream(std::move(data));
fmalitae1baa7c2016-09-14 12:04:30 -0700673 sk_sp<SkSVGDOM> svgDom = SkSVGDOM::MakeFromStream(stream);
fmalita6519c212016-09-14 08:05:17 -0700674 if (!svgDom) {
675 SkDebugf("Could not parse %s.\n", path);
676 return nullptr;
677 }
678
fmalitae1baa7c2016-09-14 12:04:30 -0700679 // Use the intrinsic SVG size if available, otherwise fall back to a default value.
680 static const SkSize kDefaultContainerSize = SkSize::Make(128, 128);
681 if (svgDom->containerSize().isEmpty()) {
682 svgDom->setContainerSize(kDefaultContainerSize);
683 }
684
fmalita6519c212016-09-14 08:05:17 -0700685 SkPictureRecorder recorder;
fmalitae1baa7c2016-09-14 12:04:30 -0700686 svgDom->render(recorder.beginRecording(svgDom->containerSize().width(),
687 svgDom->containerSize().height()));
fmalita6519c212016-09-14 08:05:17 -0700688 return recorder.finishRecordingAsPicture();
Hal Canary0f666812018-03-22 15:21:12 -0400689#else
690 return nullptr;
691#endif // SK_XML
fmalita6519c212016-09-14 08:05:17 -0700692 }
693
mtklein92007582014-08-01 07:46:52 -0700694 Benchmark* next() {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400695 std::unique_ptr<Benchmark> bench;
mtklein65dfd2f2016-02-03 10:40:54 -0800696 do {
697 bench.reset(this->rawNext());
698 if (!bench) {
699 return nullptr;
700 }
701 } while(SkCommandLineFlags::ShouldSkip(FLAGS_sourceType, fSourceType) ||
702 SkCommandLineFlags::ShouldSkip(FLAGS_benchType, fBenchType));
mtklein18300a32016-03-16 13:53:35 -0700703 return bench.release();
mtklein65dfd2f2016-02-03 10:40:54 -0800704 }
705
706 Benchmark* rawNext() {
mtkleine714e752014-07-31 12:13:48 -0700707 if (fBenches) {
Hal Canary972eba32018-07-30 17:07:07 -0400708 Benchmark* bench = fBenches->get()(nullptr);
mtkleine714e752014-07-31 12:13:48 -0700709 fBenches = fBenches->next();
mtklein92007582014-08-01 07:46:52 -0700710 fSourceType = "bench";
mtkleinfd731ce2014-09-10 12:19:30 -0700711 fBenchType = "micro";
mtkleine714e752014-07-31 12:13:48 -0700712 return bench;
713 }
mtklein92007582014-08-01 07:46:52 -0700714
mtkleine714e752014-07-31 12:13:48 -0700715 while (fGMs) {
Hal Canary972eba32018-07-30 17:07:07 -0400716 std::unique_ptr<skiagm::GM> gm(fGMs->get()(nullptr));
mtkleine714e752014-07-31 12:13:48 -0700717 fGMs = fGMs->next();
mtkleincf5d9c92015-01-23 10:31:45 -0800718 if (gm->runAsBench()) {
mtklein92007582014-08-01 07:46:52 -0700719 fSourceType = "gm";
mtkleinfd731ce2014-09-10 12:19:30 -0700720 fBenchType = "micro";
mtklein18300a32016-03-16 13:53:35 -0700721 return new GMBench(gm.release());
mtkleine714e752014-07-31 12:13:48 -0700722 }
723 }
mtklein92007582014-08-01 07:46:52 -0700724
mtkleinfd731ce2014-09-10 12:19:30 -0700725 // First add all .skps as RecordingBenches.
726 while (fCurrentRecording < fSKPs.count()) {
727 const SkString& path = fSKPs[fCurrentRecording++];
reedca2622b2016-03-18 07:25:55 -0700728 sk_sp<SkPicture> pic = ReadPicture(path.c_str());
729 if (!pic) {
mtkleinfd731ce2014-09-10 12:19:30 -0700730 continue;
731 }
732 SkString name = SkOSPath::Basename(path.c_str());
733 fSourceType = "skp";
734 fBenchType = "recording";
Mike Klein88d90712018-01-27 17:30:04 +0000735 fSKPBytes = static_cast<double>(pic->approximateBytesUsed());
736 fSKPOps = pic->approximateOpCount();
mtklein8c1a4f82016-08-08 06:56:22 -0700737 return new RecordingBench(name.c_str(), pic.get(), FLAGS_bbh, FLAGS_lite);
mtkleinfd731ce2014-09-10 12:19:30 -0700738 }
739
Mike Reede45ff462017-12-06 10:47:03 -0500740 // Add all .skps as DeserializePictureBenchs.
741 while (fCurrentDeserialPicture < fSKPs.count()) {
742 const SkString& path = fSKPs[fCurrentDeserialPicture++];
743 sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str());
744 if (!data) {
745 continue;
746 }
747 SkString name = SkOSPath::Basename(path.c_str());
748 fSourceType = "skp";
749 fBenchType = "deserial";
Mike Reed7557bbb2017-12-24 19:50:57 -0500750 fSKPBytes = static_cast<double>(data->size());
Mike Klein88d90712018-01-27 17:30:04 +0000751 fSKPOps = 0;
Mike Reede45ff462017-12-06 10:47:03 -0500752 return new DeserializePictureBench(name.c_str(), std::move(data));
753 }
754
mtkleinfd731ce2014-09-10 12:19:30 -0700755 // Then once each for each scale as SKPBenches (playback).
mtklein92007582014-08-01 07:46:52 -0700756 while (fCurrentScale < fScales.count()) {
757 while (fCurrentSKP < fSKPs.count()) {
robertphillips5b693772014-11-21 06:19:36 -0800758 const SkString& path = fSKPs[fCurrentSKP];
reedca2622b2016-03-18 07:25:55 -0700759 sk_sp<SkPicture> pic = ReadPicture(path.c_str());
760 if (!pic) {
robertphillips5b693772014-11-21 06:19:36 -0800761 fCurrentSKP++;
mtklein92007582014-08-01 07:46:52 -0700762 continue;
763 }
robertphillips5b693772014-11-21 06:19:36 -0800764
765 while (fCurrentUseMPD < fUseMPDs.count()) {
766 if (FLAGS_bbh) {
767 // The SKP we read off disk doesn't have a BBH. Re-record so it grows one.
768 SkRTreeFactory factory;
769 SkPictureRecorder recorder;
robertphillips5b693772014-11-21 06:19:36 -0800770 pic->playback(recorder.beginRecording(pic->cullRect().width(),
771 pic->cullRect().height(),
mtklein748ca3b2015-01-15 10:56:12 -0800772 &factory,
robertphillipsdda54452016-07-13 13:27:16 -0700773 0));
reedca2622b2016-03-18 07:25:55 -0700774 pic = recorder.finishRecordingAsPicture();
robertphillips5b693772014-11-21 06:19:36 -0800775 }
776 SkString name = SkOSPath::Basename(path.c_str());
777 fSourceType = "skp";
778 fBenchType = "playback";
halcanary385fe4d2015-08-26 13:07:48 -0700779 return new SKPBench(name.c_str(), pic.get(), fClip, fScales[fCurrentScale],
780 fUseMPDs[fCurrentUseMPD++], FLAGS_loopSKP);
mtklein20840502014-08-21 15:51:22 -0700781 }
robertphillips5b693772014-11-21 06:19:36 -0800782 fCurrentUseMPD = 0;
783 fCurrentSKP++;
mtklein92007582014-08-01 07:46:52 -0700784 }
fmalita6519c212016-09-14 08:05:17 -0700785
786 while (fCurrentSVG++ < fSVGs.count()) {
787 const char* path = fSVGs[fCurrentSVG - 1].c_str();
788 if (sk_sp<SkPicture> pic = ReadSVGPicture(path)) {
789 fSourceType = "svg";
790 fBenchType = "playback";
791 return new SKPBench(SkOSPath::Basename(path).c_str(), pic.get(), fClip,
792 fScales[fCurrentScale], false, FLAGS_loopSKP);
793 }
794 }
795
mtklein92007582014-08-01 07:46:52 -0700796 fCurrentSKP = 0;
fmalita6519c212016-09-14 08:05:17 -0700797 fCurrentSVG = 0;
mtklein92007582014-08-01 07:46:52 -0700798 fCurrentScale++;
799 }
800
joshualitt261c3ad2015-04-27 09:16:57 -0700801 // Now loop over each skp again if we have an animation
cdalton63a82852015-06-29 14:06:10 -0700802 if (fZoomMax != 1.0f && fZoomPeriodMs > 0) {
joshualitt261c3ad2015-04-27 09:16:57 -0700803 while (fCurrentAnimSKP < fSKPs.count()) {
804 const SkString& path = fSKPs[fCurrentAnimSKP];
reedca2622b2016-03-18 07:25:55 -0700805 sk_sp<SkPicture> pic = ReadPicture(path.c_str());
806 if (!pic) {
joshualitt261c3ad2015-04-27 09:16:57 -0700807 fCurrentAnimSKP++;
808 continue;
809 }
810
811 fCurrentAnimSKP++;
812 SkString name = SkOSPath::Basename(path.c_str());
Hal Canary2db83612016-11-04 13:02:54 -0400813 sk_sp<SKPAnimationBench::Animation> animation(
cdalton63a82852015-06-29 14:06:10 -0700814 SKPAnimationBench::CreateZoomAnimation(fZoomMax, fZoomPeriodMs));
Hal Canary2db83612016-11-04 13:02:54 -0400815 return new SKPAnimationBench(name.c_str(), pic.get(), fClip, animation.get(),
halcanary385fe4d2015-08-26 13:07:48 -0700816 FLAGS_loopSKP);
joshualitt261c3ad2015-04-27 09:16:57 -0700817 }
818 }
819
scroggo60869a42015-04-01 12:09:17 -0700820 for (; fCurrentCodec < fImages.count(); fCurrentCodec++) {
scroggo303fa352015-10-05 11:03:34 -0700821 fSourceType = "image";
822 fBenchType = "skcodec";
scroggo60869a42015-04-01 12:09:17 -0700823 const SkString& path = fImages[fCurrentCodec];
mtklein6f0ff912016-01-11 09:04:21 -0800824 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path.c_str())) {
825 continue;
826 }
bungeman38d909e2016-08-02 14:40:46 -0700827 sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
Mike Reedede7bac2017-07-23 15:30:02 -0400828 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
scroggo60869a42015-04-01 12:09:17 -0700829 if (!codec) {
830 // Nothing to time.
msarett9d9725c2015-04-24 11:41:55 -0700831 SkDebugf("Cannot find codec for %s\n", path.c_str());
scroggo60869a42015-04-01 12:09:17 -0700832 continue;
833 }
scroggo21027992015-04-02 13:22:38 -0700834
scroggo60869a42015-04-01 12:09:17 -0700835 while (fCurrentColorType < fColorTypes.count()) {
scroggo21027992015-04-02 13:22:38 -0700836 const SkColorType colorType = fColorTypes[fCurrentColorType];
scroggo21027992015-04-02 13:22:38 -0700837
msarettc7796b92016-01-07 14:20:20 -0800838 SkAlphaType alphaType = codec->getInfo().alphaType();
msarett67cb6662016-06-21 08:49:26 -0700839 if (FLAGS_simpleCodec) {
840 if (kUnpremul_SkAlphaType == alphaType) {
841 alphaType = kPremul_SkAlphaType;
842 }
843
844 fCurrentColorType++;
845 } else {
846 switch (alphaType) {
847 case kOpaque_SkAlphaType:
848 // We only need to test one alpha type (opaque).
msarettc7796b92016-01-07 14:20:20 -0800849 fCurrentColorType++;
msarett67cb6662016-06-21 08:49:26 -0700850 break;
851 case kUnpremul_SkAlphaType:
852 case kPremul_SkAlphaType:
853 if (0 == fCurrentAlphaType) {
854 // Test unpremul first.
855 alphaType = kUnpremul_SkAlphaType;
856 fCurrentAlphaType++;
857 } else {
858 // Test premul.
859 alphaType = kPremul_SkAlphaType;
860 fCurrentAlphaType = 0;
861 fCurrentColorType++;
862 }
863 break;
864 default:
865 SkASSERT(false);
866 fCurrentColorType++;
867 break;
868 }
scroggo21027992015-04-02 13:22:38 -0700869 }
870
msarettc7796b92016-01-07 14:20:20 -0800871 // Make sure we can decode to this color type and alpha type.
872 SkImageInfo info =
873 codec->getInfo().makeColorType(colorType).makeAlphaType(alphaType);
scroggo21027992015-04-02 13:22:38 -0700874 const size_t rowBytes = info.minRowBytes();
Mike Reedf0ffb892017-10-03 14:47:21 -0400875 SkAutoMalloc storage(info.computeByteSize(rowBytes));
scroggo21027992015-04-02 13:22:38 -0700876
scroggoeb602a52015-07-09 08:16:03 -0700877 const SkCodec::Result result = codec->getPixels(
Leon Scroggins571b30f2017-07-11 17:35:31 +0000878 info, storage.get(), rowBytes);
scroggo60869a42015-04-01 12:09:17 -0700879 switch (result) {
scroggoeb602a52015-07-09 08:16:03 -0700880 case SkCodec::kSuccess:
881 case SkCodec::kIncompleteInput:
scroggo60869a42015-04-01 12:09:17 -0700882 return new CodecBench(SkOSPath::Basename(path.c_str()),
bungeman38d909e2016-08-02 14:40:46 -0700883 encoded.get(), colorType, alphaType);
scroggoeb602a52015-07-09 08:16:03 -0700884 case SkCodec::kInvalidConversion:
scroggo60869a42015-04-01 12:09:17 -0700885 // This is okay. Not all conversions are valid.
886 break;
scroggo60869a42015-04-01 12:09:17 -0700887 default:
888 // This represents some sort of failure.
889 SkASSERT(false);
890 break;
891 }
892 }
893 fCurrentColorType = 0;
894 }
895
msarett84451022016-02-11 06:45:51 -0800896 // Run AndroidCodecBenches
897 const int sampleSizes[] = { 2, 4, 8 };
898 for (; fCurrentAndroidCodec < fImages.count(); fCurrentAndroidCodec++) {
899 fSourceType = "image";
900 fBenchType = "skandroidcodec";
901
902 const SkString& path = fImages[fCurrentAndroidCodec];
903 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path.c_str())) {
904 continue;
905 }
bungeman38d909e2016-08-02 14:40:46 -0700906 sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
Mike Reedede7bac2017-07-23 15:30:02 -0400907 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
msarett84451022016-02-11 06:45:51 -0800908 if (!codec) {
909 // Nothing to time.
910 SkDebugf("Cannot find codec for %s\n", path.c_str());
911 continue;
912 }
913
914 while (fCurrentSampleSize < (int) SK_ARRAY_COUNT(sampleSizes)) {
915 int sampleSize = sampleSizes[fCurrentSampleSize];
916 fCurrentSampleSize++;
917 if (10 * sampleSize > SkTMin(codec->getInfo().width(), codec->getInfo().height())) {
918 // Avoid benchmarking scaled decodes of already small images.
919 break;
920 }
921
bungeman38d909e2016-08-02 14:40:46 -0700922 return new AndroidCodecBench(SkOSPath::Basename(path.c_str()),
923 encoded.get(), sampleSize);
msarett84451022016-02-11 06:45:51 -0800924 }
925 fCurrentSampleSize = 0;
926 }
927
msarett7f691442015-09-22 11:56:16 -0700928 // Run the BRDBenches
msarett7f691442015-09-22 11:56:16 -0700929 // We intend to create benchmarks that model the use cases in
930 // android/libraries/social/tiledimage. In this library, an image is decoded in 512x512
931 // tiles. The image can be translated freely, so the location of a tile may be anywhere in
932 // the image. For that reason, we will benchmark decodes in five representative locations
933 // in the image. Additionally, this use case utilizes power of two scaling, so we will
934 // test on power of two sample sizes. The output tile is always 512x512, so, when a
935 // sampleSize is used, the size of the subset that is decoded is always
936 // (sampleSize*512)x(sampleSize*512).
937 // There are a few good reasons to only test on power of two sample sizes at this time:
msarett7f691442015-09-22 11:56:16 -0700938 // All use cases we are aware of only scale by powers of two.
939 // PNG decodes use the indicated sampling strategy regardless of the sample size, so
940 // these tests are sufficient to provide good coverage of our scaling options.
msarett84451022016-02-11 06:45:51 -0800941 const uint32_t brdSampleSizes[] = { 1, 2, 4, 8, 16 };
msarett7f691442015-09-22 11:56:16 -0700942 const uint32_t minOutputSize = 512;
mtklein6f0ff912016-01-11 09:04:21 -0800943 for (; fCurrentBRDImage < fImages.count(); fCurrentBRDImage++) {
msarettd1227a72016-05-18 06:23:57 -0700944 fSourceType = "image";
945 fBenchType = "BRD";
946
mtklein6f0ff912016-01-11 09:04:21 -0800947 const SkString& path = fImages[fCurrentBRDImage];
948 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path.c_str())) {
949 continue;
950 }
scroggo860e8a62015-10-15 07:51:28 -0700951
msarettd1227a72016-05-18 06:23:57 -0700952 while (fCurrentColorType < fColorTypes.count()) {
953 while (fCurrentSampleSize < (int) SK_ARRAY_COUNT(brdSampleSizes)) {
954 while (fCurrentSubsetType <= kLastSingle_SubsetType) {
scroggo860e8a62015-10-15 07:51:28 -0700955
bungeman38d909e2016-08-02 14:40:46 -0700956 sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
msarettd1227a72016-05-18 06:23:57 -0700957 const SkColorType colorType = fColorTypes[fCurrentColorType];
958 uint32_t sampleSize = brdSampleSizes[fCurrentSampleSize];
959 int currentSubsetType = fCurrentSubsetType++;
scroggo860e8a62015-10-15 07:51:28 -0700960
msarettd1227a72016-05-18 06:23:57 -0700961 int width = 0;
962 int height = 0;
reed42943c82016-09-12 12:01:44 -0700963 if (!valid_brd_bench(encoded, colorType, sampleSize, minOutputSize,
msarettd1227a72016-05-18 06:23:57 -0700964 &width, &height)) {
965 break;
msarett7f691442015-09-22 11:56:16 -0700966 }
msarettd1227a72016-05-18 06:23:57 -0700967
968 SkString basename = SkOSPath::Basename(path.c_str());
969 SkIRect subset;
970 const uint32_t subsetSize = sampleSize * minOutputSize;
971 switch (currentSubsetType) {
972 case kTopLeft_SubsetType:
973 basename.append("_TopLeft");
974 subset = SkIRect::MakeXYWH(0, 0, subsetSize, subsetSize);
975 break;
976 case kTopRight_SubsetType:
977 basename.append("_TopRight");
978 subset = SkIRect::MakeXYWH(width - subsetSize, 0, subsetSize,
979 subsetSize);
980 break;
981 case kMiddle_SubsetType:
982 basename.append("_Middle");
983 subset = SkIRect::MakeXYWH((width - subsetSize) / 2,
984 (height - subsetSize) / 2, subsetSize, subsetSize);
985 break;
986 case kBottomLeft_SubsetType:
987 basename.append("_BottomLeft");
988 subset = SkIRect::MakeXYWH(0, height - subsetSize, subsetSize,
989 subsetSize);
990 break;
991 case kBottomRight_SubsetType:
992 basename.append("_BottomRight");
993 subset = SkIRect::MakeXYWH(width - subsetSize,
994 height - subsetSize, subsetSize, subsetSize);
995 break;
996 default:
997 SkASSERT(false);
998 }
999
1000 return new BitmapRegionDecoderBench(basename.c_str(), encoded.get(),
1001 colorType, sampleSize, subset);
msarett7f691442015-09-22 11:56:16 -07001002 }
msarettd1227a72016-05-18 06:23:57 -07001003 fCurrentSubsetType = 0;
1004 fCurrentSampleSize++;
msarett7f691442015-09-22 11:56:16 -07001005 }
msarettd1227a72016-05-18 06:23:57 -07001006 fCurrentSampleSize = 0;
1007 fCurrentColorType++;
msarett7f691442015-09-22 11:56:16 -07001008 }
msarettd1227a72016-05-18 06:23:57 -07001009 fCurrentColorType = 0;
msarett7f691442015-09-22 11:56:16 -07001010 }
1011
halcanary96fcdcc2015-08-27 07:41:13 -07001012 return nullptr;
mtkleine714e752014-07-31 12:13:48 -07001013 }
mtklein92007582014-08-01 07:46:52 -07001014
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001015 void fillCurrentOptions(NanoJSONResultsWriter& log) const {
1016 log.appendString("source_type", fSourceType);
1017 log.appendString("bench_type", fBenchType);
mtklein92007582014-08-01 07:46:52 -07001018 if (0 == strcmp(fSourceType, "skp")) {
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001019 log.appendString("clip",
mtklein92007582014-08-01 07:46:52 -07001020 SkStringPrintf("%d %d %d %d", fClip.fLeft, fClip.fTop,
1021 fClip.fRight, fClip.fBottom).c_str());
djsollenf2b340f2016-01-29 08:51:04 -08001022 SkASSERT_RELEASE(fCurrentScale < fScales.count()); // debugging paranoia
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001023 log.appendString("scale", SkStringPrintf("%.2g", fScales[fCurrentScale]).c_str());
robertphillips5b693772014-11-21 06:19:36 -08001024 if (fCurrentUseMPD > 0) {
1025 SkASSERT(1 == fCurrentUseMPD || 2 == fCurrentUseMPD);
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001026 log.appendString("multi_picture_draw",
1027 fUseMPDs[fCurrentUseMPD-1] ? "true" : "false");
robertphillips5b693772014-11-21 06:19:36 -08001028 }
mtklein92007582014-08-01 07:46:52 -07001029 }
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001030 }
1031
1032 void fillCurrentMetrics(NanoJSONResultsWriter& log) const {
mtklein051e56d2014-12-04 08:46:51 -08001033 if (0 == strcmp(fBenchType, "recording")) {
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001034 log.appendMetric("bytes", fSKPBytes);
1035 log.appendMetric("ops", fSKPOps);
mtklein051e56d2014-12-04 08:46:51 -08001036 }
mtklein92007582014-08-01 07:46:52 -07001037 }
1038
mtkleine714e752014-07-31 12:13:48 -07001039private:
msarettb23e6aa2015-06-09 13:56:10 -07001040 enum SubsetType {
1041 kTopLeft_SubsetType = 0,
1042 kTopRight_SubsetType = 1,
msarettab80e352015-06-17 10:28:22 -07001043 kMiddle_SubsetType = 2,
1044 kBottomLeft_SubsetType = 3,
1045 kBottomRight_SubsetType = 4,
1046 kTranslate_SubsetType = 5,
1047 kZoom_SubsetType = 6,
msarett7f691442015-09-22 11:56:16 -07001048 kLast_SubsetType = kZoom_SubsetType,
1049 kLastSingle_SubsetType = kBottomRight_SubsetType,
msarettb23e6aa2015-06-09 13:56:10 -07001050 };
1051
mtkleine714e752014-07-31 12:13:48 -07001052 const BenchRegistry* fBenches;
1053 const skiagm::GMRegistry* fGMs;
mtklein92007582014-08-01 07:46:52 -07001054 SkIRect fClip;
1055 SkTArray<SkScalar> fScales;
1056 SkTArray<SkString> fSKPs;
fmalita6519c212016-09-14 08:05:17 -07001057 SkTArray<SkString> fSVGs;
robertphillips5b693772014-11-21 06:19:36 -08001058 SkTArray<bool> fUseMPDs;
msarett95f192d2015-02-13 09:05:41 -08001059 SkTArray<SkString> fImages;
msarett74deb982015-10-20 16:45:56 -07001060 SkTArray<SkColorType, true> fColorTypes;
cdalton63a82852015-06-29 14:06:10 -07001061 SkScalar fZoomMax;
1062 double fZoomPeriodMs;
mtklein92007582014-08-01 07:46:52 -07001063
Mike Klein88d90712018-01-27 17:30:04 +00001064 double fSKPBytes, fSKPOps;
mtklein051e56d2014-12-04 08:46:51 -08001065
mtkleinfd731ce2014-09-10 12:19:30 -07001066 const char* fSourceType; // What we're benching: bench, GM, SKP, ...
1067 const char* fBenchType; // How we bench it: micro, recording, playback, ...
1068 int fCurrentRecording;
Mike Reede45ff462017-12-06 10:47:03 -05001069 int fCurrentDeserialPicture;
mtklein92007582014-08-01 07:46:52 -07001070 int fCurrentScale;
1071 int fCurrentSKP;
fmalita6519c212016-09-14 08:05:17 -07001072 int fCurrentSVG;
robertphillips5b693772014-11-21 06:19:36 -08001073 int fCurrentUseMPD;
scroggo60869a42015-04-01 12:09:17 -07001074 int fCurrentCodec;
msarett84451022016-02-11 06:45:51 -08001075 int fCurrentAndroidCodec;
msarett7f691442015-09-22 11:56:16 -07001076 int fCurrentBRDImage;
msarett95f192d2015-02-13 09:05:41 -08001077 int fCurrentColorType;
msarettc7796b92016-01-07 14:20:20 -08001078 int fCurrentAlphaType;
msarettb23e6aa2015-06-09 13:56:10 -07001079 int fCurrentSubsetType;
msarett84451022016-02-11 06:45:51 -08001080 int fCurrentSampleSize;
joshualitt261c3ad2015-04-27 09:16:57 -07001081 int fCurrentAnimSKP;
mtkleine714e752014-07-31 12:13:48 -07001082};
1083
msarettc149f0e2016-01-04 11:35:43 -08001084// Some runs (mostly, Valgrind) are so slow that the bot framework thinks we've hung.
1085// This prints something every once in a while so that it knows we're still working.
1086static void start_keepalive() {
Mike Klein03141d22017-10-30 11:57:15 -04001087 static std::thread* intentionallyLeaked = new std::thread([]{
1088 for (;;) {
1089 static const int kSec = 1200;
1090 #if defined(SK_BUILD_FOR_WIN)
1091 Sleep(kSec * 1000);
1092 #else
1093 sleep(kSec);
1094 #endif
1095 SkDebugf("\nBenchmarks still running...\n");
msarettc149f0e2016-01-04 11:35:43 -08001096 }
Mike Klein03141d22017-10-30 11:57:15 -04001097 });
1098 (void)intentionallyLeaked;
msarettc149f0e2016-01-04 11:35:43 -08001099}
1100
Mike Kleinbe28ee22017-02-06 12:46:20 -05001101int main(int argc, char** argv) {
1102 SkCommandLineFlags::Parse(argc, argv);
Brian Osman53136aa2017-07-20 15:43:35 -04001103
Brian Osmanbc8150f2017-07-24 11:38:01 -04001104 initializeEventTracingForTools();
Brian Osman53136aa2017-07-20 15:43:35 -04001105
Mike Kleinadacaef2017-02-06 09:26:14 -05001106#if defined(SK_BUILD_FOR_IOS)
1107 cd_Documents();
1108#endif
jcgregorio3b27ade2014-11-13 08:06:40 -08001109 SetupCrashHandler();
mtkleinf3723212014-06-25 14:08:00 -07001110 SkAutoGraphics ag;
mtkleincc29d262015-07-09 10:04:56 -07001111 SkTaskGroup::Enabler enabled(FLAGS_threads);
mtkleinf3723212014-06-25 14:08:00 -07001112
Chris Dalton040238b2017-12-18 14:22:34 -07001113 SetCtxOptionsFromCommonFlags(&grContextOpts);
krajcevski69a55602014-08-13 10:46:31 -07001114
bsalomon06cddec2014-10-24 10:40:50 -07001115 if (FLAGS_veryVerbose) {
1116 FLAGS_verbose = true;
1117 }
1118
bsalomon6eb03cc2014-08-07 14:28:50 -07001119 if (kAutoTuneLoops != FLAGS_loops) {
mtkleina189ccd2014-07-14 12:28:47 -07001120 FLAGS_samples = 1;
1121 FLAGS_gpuFrameLag = 0;
1122 }
1123
bsalomon6eb03cc2014-08-07 14:28:50 -07001124 if (!FLAGS_writePath.isEmpty()) {
1125 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]);
1126 if (!sk_mkdir(FLAGS_writePath[0])) {
1127 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_writePath[0]);
halcanary96fcdcc2015-08-27 07:41:13 -07001128 FLAGS_writePath.set(0, nullptr);
bsalomon6eb03cc2014-08-07 14:28:50 -07001129 }
1130 }
1131
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001132 std::unique_ptr<SkWStream> logStream(new SkNullWStream);
mtklein60317d0f2014-07-14 11:30:37 -07001133 if (!FLAGS_outResultsFile.isEmpty()) {
mtklein53520152016-01-20 09:53:59 -08001134#if defined(SK_RELEASE)
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001135 logStream.reset(new SkFILEWStream(FLAGS_outResultsFile[0]));
mtklein53520152016-01-20 09:53:59 -08001136#else
1137 SkDebugf("I'm ignoring --outResultsFile because this is a Debug build.");
1138 return 1;
1139#endif
mtklein60317d0f2014-07-14 11:30:37 -07001140 }
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001141 NanoJSONResultsWriter log(logStream.get(), SkJSONWriter::Mode::kPretty);
1142 log.beginObject(); // root
mtklein1915b622014-08-20 11:45:00 -07001143
1144 if (1 == FLAGS_properties.count() % 2) {
1145 SkDebugf("ERROR: --properties must be passed with an even number of arguments.\n");
1146 return 1;
1147 }
1148 for (int i = 1; i < FLAGS_properties.count(); i += 2) {
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001149 log.appendString(FLAGS_properties[i-1], FLAGS_properties[i]);
mtklein1915b622014-08-20 11:45:00 -07001150 }
jcgregoriobf5e5232014-07-17 13:14:16 -07001151
1152 if (1 == FLAGS_key.count() % 2) {
1153 SkDebugf("ERROR: --key must be passed with an even number of arguments.\n");
1154 return 1;
1155 }
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001156 if (FLAGS_key.count()) {
1157 log.beginObject("key");
1158 for (int i = 1; i < FLAGS_key.count(); i += 2) {
1159 log.appendString(FLAGS_key[i - 1], FLAGS_key[i]);
1160 }
1161 log.endObject(); // key
mtklein94e51562014-08-19 12:41:53 -07001162 }
mtklein60317d0f2014-07-14 11:30:37 -07001163
mtkleinf3723212014-06-25 14:08:00 -07001164 const double overhead = estimate_timer_overhead();
mtklein55b0ffc2014-07-17 08:38:23 -07001165 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
Mike Klein91294772014-07-16 19:59:32 -04001166
cdaltone1b89582015-06-25 19:17:08 -07001167 SkTArray<double> samples;
mtkleinbb6a0282014-07-01 08:43:42 -07001168
bsalomon6eb03cc2014-08-07 14:28:50 -07001169 if (kAutoTuneLoops != FLAGS_loops) {
1170 SkDebugf("Fixed number of loops; times would only be misleading so we won't print them.\n");
mtkleinf3723212014-06-25 14:08:00 -07001171 } else if (FLAGS_quiet) {
mtklein66cfcff2015-12-04 06:35:30 -08001172 SkDebugf("! -> high variance, ? -> moderate variance\n");
1173 SkDebugf(" micros \tbench\n");
mtkleinbbba1682015-10-28 11:36:30 -07001174 } else if (FLAGS_ms) {
cdaltone1b89582015-06-25 19:17:08 -07001175 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\n");
mtkleinf3723212014-06-25 14:08:00 -07001176 } else {
mtkleind75c4662015-04-30 07:11:22 -07001177 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n",
qiankun.miao8247ec32014-09-09 19:24:36 -07001178 FLAGS_samples, "samples");
mtkleinf3723212014-06-25 14:08:00 -07001179 }
1180
svaisanenc47635e2016-01-28 06:05:43 -08001181 SkTArray<Config> configs;
bsalomonc2553372014-07-22 13:09:05 -07001182 create_configs(&configs);
1183
msarettc149f0e2016-01-04 11:35:43 -08001184 if (FLAGS_keepAlive) {
1185 start_keepalive();
1186 }
1187
Yuqian Liba62b4a2016-12-14 13:46:53 -05001188 gSkUseAnalyticAA = FLAGS_analyticAA;
Yuqian Lidf60e362017-07-25 11:26:31 -04001189 gSkUseDeltaAA = FLAGS_deltaAA;
liyuqian38911a72016-10-04 11:23:22 -07001190
Yuqian Lidf60e362017-07-25 11:26:31 -04001191 if (FLAGS_forceDeltaAA) {
1192 gSkForceDeltaAA = true;
1193 }
Yuqian Li550148b2017-01-13 10:13:13 -05001194 if (FLAGS_forceAnalyticAA) {
1195 gSkForceAnalyticAA = true;
1196 }
Mike Reedc928fe22017-06-05 10:20:31 -04001197 if (FLAGS_forceRasterPipeline) {
1198 gSkForceRasterPipelineBlitter = true;
1199 }
Yuqian Li550148b2017-01-13 10:13:13 -05001200
mtkleine070c2b2014-10-14 08:40:43 -07001201 int runs = 0;
mtklein92007582014-08-01 07:46:52 -07001202 BenchmarkStream benchStream;
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001203 log.beginObject("results");
mtklein92007582014-08-01 07:46:52 -07001204 while (Benchmark* b = benchStream.next()) {
Ben Wagner145dbcd2016-11-03 14:40:50 -04001205 std::unique_ptr<Benchmark> bench(b);
mtklein96289052014-09-10 12:05:59 -07001206 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getUniqueName())) {
mtkleinf3723212014-06-25 14:08:00 -07001207 continue;
1208 }
1209
svaisanenc47635e2016-01-28 06:05:43 -08001210 if (!configs.empty()) {
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001211 log.beginBench(bench->getUniqueName(), bench->getSize().fX, bench->getSize().fY);
joshualitt8a6697a2015-09-30 12:11:07 -07001212 bench->delayedSetup();
jcgregoriobf5e5232014-07-17 13:14:16 -07001213 }
egdaniel3bf92062015-06-26 08:12:46 -07001214 for (int i = 0; i < configs.count(); ++i) {
1215 Target* target = is_enabled(b, configs[i]);
1216 if (!target) {
1217 continue;
1218 }
mtkleinf3723212014-06-25 14:08:00 -07001219
halcanary96fcdcc2015-08-27 07:41:13 -07001220 // During HWUI output this canvas may be nullptr.
egdaniel3bf92062015-06-26 08:12:46 -07001221 SkCanvas* canvas = target->getCanvas();
svaisanenc47635e2016-01-28 06:05:43 -08001222 const char* config = target->config.name.c_str();
egdaniel3bf92062015-06-26 08:12:46 -07001223
brianosman7a5ada82016-02-08 13:49:12 -08001224 if (FLAGS_pre_log || FLAGS_dryRun) {
benjaminwagner8d61f0d2016-01-25 13:02:40 -08001225 SkDebugf("Running %s\t%s\n"
1226 , bench->getUniqueName()
1227 , config);
brianosman7a5ada82016-02-08 13:49:12 -08001228 if (FLAGS_dryRun) {
1229 continue;
1230 }
benjaminwagner8d61f0d2016-01-25 13:02:40 -08001231 }
1232
Brian Osman5ad87aa2017-09-08 16:05:23 -04001233 TRACE_EVENT2("skia", "Benchmark", "name", TRACE_STR_COPY(bench->getUniqueName()),
1234 "config", TRACE_STR_COPY(config));
Brian Osmanc3cdef52017-08-31 14:09:22 -04001235
egdaniel3bf92062015-06-26 08:12:46 -07001236 target->setup();
robertphillips5b693772014-11-21 06:19:36 -08001237 bench->perCanvasPreDraw(canvas);
1238
cdaltone1b89582015-06-25 19:17:08 -07001239 int maxFrameLag;
mtkleina1ebeb22015-10-01 09:43:39 -07001240 int loops = target->needsFrameTiming(&maxFrameLag)
egdaniel3bf92062015-06-26 08:12:46 -07001241 ? setup_gpu_bench(target, bench.get(), maxFrameLag)
1242 : setup_cpu_bench(overhead, target, bench.get());
cdaltone1b89582015-06-25 19:17:08 -07001243
Leon Scroggins IIIb30d1132017-10-02 09:48:15 -04001244 if (kFailedLoops == loops) {
1245 // Can't be timed. A warning note has already been printed.
1246 cleanup_run(target);
1247 continue;
1248 }
1249
Yuqian Li3528eb32017-09-21 13:23:49 -04001250 if (runs == 0 && FLAGS_ms < 1000) {
1251 // Run the first bench for 1000ms to warm up the nanobench if FLAGS_ms < 1000.
1252 // Otherwise, the first few benches' measurements will be inaccurate.
1253 auto stop = now_ms() + 1000;
1254 do {
1255 time(loops, bench.get(), target);
1256 } while (now_ms() < stop);
1257 }
1258
mtkleinbbba1682015-10-28 11:36:30 -07001259 if (FLAGS_ms) {
1260 samples.reset();
1261 auto stop = now_ms() + FLAGS_ms;
1262 do {
Ben Wagner145dbcd2016-11-03 14:40:50 -04001263 samples.push_back(time(loops, bench.get(), target) / loops);
mtkleinbbba1682015-10-28 11:36:30 -07001264 } while (now_ms() < stop);
1265 } else {
cdaltone1b89582015-06-25 19:17:08 -07001266 samples.reset(FLAGS_samples);
1267 for (int s = 0; s < FLAGS_samples; s++) {
Ben Wagner145dbcd2016-11-03 14:40:50 -04001268 samples[s] = time(loops, bench.get(), target) / loops;
cdaltone1b89582015-06-25 19:17:08 -07001269 }
cdaltone1b89582015-06-25 19:17:08 -07001270 }
mtkleinf3723212014-06-25 14:08:00 -07001271
joshualitte45c81c2015-12-02 09:05:37 -08001272 SkTArray<SkString> keys;
1273 SkTArray<double> values;
1274 bool gpuStatsDump = FLAGS_gpuStatsDump && Benchmark::kGPU_Backend == configs[i].backend;
1275 if (gpuStatsDump) {
1276 // TODO cache stats
1277 bench->getGpuStats(canvas, &keys, &values);
1278 }
joshualitte45c81c2015-12-02 09:05:37 -08001279
robertphillips5b693772014-11-21 06:19:36 -08001280 bench->perCanvasPostDraw(canvas);
1281
egdaniel3bf92062015-06-26 08:12:46 -07001282 if (Benchmark::kNonRendering_Backend != target->config.backend &&
tomhudsond968a6f2015-03-26 11:28:06 -07001283 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
bsalomon6eb03cc2014-08-07 14:28:50 -07001284 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config);
mtklein96289052014-09-10 12:05:59 -07001285 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName());
bsalomon6eb03cc2014-08-07 14:28:50 -07001286 pngFilename.append(".png");
egdaniel3bf92062015-06-26 08:12:46 -07001287 write_canvas_png(target, pngFilename);
bsalomon6eb03cc2014-08-07 14:28:50 -07001288 }
1289
Mike Klein512a2442018-09-27 10:44:56 -04001290 // Building stats.plot often shows up in profiles,
1291 // so skip building it when we're not going to print it anyway.
1292 const bool want_plot = !FLAGS_quiet;
1293
1294 Stats stats(samples, want_plot);
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001295 log.beginObject(config);
1296
1297 log.beginObject("options");
1298 log.appendString("name", bench->getName());
1299 benchStream.fillCurrentOptions(log);
1300 target->fillOptions(log);
1301 log.endObject(); // options
1302
1303 // Metrics
1304 log.appendMetric("min_ms", stats.min);
1305 log.beginArray("samples");
1306 for (double sample : samples) {
1307 log.appendDoubleDigits(sample, 16);
1308 }
1309 log.endArray(); // samples
1310 benchStream.fillCurrentMetrics(log);
joshualitte45c81c2015-12-02 09:05:37 -08001311 if (gpuStatsDump) {
1312 // dump to json, only SKPBench currently returns valid keys / values
1313 SkASSERT(keys.count() == values.count());
1314 for (int i = 0; i < keys.count(); i++) {
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001315 log.appendMetric(keys[i].c_str(), values[i]);
joshualitte45c81c2015-12-02 09:05:37 -08001316 }
1317 }
joshualitte45c81c2015-12-02 09:05:37 -08001318
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001319 log.endObject(); // config
1320
mtkleine070c2b2014-10-14 08:40:43 -07001321 if (runs++ % FLAGS_flushEvery == 0) {
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001322 log.flush();
mtkleine070c2b2014-10-14 08:40:43 -07001323 }
mtklein60317d0f2014-07-14 11:30:37 -07001324
bsalomon6eb03cc2014-08-07 14:28:50 -07001325 if (kAutoTuneLoops != FLAGS_loops) {
egdaniel3bf92062015-06-26 08:12:46 -07001326 if (configs.count() == 1) {
mtkleina189ccd2014-07-14 12:28:47 -07001327 config = ""; // Only print the config if we run the same bench on more than one.
1328 }
mtkleind75c4662015-04-30 07:11:22 -07001329 SkDebugf("%4d/%-4dMB\t%s\t%s\n"
1330 , sk_tools::getCurrResidentSetSizeMB()
1331 , sk_tools::getMaxResidentSetSizeMB()
mtklein53d25622014-09-18 07:39:42 -07001332 , bench->getUniqueName()
1333 , config);
mtkleinf3723212014-06-25 14:08:00 -07001334 } else if (FLAGS_quiet) {
mtklein66cfcff2015-12-04 06:35:30 -08001335 const char* mark = " ";
Hal Canarye99e8da2019-01-14 16:34:50 -05001336 const double stddev_percent =
1337 sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean);
mtklein66cfcff2015-12-04 06:35:30 -08001338 if (stddev_percent > 5) mark = "?";
1339 if (stddev_percent > 10) mark = "!";
1340
1341 SkDebugf("%10.2f %s\t%s\t%s\n",
1342 stats.median*1e3, mark, bench->getUniqueName(), config);
Mike Reedc665e5b2017-07-04 22:56:06 -04001343 } else if (FLAGS_csv) {
Hal Canarye99e8da2019-01-14 16:34:50 -05001344 const double stddev_percent =
1345 sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean);
Mike Reedc665e5b2017-07-04 22:56:06 -04001346 SkDebugf("%g,%g,%g,%g,%g,%s,%s\n"
1347 , stats.min
1348 , stats.median
1349 , stats.mean
1350 , stats.max
1351 , stddev_percent
1352 , config
1353 , bench->getUniqueName()
1354 );
1355 } else {
1356 const char* format = "%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n";
Hal Canarye99e8da2019-01-14 16:34:50 -05001357 const double stddev_percent =
1358 sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean);
Mike Reedc665e5b2017-07-04 22:56:06 -04001359 SkDebugf(format
mtkleind75c4662015-04-30 07:11:22 -07001360 , sk_tools::getCurrResidentSetSizeMB()
1361 , sk_tools::getMaxResidentSetSizeMB()
mtkleinf3723212014-06-25 14:08:00 -07001362 , loops
mtklein55b0ffc2014-07-17 08:38:23 -07001363 , HUMANIZE(stats.min)
1364 , HUMANIZE(stats.median)
1365 , HUMANIZE(stats.mean)
1366 , HUMANIZE(stats.max)
mtkleinf3723212014-06-25 14:08:00 -07001367 , stddev_percent
mtkleinbbba1682015-10-28 11:36:30 -07001368 , FLAGS_ms ? to_string(samples.count()).c_str() : stats.plot.c_str()
mtkleinf3723212014-06-25 14:08:00 -07001369 , config
mtklein96289052014-09-10 12:05:59 -07001370 , bench->getUniqueName()
mtkleinf3723212014-06-25 14:08:00 -07001371 );
1372 }
joshualitte45c81c2015-12-02 09:05:37 -08001373
joshualitte45c81c2015-12-02 09:05:37 -08001374 if (FLAGS_gpuStats && Benchmark::kGPU_Backend == configs[i].backend) {
Brian Salomon0b4d8aa2017-10-11 15:34:27 -04001375 target->dumpStats();
bsalomon06cddec2014-10-24 10:40:50 -07001376 }
joshualitte45c81c2015-12-02 09:05:37 -08001377
cdalton2c56ba52015-06-26 13:32:53 -07001378 if (FLAGS_verbose) {
1379 SkDebugf("Samples: ");
1380 for (int i = 0; i < samples.count(); i++) {
1381 SkDebugf("%s ", HUMANIZE(samples[i]));
1382 }
1383 SkDebugf("%s\n", bench->getUniqueName());
1384 }
egdaniel3bf92062015-06-26 08:12:46 -07001385 cleanup_run(target);
mtkleinf3723212014-06-25 14:08:00 -07001386 }
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001387 if (!configs.empty()) {
1388 log.endBench();
1389 }
mtkleinf3723212014-06-25 14:08:00 -07001390 }
1391
Herb Derby5a523fe2017-01-26 16:48:28 -05001392 SkGraphics::PurgeAllCaches();
1393
Brian Osman8c0a1ca2019-01-28 14:24:29 -05001394 log.beginBench("memory_usage", 0, 0);
1395 log.beginObject("meta"); // config
1396 log.appendS32("max_rss_mb", sk_tools::getMaxResidentSetSizeMB());
1397 log.endObject(); // config
1398 log.endBench();
1399
1400 log.endObject(); // results
1401 log.endObject(); // root
1402 log.flush();
mtkleine1091452014-12-04 10:47:02 -08001403
mtkleinf3723212014-06-25 14:08:00 -07001404 return 0;
1405}