blob: dbf7124555253066fc07aa8fdc06177b0cef9dc8 [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
mtkleinf3723212014-06-25 14:08:00 -070012#include "Benchmark.h"
scroggo60869a42015-04-01 12:09:17 -070013#include "CodecBench.h"
mtkleinf3723212014-06-25 14:08:00 -070014#include "CrashHandler.h"
msarett95f192d2015-02-13 09:05:41 -080015#include "DecodingBench.h"
mtkleine714e752014-07-31 12:13:48 -070016#include "GMBench.h"
mtkleinafb43792014-08-19 15:55:55 -070017#include "ProcStats.h"
mtklein60317d0f2014-07-14 11:30:37 -070018#include "ResultsWriter.h"
mtkleinfd731ce2014-09-10 12:19:30 -070019#include "RecordingBench.h"
joshualitt261c3ad2015-04-27 09:16:57 -070020#include "SKPAnimationBench.h"
mtklein92007582014-08-01 07:46:52 -070021#include "SKPBench.h"
msarettb23e6aa2015-06-09 13:56:10 -070022#include "SubsetBenchPriv.h"
msarettb23e6aa2015-06-09 13:56:10 -070023#include "SubsetSingleBench.h"
24#include "SubsetTranslateBench.h"
25#include "SubsetZoomBench.h"
mtkleinf3723212014-06-25 14:08:00 -070026#include "Stats.h"
27#include "Timer.h"
28
mtklein6838d852014-10-29 14:15:10 -070029#include "SkBBoxHierarchy.h"
mtkleinf3723212014-06-25 14:08:00 -070030#include "SkCanvas.h"
scroggo60869a42015-04-01 12:09:17 -070031#include "SkCodec.h"
caryclark17f0b6d2014-07-22 10:15:34 -070032#include "SkCommonFlags.h"
msarett95f192d2015-02-13 09:05:41 -080033#include "SkData.h"
mtkleinf3723212014-06-25 14:08:00 -070034#include "SkForceLinking.h"
35#include "SkGraphics.h"
mtklein20840502014-08-21 15:51:22 -070036#include "SkOSFile.h"
37#include "SkPictureRecorder.h"
mtklein051e56d2014-12-04 08:46:51 -080038#include "SkPictureUtils.h"
scroggo9b2cdbf2015-07-10 12:07:02 -070039#include "SkScanlineDecoder.h"
mtkleinf3723212014-06-25 14:08:00 -070040#include "SkString.h"
41#include "SkSurface.h"
robertphillips5b693772014-11-21 06:19:36 -080042#include "SkTaskGroup.h"
mtkleinf3723212014-06-25 14:08:00 -070043
tomhudsond968a6f2015-03-26 11:28:06 -070044#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
45 #include "nanobenchAndroid.h"
46#endif
47
mtkleinbb6a0282014-07-01 08:43:42 -070048#if SK_SUPPORT_GPU
jcgregoriobf5e5232014-07-17 13:14:16 -070049 #include "gl/GrGLDefines.h"
bsalomon76228632015-05-29 08:02:10 -070050 #include "GrCaps.h"
mtkleinbb6a0282014-07-01 08:43:42 -070051 #include "GrContextFactory.h"
krajcevski69a55602014-08-13 10:46:31 -070052 SkAutoTDelete<GrContextFactory> gGrFactory;
mtkleinbb6a0282014-07-01 08:43:42 -070053#endif
54
bsalomon682c2692015-05-22 14:01:46 -070055 struct GrContextOptions;
56
mtkleinf3723212014-06-25 14:08:00 -070057__SK_FORCE_IMAGE_DECODER_LINKING;
58
cdaltone1b89582015-06-25 19:17:08 -070059static const int kTimedSampling = 0;
60
reed53249782014-10-10 09:09:52 -070061static const int kAutoTuneLoops = 0;
bsalomon6eb03cc2014-08-07 14:28:50 -070062
mtkleinb5110422014-08-07 15:20:02 -070063static const int kDefaultLoops =
bsalomon6eb03cc2014-08-07 14:28:50 -070064#ifdef SK_DEBUG
65 1;
mtkleina189ccd2014-07-14 12:28:47 -070066#else
bsalomon6eb03cc2014-08-07 14:28:50 -070067 kAutoTuneLoops;
mtkleina189ccd2014-07-14 12:28:47 -070068#endif
69
bsalomon6eb03cc2014-08-07 14:28:50 -070070static SkString loops_help_txt() {
71 SkString help;
72 help.printf("Number of times to run each bench. Set this to %d to auto-"
73 "tune for each bench. Timings are only reported when auto-tuning.",
74 kAutoTuneLoops);
75 return help;
76}
77
cdaltone1b89582015-06-25 19:17:08 -070078static SkString to_string(int n) {
79 SkString str;
80 str.appendS32(n);
81 return str;
82}
83
bsalomon6eb03cc2014-08-07 14:28:50 -070084DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str());
85
mtkleinf3723212014-06-25 14:08:00 -070086DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
cdaltone1b89582015-06-25 19:17:08 -070087DEFINE_string(samplingTime, "0", "Amount of time to run each bench. Takes precedence over samples."
88 "Must be \"0\", \"%%lfs\", or \"%%lfms\"");
mtkleinf3723212014-06-25 14:08:00 -070089DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
90DEFINE_double(overheadGoal, 0.0001,
91 "Loop until timer overhead is at most this fraction of our measurments.");
mtkleinbb6a0282014-07-01 08:43:42 -070092DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
cdaltond416a5b2015-06-23 13:23:44 -070093DEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag.");
krajcevski12b35442014-08-13 12:06:26 -070094DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to "
95 "software path rendering.");
mtkleinf3723212014-06-25 14:08:00 -070096
mtklein60317d0f2014-07-14 11:30:37 -070097DEFINE_string(outResultsFile, "", "If given, write results here as JSON.");
mtklein55b0ffc2014-07-17 08:38:23 -070098DEFINE_int32(maxCalibrationAttempts, 3,
99 "Try up to this many times to guess loops for a bench, or skip the bench.");
100DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this.");
mtklein92007582014-08-01 07:46:52 -0700101DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs.");
102DEFINE_string(scales, "1.0", "Space-separated scales for SKPs.");
cdalton63a82852015-06-29 14:06:10 -0700103DEFINE_string(zoom, "1.0,0", "Comma-separated zoomMax,zoomPeriodMs factors for a periodic SKP zoom "
104 "function that ping-pongs between 1.0 and zoomMax.");
mtklein20840502014-08-21 15:51:22 -0700105DEFINE_bool(bbh, true, "Build a BBH for SKPs?");
robertphillips5b693772014-11-21 06:19:36 -0800106DEFINE_bool(mpd, true, "Use MultiPictureDraw for the SKPs?");
cdaltonb4022962015-06-25 10:51:56 -0700107DEFINE_bool(loopSKP, true, "Loop SKPs like we do for micro benches?");
mtkleine070c2b2014-10-14 08:40:43 -0700108DEFINE_int32(flushEvery, 10, "Flush --outResultsFile every Nth run.");
mtklein55e88b22015-01-21 15:50:13 -0800109DEFINE_bool(resetGpuContext, true, "Reset the GrContext before running each test.");
bsalomonb12ea412015-02-02 21:19:50 -0800110DEFINE_bool(gpuStats, false, "Print GPU stats after each gpu benchmark?");
mtklein92007582014-08-01 07:46:52 -0700111
mtkleinf3723212014-06-25 14:08:00 -0700112static SkString humanize(double ms) {
mtkleindc5bbab2014-09-24 06:34:09 -0700113 if (FLAGS_verbose) return SkStringPrintf("%llu", (uint64_t)(ms*1e6));
mtklein748ca3b2015-01-15 10:56:12 -0800114 return HumanizeMs(ms);
mtkleinf3723212014-06-25 14:08:00 -0700115}
mtklein55b0ffc2014-07-17 08:38:23 -0700116#define HUMANIZE(ms) humanize(ms).c_str()
mtkleinf3723212014-06-25 14:08:00 -0700117
tomhudsond968a6f2015-03-26 11:28:06 -0700118bool Target::init(SkImageInfo info, Benchmark* bench) {
119 if (Benchmark::kRaster_Backend == config.backend) {
120 this->surface.reset(SkSurface::NewRaster(info));
121 if (!this->surface.get()) {
122 return false;
123 }
124 }
125 return true;
126}
127bool Target::capturePixels(SkBitmap* bmp) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700128 SkCanvas* canvas = this->getCanvas();
tomhudsond968a6f2015-03-26 11:28:06 -0700129 if (!canvas) {
130 return false;
131 }
132 bmp->setInfo(canvas->imageInfo());
133 if (!canvas->readPixels(bmp, 0, 0)) {
134 SkDebugf("Can't read canvas pixels.\n");
135 return false;
136 }
137 return true;
138}
139
140#if SK_SUPPORT_GPU
141struct GPUTarget : public Target {
142 explicit GPUTarget(const Config& c) : Target(c), gl(NULL) { }
143 SkGLContext* gl;
144
145 void setup() override {
146 this->gl->makeCurrent();
147 // Make sure we're done with whatever came before.
148 SK_GL(*this->gl, Finish());
149 }
150 void endTiming() override {
151 if (this->gl) {
152 SK_GL(*this->gl, Flush());
153 this->gl->swapBuffers();
154 }
155 }
156 void fence() override {
157 SK_GL(*this->gl, Finish());
158 }
mtkleind75c4662015-04-30 07:11:22 -0700159
cdaltond416a5b2015-06-23 13:23:44 -0700160 bool needsFrameTiming(int* maxFrameLag) const override {
161 if (!this->gl->getMaxGpuFrameLag(maxFrameLag)) {
162 // Frame lag is unknown.
163 *maxFrameLag = FLAGS_gpuFrameLag;
164 }
165 return true;
166 }
tomhudsond968a6f2015-03-26 11:28:06 -0700167 bool init(SkImageInfo info, Benchmark* bench) override {
168 uint32_t flags = this->config.useDFText ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
169 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
170 this->surface.reset(SkSurface::NewRenderTarget(gGrFactory->get(this->config.ctxType),
171 SkSurface::kNo_Budgeted, info,
172 this->config.samples, &props));
173 this->gl = gGrFactory->getGLContext(this->config.ctxType);
174 if (!this->surface.get()) {
175 return false;
176 }
cdaltond416a5b2015-06-23 13:23:44 -0700177 if (!this->gl->fenceSyncSupport()) {
178 SkDebugf("WARNING: GL context for config \"%s\" does not support fence sync. "
179 "Timings might not be accurate.\n", this->config.name);
180 }
tomhudsond968a6f2015-03-26 11:28:06 -0700181 return true;
182 }
183 void fillOptions(ResultsWriter* log) override {
184 const GrGLubyte* version;
185 SK_GL_RET(*this->gl, version, GetString(GR_GL_VERSION));
186 log->configOption("GL_VERSION", (const char*)(version));
187
188 SK_GL_RET(*this->gl, version, GetString(GR_GL_RENDERER));
189 log->configOption("GL_RENDERER", (const char*) version);
190
191 SK_GL_RET(*this->gl, version, GetString(GR_GL_VENDOR));
192 log->configOption("GL_VENDOR", (const char*) version);
193
194 SK_GL_RET(*this->gl, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
195 log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
196 }
197};
mtkleind75c4662015-04-30 07:11:22 -0700198
tomhudsond968a6f2015-03-26 11:28:06 -0700199#endif
200
tomhudson75a0ebb2015-03-27 12:11:44 -0700201static double time(int loops, Benchmark* bench, Target* target) {
202 SkCanvas* canvas = target->getCanvas();
bsalomon6eb03cc2014-08-07 14:28:50 -0700203 if (canvas) {
204 canvas->clear(SK_ColorWHITE);
205 }
mtkleinbb6a0282014-07-01 08:43:42 -0700206 WallTimer timer;
207 timer.start();
tomhudson75a0ebb2015-03-27 12:11:44 -0700208 canvas = target->beginTiming(canvas);
209 bench->draw(loops, canvas);
mtkleinbb6a0282014-07-01 08:43:42 -0700210 if (canvas) {
211 canvas->flush();
212 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700213 target->endTiming();
mtkleinbb6a0282014-07-01 08:43:42 -0700214 timer.end();
215 return timer.fWall;
216}
217
mtkleinf3723212014-06-25 14:08:00 -0700218static double estimate_timer_overhead() {
219 double overhead = 0;
mtkleinf3723212014-06-25 14:08:00 -0700220 for (int i = 0; i < FLAGS_overheadLoops; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700221 WallTimer timer;
222 timer.start();
223 timer.end();
224 overhead += timer.fWall;
mtkleinf3723212014-06-25 14:08:00 -0700225 }
226 return overhead / FLAGS_overheadLoops;
227}
228
reed53249782014-10-10 09:09:52 -0700229static int detect_forever_loops(int loops) {
230 // look for a magic run-forever value
231 if (loops < 0) {
232 loops = SK_MaxS32;
233 }
234 return loops;
235}
236
mtklein55b0ffc2014-07-17 08:38:23 -0700237static int clamp_loops(int loops) {
238 if (loops < 1) {
mtklein527930f2014-11-06 08:04:34 -0800239 SkDebugf("ERROR: clamping loops from %d to 1. "
240 "There's probably something wrong with the bench.\n", loops);
mtklein55b0ffc2014-07-17 08:38:23 -0700241 return 1;
242 }
243 if (loops > FLAGS_maxLoops) {
244 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops);
245 return FLAGS_maxLoops;
246 }
247 return loops;
248}
249
tomhudsond968a6f2015-03-26 11:28:06 -0700250static bool write_canvas_png(Target* target, const SkString& filename) {
251
bsalomon6eb03cc2014-08-07 14:28:50 -0700252 if (filename.isEmpty()) {
253 return false;
254 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700255 if (target->getCanvas() &&
256 kUnknown_SkColorType == target->getCanvas()->imageInfo().colorType()) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700257 return false;
258 }
tomhudsond968a6f2015-03-26 11:28:06 -0700259
bsalomon6eb03cc2014-08-07 14:28:50 -0700260 SkBitmap bmp;
tomhudsond968a6f2015-03-26 11:28:06 -0700261
262 if (!target->capturePixels(&bmp)) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700263 return false;
264 }
tomhudsond968a6f2015-03-26 11:28:06 -0700265
bsalomon6eb03cc2014-08-07 14:28:50 -0700266 SkString dir = SkOSPath::Dirname(filename.c_str());
267 if (!sk_mkdir(dir.c_str())) {
268 SkDebugf("Can't make dir %s.\n", dir.c_str());
269 return false;
270 }
271 SkFILEWStream stream(filename.c_str());
272 if (!stream.isValid()) {
273 SkDebugf("Can't write %s.\n", filename.c_str());
274 return false;
275 }
276 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 100)) {
277 SkDebugf("Can't encode a PNG.\n");
278 return false;
279 }
280 return true;
281}
282
283static int kFailedLoops = -2;
cdaltone1b89582015-06-25 19:17:08 -0700284static int setup_cpu_bench(const double overhead, Target* target, Benchmark* bench) {
mtkleinbb6a0282014-07-01 08:43:42 -0700285 // First figure out approximately how many loops of bench it takes to make overhead negligible.
mtklein2069e222014-08-04 13:57:39 -0700286 double bench_plus_overhead = 0.0;
mtklein55b0ffc2014-07-17 08:38:23 -0700287 int round = 0;
cdaltonb4022962015-06-25 10:51:56 -0700288 int loops = bench->calculateLoops(FLAGS_loops);
289 if (kAutoTuneLoops == loops) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700290 while (bench_plus_overhead < overhead) {
291 if (round++ == FLAGS_maxCalibrationAttempts) {
292 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
mtklein96289052014-09-10 12:05:59 -0700293 bench->getUniqueName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
bsalomon6eb03cc2014-08-07 14:28:50 -0700294 return kFailedLoops;
295 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700296 bench_plus_overhead = time(1, bench, target);
mtklein55b0ffc2014-07-17 08:38:23 -0700297 }
mtklein2069e222014-08-04 13:57:39 -0700298 }
mtkleinf3723212014-06-25 14:08:00 -0700299
mtkleinbb6a0282014-07-01 08:43:42 -0700300 // Later we'll just start and stop the timer once but loop N times.
mtkleinf3723212014-06-25 14:08:00 -0700301 // We'll pick N to make timer overhead negligible:
302 //
mtkleinbb6a0282014-07-01 08:43:42 -0700303 // overhead
304 // ------------------------- < FLAGS_overheadGoal
305 // overhead + N * Bench Time
mtkleinf3723212014-06-25 14:08:00 -0700306 //
mtkleinbb6a0282014-07-01 08:43:42 -0700307 // where bench_plus_overhead ≈ overhead + Bench Time.
mtkleinf3723212014-06-25 14:08:00 -0700308 //
309 // Doing some math, we get:
310 //
mtkleinbb6a0282014-07-01 08:43:42 -0700311 // (overhead / FLAGS_overheadGoal) - overhead
312 // ------------------------------------------ < N
313 // bench_plus_overhead - overhead)
mtkleinf3723212014-06-25 14:08:00 -0700314 //
315 // Luckily, this also works well in practice. :)
bsalomon6eb03cc2014-08-07 14:28:50 -0700316 if (kAutoTuneLoops == loops) {
317 const double numer = overhead / FLAGS_overheadGoal - overhead;
318 const double denom = bench_plus_overhead - overhead;
319 loops = (int)ceil(numer / denom);
reed53249782014-10-10 09:09:52 -0700320 loops = clamp_loops(loops);
321 } else {
322 loops = detect_forever_loops(loops);
bsalomon6eb03cc2014-08-07 14:28:50 -0700323 }
mtkleinbb6a0282014-07-01 08:43:42 -0700324
mtkleinbb6a0282014-07-01 08:43:42 -0700325 return loops;
mtkleinf3723212014-06-25 14:08:00 -0700326}
327
cdaltone1b89582015-06-25 19:17:08 -0700328static int setup_gpu_bench(Target* target, Benchmark* bench, int maxGpuFrameLag) {
mtkleinbb6a0282014-07-01 08:43:42 -0700329 // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
cdaltonb4022962015-06-25 10:51:56 -0700330 int loops = bench->calculateLoops(FLAGS_loops);
bsalomon6eb03cc2014-08-07 14:28:50 -0700331 if (kAutoTuneLoops == loops) {
332 loops = 1;
mtkleina189ccd2014-07-14 12:28:47 -0700333 double elapsed = 0;
334 do {
mtklein527930f2014-11-06 08:04:34 -0800335 if (1<<30 == loops) {
336 // We're about to wrap. Something's wrong with the bench.
337 loops = 0;
338 break;
339 }
mtkleina189ccd2014-07-14 12:28:47 -0700340 loops *= 2;
341 // If the GPU lets frames lag at all, we need to make sure we're timing
cdaltond416a5b2015-06-23 13:23:44 -0700342 // _this_ round, not still timing last round.
343 for (int i = 0; i < maxGpuFrameLag; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700344 elapsed = time(loops, bench, target);
mtkleina189ccd2014-07-14 12:28:47 -0700345 }
346 } while (elapsed < FLAGS_gpuMs);
mtkleinbb6a0282014-07-01 08:43:42 -0700347
mtkleina189ccd2014-07-14 12:28:47 -0700348 // We've overshot at least a little. Scale back linearly.
349 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed);
reed53249782014-10-10 09:09:52 -0700350 loops = clamp_loops(loops);
mtkleinbb6a0282014-07-01 08:43:42 -0700351
tomhudsond968a6f2015-03-26 11:28:06 -0700352 // Make sure we're not still timing our calibration.
353 target->fence();
reed53249782014-10-10 09:09:52 -0700354 } else {
355 loops = detect_forever_loops(loops);
mtkleina189ccd2014-07-14 12:28:47 -0700356 }
mtkleinbb6a0282014-07-01 08:43:42 -0700357
358 // Pretty much the same deal as the calibration: do some warmup to make
359 // sure we're timing steady-state pipelined frames.
cdaltond416a5b2015-06-23 13:23:44 -0700360 for (int i = 0; i < maxGpuFrameLag - 1; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700361 time(loops, bench, target);
mtkleinf3723212014-06-25 14:08:00 -0700362 }
mtkleinbb6a0282014-07-01 08:43:42 -0700363
mtkleinbb6a0282014-07-01 08:43:42 -0700364 return loops;
365}
mtkleinbb6a0282014-07-01 08:43:42 -0700366
367static SkString to_lower(const char* str) {
368 SkString lower(str);
369 for (size_t i = 0; i < lower.size(); i++) {
370 lower[i] = tolower(lower[i]);
371 }
372 return lower;
mtkleinf3723212014-06-25 14:08:00 -0700373}
374
bsalomonc2553372014-07-22 13:09:05 -0700375static bool is_cpu_config_allowed(const char* name) {
mtkleinbb6a0282014-07-01 08:43:42 -0700376 for (int i = 0; i < FLAGS_config.count(); i++) {
bsalomonc2553372014-07-22 13:09:05 -0700377 if (to_lower(FLAGS_config[i]).equals(name)) {
378 return true;
mtkleinf3723212014-06-25 14:08:00 -0700379 }
380 }
bsalomonc2553372014-07-22 13:09:05 -0700381 return false;
mtkleinbb6a0282014-07-01 08:43:42 -0700382}
383
bsalomonc2553372014-07-22 13:09:05 -0700384#if SK_SUPPORT_GPU
385static bool is_gpu_config_allowed(const char* name, GrContextFactory::GLContextType ctxType,
386 int sampleCnt) {
387 if (!is_cpu_config_allowed(name)) {
388 return false;
389 }
krajcevski69a55602014-08-13 10:46:31 -0700390 if (const GrContext* ctx = gGrFactory->get(ctxType)) {
bsalomon76228632015-05-29 08:02:10 -0700391 return sampleCnt <= ctx->caps()->maxSampleCount();
bsalomonc2553372014-07-22 13:09:05 -0700392 }
393 return false;
394}
395#endif
mtkleinbb6a0282014-07-01 08:43:42 -0700396
bsalomonc2553372014-07-22 13:09:05 -0700397#if SK_SUPPORT_GPU
398#define kBogusGLContextType GrContextFactory::kNative_GLContextType
399#else
400#define kBogusGLContextType 0
mtkleine714e752014-07-31 12:13:48 -0700401#endif
bsalomonc2553372014-07-22 13:09:05 -0700402
403// Append all configs that are enabled and supported.
404static void create_configs(SkTDArray<Config>* configs) {
jvanverth4736e142014-11-07 07:12:46 -0800405 #define CPU_CONFIG(name, backend, color, alpha) \
406 if (is_cpu_config_allowed(#name)) { \
407 Config config = { #name, Benchmark::backend, color, alpha, 0, \
408 kBogusGLContextType, false }; \
409 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700410 }
mtkleine714e752014-07-31 12:13:48 -0700411
mtklein40b32be2014-07-09 08:46:49 -0700412 if (FLAGS_cpu) {
bsalomonc2553372014-07-22 13:09:05 -0700413 CPU_CONFIG(nonrendering, kNonRendering_Backend, kUnknown_SkColorType, kUnpremul_SkAlphaType)
414 CPU_CONFIG(8888, kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType)
415 CPU_CONFIG(565, kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType)
mtklein40b32be2014-07-09 08:46:49 -0700416 }
mtkleinbb6a0282014-07-01 08:43:42 -0700417
418#if SK_SUPPORT_GPU
jvanverth4736e142014-11-07 07:12:46 -0800419 #define GPU_CONFIG(name, ctxType, samples, useDFText) \
bsalomonc2553372014-07-22 13:09:05 -0700420 if (is_gpu_config_allowed(#name, GrContextFactory::ctxType, samples)) { \
421 Config config = { \
422 #name, \
423 Benchmark::kGPU_Backend, \
424 kN32_SkColorType, \
425 kPremul_SkAlphaType, \
426 samples, \
jvanverth4736e142014-11-07 07:12:46 -0800427 GrContextFactory::ctxType, \
428 useDFText }; \
bsalomonc2553372014-07-22 13:09:05 -0700429 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700430 }
mtkleine714e752014-07-31 12:13:48 -0700431
mtklein40b32be2014-07-09 08:46:49 -0700432 if (FLAGS_gpu) {
jvanverth4736e142014-11-07 07:12:46 -0800433 GPU_CONFIG(gpu, kNative_GLContextType, 0, false)
434 GPU_CONFIG(msaa4, kNative_GLContextType, 4, false)
435 GPU_CONFIG(msaa16, kNative_GLContextType, 16, false)
436 GPU_CONFIG(nvprmsaa4, kNVPR_GLContextType, 4, false)
437 GPU_CONFIG(nvprmsaa16, kNVPR_GLContextType, 16, false)
438 GPU_CONFIG(gpudft, kNative_GLContextType, 0, true)
439 GPU_CONFIG(debug, kDebug_GLContextType, 0, false)
440 GPU_CONFIG(nullgpu, kNull_GLContextType, 0, false)
bsalomon3b4d0772014-08-06 10:52:33 -0700441#ifdef SK_ANGLE
jvanverth4736e142014-11-07 07:12:46 -0800442 GPU_CONFIG(angle, kANGLE_GLContextType, 0, false)
bsalomon3b4d0772014-08-06 10:52:33 -0700443#endif
cdaltond416a5b2015-06-23 13:23:44 -0700444#if SK_MESA
445 GPU_CONFIG(mesa, kMESA_GLContextType, 0, false)
446#endif
mtklein40b32be2014-07-09 08:46:49 -0700447 }
mtkleinbb6a0282014-07-01 08:43:42 -0700448#endif
tomhudsond968a6f2015-03-26 11:28:06 -0700449
450#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
451 if (is_cpu_config_allowed("hwui")) {
452 Config config = { "hwui", Benchmark::kHWUI_Backend, kRGBA_8888_SkColorType,
453 kPremul_SkAlphaType, 0, kBogusGLContextType, false };
454 configs->push(config);
455 }
456#endif
mtkleinf3723212014-06-25 14:08:00 -0700457}
458
bsalomonc2553372014-07-22 13:09:05 -0700459// If bench is enabled for config, returns a Target* for it, otherwise NULL.
460static Target* is_enabled(Benchmark* bench, const Config& config) {
461 if (!bench->isSuitableFor(config.backend)) {
462 return NULL;
463 }
464
reede5ea5002014-09-03 11:54:58 -0700465 SkImageInfo info = SkImageInfo::Make(bench->getSize().fX, bench->getSize().fY,
466 config.color, config.alpha);
bsalomonc2553372014-07-22 13:09:05 -0700467
tomhudsond968a6f2015-03-26 11:28:06 -0700468 Target* target = NULL;
bsalomonc2553372014-07-22 13:09:05 -0700469
tomhudsond968a6f2015-03-26 11:28:06 -0700470 switch (config.backend) {
bsalomonc2553372014-07-22 13:09:05 -0700471#if SK_SUPPORT_GPU
tomhudsond968a6f2015-03-26 11:28:06 -0700472 case Benchmark::kGPU_Backend:
473 target = new GPUTarget(config);
474 break;
bsalomonc2553372014-07-22 13:09:05 -0700475#endif
tomhudsond968a6f2015-03-26 11:28:06 -0700476#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
477 case Benchmark::kHWUI_Backend:
478 target = new HWUITarget(config, bench);
479 break;
480#endif
481 default:
482 target = new Target(config);
483 break;
484 }
bsalomonc2553372014-07-22 13:09:05 -0700485
tomhudsond968a6f2015-03-26 11:28:06 -0700486 if (!target->init(info, bench)) {
bsalomonc2553372014-07-22 13:09:05 -0700487 delete target;
488 return NULL;
489 }
490 return target;
491}
492
msarettb23e6aa2015-06-09 13:56:10 -0700493/*
494 * Returns true if set up for a subset decode succeeds, false otherwise
495 * If the set-up succeeds, the width and height parameters will be set
496 */
497static bool valid_subset_bench(const SkString& path, SkColorType colorType, bool useCodec,
498 int* width, int* height) {
499 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
500 SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(encoded));
501
msarettab80e352015-06-17 10:28:22 -0700502 // Check that we can create a codec or image decoder.
msarettb23e6aa2015-06-09 13:56:10 -0700503 if (useCodec) {
504 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach()));
505 if (NULL == codec) {
506 SkDebugf("Could not create codec for %s. Skipping bench.\n", path.c_str());
507 return false;
508 }
509
510 // These will be initialized by SkCodec if the color type is kIndex8 and
511 // unused otherwise.
512 SkPMColor colors[256];
513 int colorCount;
514 const SkImageInfo info = codec->getInfo().makeColorType(colorType);
515 SkAutoTDeleteArray<uint8_t> row(SkNEW_ARRAY(uint8_t, info.minRowBytes()));
scroggo9b2cdbf2015-07-10 12:07:02 -0700516 SkAutoTDelete<SkScanlineDecoder> scanlineDecoder(codec->getScanlineDecoder(info, NULL,
517 colors, &colorCount));
msarettb23e6aa2015-06-09 13:56:10 -0700518 if (NULL == scanlineDecoder) {
519 SkDebugf("Could not create scanline decoder for %s with color type %s. "
520 "Skipping bench.\n", path.c_str(), get_color_name(colorType));
521 return false;
522 }
523 *width = info.width();
524 *height = info.height();
525 } else {
526 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
527 if (NULL == decoder) {
528 SkDebugf("Could not create decoder for %s. Skipping bench.\n", path.c_str());
529 return false;
530 }
531 //FIXME: See skbug.com/3921
532 if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) {
533 SkDebugf("Cannot use image subset decoder for %s with color type %s. "
534 "Skipping bench.\n", path.c_str(), get_color_name(colorType));
535 return false;
536 }
537 if (!decoder->buildTileIndex(stream.detach(), width, height)) {
538 SkDebugf("Could not build tile index for %s. Skipping bench.\n", path.c_str());
539 return false;
540 }
541 }
msarettab80e352015-06-17 10:28:22 -0700542
543 // Check if the image is large enough for a meaningful subset benchmark.
544 if (*width <= 512 && *height <= 512) {
545 // This should not print a message since it is not an error.
546 return false;
547 }
548
msarettb23e6aa2015-06-09 13:56:10 -0700549 return true;
550}
jcgregoriobf5e5232014-07-17 13:14:16 -0700551
egdaniel3bf92062015-06-26 08:12:46 -0700552static void cleanup_run(Target* target) {
553 SkDELETE(target);
554#if SK_SUPPORT_GPU
555 if (FLAGS_abandonGpuContext) {
556 gGrFactory->abandonContexts();
557 }
558 if (FLAGS_resetGpuContext || FLAGS_abandonGpuContext) {
559 gGrFactory->destroyContexts();
560 }
561#endif
562}
563
mtkleine714e752014-07-31 12:13:48 -0700564class BenchmarkStream {
565public:
mtklein92007582014-08-01 07:46:52 -0700566 BenchmarkStream() : fBenches(BenchRegistry::Head())
567 , fGMs(skiagm::GMRegistry::Head())
mtkleinfd731ce2014-09-10 12:19:30 -0700568 , fCurrentRecording(0)
mtklein92007582014-08-01 07:46:52 -0700569 , fCurrentScale(0)
robertphillips5b693772014-11-21 06:19:36 -0800570 , fCurrentSKP(0)
msarett95f192d2015-02-13 09:05:41 -0800571 , fCurrentUseMPD(0)
scroggo60869a42015-04-01 12:09:17 -0700572 , fCurrentCodec(0)
msarett95f192d2015-02-13 09:05:41 -0800573 , fCurrentImage(0)
574 , fCurrentSubsetImage(0)
575 , fCurrentColorType(0)
msarettb23e6aa2015-06-09 13:56:10 -0700576 , fCurrentSubsetType(0)
577 , fUseCodec(0)
578 , fCurrentAnimSKP(0) {
mtklein92007582014-08-01 07:46:52 -0700579 for (int i = 0; i < FLAGS_skps.count(); i++) {
580 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
581 fSKPs.push_back() = FLAGS_skps[i];
582 } else {
583 SkOSFile::Iter it(FLAGS_skps[i], ".skp");
584 SkString path;
585 while (it.next(&path)) {
586 fSKPs.push_back() = SkOSPath::Join(FLAGS_skps[0], path.c_str());
587 }
588 }
589 }
mtkleine714e752014-07-31 12:13:48 -0700590
mtklein92007582014-08-01 07:46:52 -0700591 if (4 != sscanf(FLAGS_clip[0], "%d,%d,%d,%d",
592 &fClip.fLeft, &fClip.fTop, &fClip.fRight, &fClip.fBottom)) {
593 SkDebugf("Can't parse %s from --clip as an SkIRect.\n", FLAGS_clip[0]);
594 exit(1);
595 }
596
597 for (int i = 0; i < FLAGS_scales.count(); i++) {
598 if (1 != sscanf(FLAGS_scales[i], "%f", &fScales.push_back())) {
599 SkDebugf("Can't parse %s from --scales as an SkScalar.\n", FLAGS_scales[i]);
600 exit(1);
601 }
602 }
robertphillips5b693772014-11-21 06:19:36 -0800603
cdalton63a82852015-06-29 14:06:10 -0700604 if (2 != sscanf(FLAGS_zoom[0], "%f,%lf", &fZoomMax, &fZoomPeriodMs)) {
605 SkDebugf("Can't parse %s from --zoom as a zoomMax,zoomPeriodMs.\n", FLAGS_zoom[0]);
joshualitt261c3ad2015-04-27 09:16:57 -0700606 exit(1);
607 }
608
robertphillips5b693772014-11-21 06:19:36 -0800609 if (FLAGS_mpd) {
610 fUseMPDs.push_back() = true;
611 }
mtkleinc751ecb2015-06-15 08:56:38 -0700612 fUseMPDs.push_back() = false;
mtklein95553d92015-03-12 08:24:21 -0700613
msarett95f192d2015-02-13 09:05:41 -0800614 // Prepare the images for decoding
615 for (int i = 0; i < FLAGS_images.count(); i++) {
616 const char* flag = FLAGS_images[i];
617 if (sk_isdir(flag)) {
618 // If the value passed in is a directory, add all the images
619 SkOSFile::Iter it(flag);
620 SkString file;
621 while (it.next(&file)) {
622 fImages.push_back() = SkOSPath::Join(flag, file.c_str());
623 }
624 } else if (sk_exists(flag)) {
625 // Also add the value if it is a single image
626 fImages.push_back() = flag;
627 }
628 }
mtklein95553d92015-03-12 08:24:21 -0700629
msarett95f192d2015-02-13 09:05:41 -0800630 // Choose the candidate color types for image decoding
631 const SkColorType colorTypes[] =
msarettb23e6aa2015-06-09 13:56:10 -0700632 { kN32_SkColorType,
633 kRGB_565_SkColorType,
634 kAlpha_8_SkColorType,
635 kIndex_8_SkColorType,
636 kGray_8_SkColorType };
msarett95f192d2015-02-13 09:05:41 -0800637 fColorTypes.push_back_n(SK_ARRAY_COUNT(colorTypes), colorTypes);
mtklein92007582014-08-01 07:46:52 -0700638 }
639
mtkleinfd731ce2014-09-10 12:19:30 -0700640 static bool ReadPicture(const char* path, SkAutoTUnref<SkPicture>* pic) {
641 // Not strictly necessary, as it will be checked again later,
642 // but helps to avoid a lot of pointless work if we're going to skip it.
643 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path)) {
644 return false;
645 }
646
scroggoa1193e42015-01-21 12:09:53 -0800647 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path));
mtkleinfd731ce2014-09-10 12:19:30 -0700648 if (stream.get() == NULL) {
649 SkDebugf("Could not read %s.\n", path);
650 return false;
651 }
652
mtklein57f27bd2015-02-09 11:58:41 -0800653 pic->reset(SkPicture::CreateFromStream(stream.get()));
mtkleinfd731ce2014-09-10 12:19:30 -0700654 if (pic->get() == NULL) {
655 SkDebugf("Could not read %s as an SkPicture.\n", path);
656 return false;
657 }
658 return true;
659 }
660
mtklein92007582014-08-01 07:46:52 -0700661 Benchmark* next() {
mtkleine714e752014-07-31 12:13:48 -0700662 if (fBenches) {
663 Benchmark* bench = fBenches->factory()(NULL);
664 fBenches = fBenches->next();
mtklein92007582014-08-01 07:46:52 -0700665 fSourceType = "bench";
mtkleinfd731ce2014-09-10 12:19:30 -0700666 fBenchType = "micro";
mtkleine714e752014-07-31 12:13:48 -0700667 return bench;
668 }
mtklein92007582014-08-01 07:46:52 -0700669
mtkleine714e752014-07-31 12:13:48 -0700670 while (fGMs) {
671 SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL));
672 fGMs = fGMs->next();
mtkleincf5d9c92015-01-23 10:31:45 -0800673 if (gm->runAsBench()) {
mtklein92007582014-08-01 07:46:52 -0700674 fSourceType = "gm";
mtkleinfd731ce2014-09-10 12:19:30 -0700675 fBenchType = "micro";
mtkleine714e752014-07-31 12:13:48 -0700676 return SkNEW_ARGS(GMBench, (gm.detach()));
677 }
678 }
mtklein92007582014-08-01 07:46:52 -0700679
mtkleinfd731ce2014-09-10 12:19:30 -0700680 // First add all .skps as RecordingBenches.
681 while (fCurrentRecording < fSKPs.count()) {
682 const SkString& path = fSKPs[fCurrentRecording++];
683 SkAutoTUnref<SkPicture> pic;
684 if (!ReadPicture(path.c_str(), &pic)) {
685 continue;
686 }
687 SkString name = SkOSPath::Basename(path.c_str());
688 fSourceType = "skp";
689 fBenchType = "recording";
bsalomon0aa5cea2014-12-15 09:13:35 -0800690 fSKPBytes = static_cast<double>(SkPictureUtils::ApproximateBytesUsed(pic));
mtklein051e56d2014-12-04 08:46:51 -0800691 fSKPOps = pic->approximateOpCount();
mtkleinfd731ce2014-09-10 12:19:30 -0700692 return SkNEW_ARGS(RecordingBench, (name.c_str(), pic.get(), FLAGS_bbh));
693 }
694
695 // Then once each for each scale as SKPBenches (playback).
mtklein92007582014-08-01 07:46:52 -0700696 while (fCurrentScale < fScales.count()) {
697 while (fCurrentSKP < fSKPs.count()) {
robertphillips5b693772014-11-21 06:19:36 -0800698 const SkString& path = fSKPs[fCurrentSKP];
mtkleinfd731ce2014-09-10 12:19:30 -0700699 SkAutoTUnref<SkPicture> pic;
700 if (!ReadPicture(path.c_str(), &pic)) {
robertphillips5b693772014-11-21 06:19:36 -0800701 fCurrentSKP++;
mtklein92007582014-08-01 07:46:52 -0700702 continue;
703 }
robertphillips5b693772014-11-21 06:19:36 -0800704
705 while (fCurrentUseMPD < fUseMPDs.count()) {
706 if (FLAGS_bbh) {
707 // The SKP we read off disk doesn't have a BBH. Re-record so it grows one.
708 SkRTreeFactory factory;
709 SkPictureRecorder recorder;
710 static const int kFlags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
711 pic->playback(recorder.beginRecording(pic->cullRect().width(),
712 pic->cullRect().height(),
mtklein748ca3b2015-01-15 10:56:12 -0800713 &factory,
robertphillipse451c4d2014-12-09 10:28:00 -0800714 fUseMPDs[fCurrentUseMPD] ? kFlags : 0));
robertphillips5b693772014-11-21 06:19:36 -0800715 pic.reset(recorder.endRecording());
716 }
717 SkString name = SkOSPath::Basename(path.c_str());
718 fSourceType = "skp";
719 fBenchType = "playback";
720 return SkNEW_ARGS(SKPBench,
cdaltonb4022962015-06-25 10:51:56 -0700721 (name.c_str(), pic.get(), fClip, fScales[fCurrentScale],
722 fUseMPDs[fCurrentUseMPD++], FLAGS_loopSKP));
joshualitt261c3ad2015-04-27 09:16:57 -0700723
mtklein20840502014-08-21 15:51:22 -0700724 }
robertphillips5b693772014-11-21 06:19:36 -0800725 fCurrentUseMPD = 0;
726 fCurrentSKP++;
mtklein92007582014-08-01 07:46:52 -0700727 }
728 fCurrentSKP = 0;
729 fCurrentScale++;
730 }
731
joshualitt261c3ad2015-04-27 09:16:57 -0700732 // Now loop over each skp again if we have an animation
cdalton63a82852015-06-29 14:06:10 -0700733 if (fZoomMax != 1.0f && fZoomPeriodMs > 0) {
joshualitt261c3ad2015-04-27 09:16:57 -0700734 while (fCurrentAnimSKP < fSKPs.count()) {
735 const SkString& path = fSKPs[fCurrentAnimSKP];
736 SkAutoTUnref<SkPicture> pic;
737 if (!ReadPicture(path.c_str(), &pic)) {
738 fCurrentAnimSKP++;
739 continue;
740 }
741
742 fCurrentAnimSKP++;
743 SkString name = SkOSPath::Basename(path.c_str());
cdalton63a82852015-06-29 14:06:10 -0700744 SkAutoTUnref<SKPAnimationBench::Animation> animation(
745 SKPAnimationBench::CreateZoomAnimation(fZoomMax, fZoomPeriodMs));
746 return SkNEW_ARGS(SKPAnimationBench, (name.c_str(), pic.get(), fClip, animation,
747 FLAGS_loopSKP));
joshualitt261c3ad2015-04-27 09:16:57 -0700748 }
749 }
750
751
scroggo60869a42015-04-01 12:09:17 -0700752 for (; fCurrentCodec < fImages.count(); fCurrentCodec++) {
753 const SkString& path = fImages[fCurrentCodec];
754 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
755 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
scroggo60869a42015-04-01 12:09:17 -0700756 if (!codec) {
757 // Nothing to time.
msarett9d9725c2015-04-24 11:41:55 -0700758 SkDebugf("Cannot find codec for %s\n", path.c_str());
scroggo60869a42015-04-01 12:09:17 -0700759 continue;
760 }
scroggo21027992015-04-02 13:22:38 -0700761
scroggo60869a42015-04-01 12:09:17 -0700762 while (fCurrentColorType < fColorTypes.count()) {
scroggo21027992015-04-02 13:22:38 -0700763 const SkColorType colorType = fColorTypes[fCurrentColorType];
scroggo60869a42015-04-01 12:09:17 -0700764 fCurrentColorType++;
scroggo21027992015-04-02 13:22:38 -0700765
scroggo60869a42015-04-01 12:09:17 -0700766 // Make sure we can decode to this color type.
scroggo60869a42015-04-01 12:09:17 -0700767 SkImageInfo info = codec->getInfo().makeColorType(colorType);
scroggo21027992015-04-02 13:22:38 -0700768 SkAlphaType alphaType;
769 if (!SkColorTypeValidateAlphaType(colorType, info.alphaType(),
770 &alphaType)) {
771 continue;
772 }
773 if (alphaType != info.alphaType()) {
774 info = info.makeAlphaType(alphaType);
775 }
776
777 const size_t rowBytes = info.minRowBytes();
778 SkAutoMalloc storage(info.getSafeSize(rowBytes));
779
780 // Used if fCurrentColorType is kIndex_8_SkColorType
781 int colorCount = 256;
782 SkPMColor colors[256];
783
scroggoeb602a52015-07-09 08:16:03 -0700784 const SkCodec::Result result = codec->getPixels(
scroggo21027992015-04-02 13:22:38 -0700785 info, storage.get(), rowBytes, NULL, colors,
786 &colorCount);
scroggo60869a42015-04-01 12:09:17 -0700787 switch (result) {
scroggoeb602a52015-07-09 08:16:03 -0700788 case SkCodec::kSuccess:
789 case SkCodec::kIncompleteInput:
scroggo60869a42015-04-01 12:09:17 -0700790 return new CodecBench(SkOSPath::Basename(path.c_str()),
791 encoded, colorType);
scroggoeb602a52015-07-09 08:16:03 -0700792 case SkCodec::kInvalidConversion:
scroggo60869a42015-04-01 12:09:17 -0700793 // This is okay. Not all conversions are valid.
794 break;
scroggo60869a42015-04-01 12:09:17 -0700795 default:
796 // This represents some sort of failure.
797 SkASSERT(false);
798 break;
799 }
800 }
801 fCurrentColorType = 0;
802 }
803
msarett95f192d2015-02-13 09:05:41 -0800804 // Run the DecodingBenches
805 while (fCurrentImage < fImages.count()) {
806 while (fCurrentColorType < fColorTypes.count()) {
807 const SkString& path = fImages[fCurrentImage];
808 SkColorType colorType = fColorTypes[fCurrentColorType];
809 fCurrentColorType++;
scroggo60869a42015-04-01 12:09:17 -0700810 // Check if the image decodes to the right color type
811 // before creating the benchmark
msarett95f192d2015-02-13 09:05:41 -0800812 SkBitmap bitmap;
813 if (SkImageDecoder::DecodeFile(path.c_str(), &bitmap,
scroggo60869a42015-04-01 12:09:17 -0700814 colorType, SkImageDecoder::kDecodePixels_Mode)
815 && bitmap.colorType() == colorType) {
msarett95f192d2015-02-13 09:05:41 -0800816 return new DecodingBench(path, colorType);
817 }
818 }
819 fCurrentColorType = 0;
820 fCurrentImage++;
821 }
822
msarettb23e6aa2015-06-09 13:56:10 -0700823 // Run the SubsetBenches
824 bool useCodecOpts[] = { true, false };
825 while (fUseCodec < 2) {
826 bool useCodec = useCodecOpts[fUseCodec];
827 while (fCurrentSubsetImage < fImages.count()) {
828 while (fCurrentColorType < fColorTypes.count()) {
829 const SkString& path = fImages[fCurrentSubsetImage];
830 SkColorType colorType = fColorTypes[fCurrentColorType];
831 while (fCurrentSubsetType <= kLast_SubsetType) {
832 int width = 0;
833 int height = 0;
834 int currentSubsetType = fCurrentSubsetType++;
835 if (valid_subset_bench(path, colorType, useCodec, &width, &height)) {
836 switch (currentSubsetType) {
837 case kTopLeft_SubsetType:
msarettab80e352015-06-17 10:28:22 -0700838 return new SubsetSingleBench(path, colorType, width/3,
839 height/3, 0, 0, useCodec);
msarettb23e6aa2015-06-09 13:56:10 -0700840 case kTopRight_SubsetType:
msarettab80e352015-06-17 10:28:22 -0700841 return new SubsetSingleBench(path, colorType, width/3,
842 height/3, 2*width/3, 0, useCodec);
843 case kMiddle_SubsetType:
844 return new SubsetSingleBench(path, colorType, width/3,
845 height/3, width/3, height/3, useCodec);
msarettb23e6aa2015-06-09 13:56:10 -0700846 case kBottomLeft_SubsetType:
msarettab80e352015-06-17 10:28:22 -0700847 return new SubsetSingleBench(path, colorType, width/3,
848 height/3, 0, 2*height/3, useCodec);
msarettb23e6aa2015-06-09 13:56:10 -0700849 case kBottomRight_SubsetType:
msarettab80e352015-06-17 10:28:22 -0700850 return new SubsetSingleBench(path, colorType, width/3,
851 height/3, 2*width/3, 2*height/3, useCodec);
msarettb23e6aa2015-06-09 13:56:10 -0700852 case kTranslate_SubsetType:
853 return new SubsetTranslateBench(path, colorType, 512, 512,
854 useCodec);
855 case kZoom_SubsetType:
856 return new SubsetZoomBench(path, colorType, 512, 512,
857 useCodec);
msarett95f192d2015-02-13 09:05:41 -0800858 }
msarettb23e6aa2015-06-09 13:56:10 -0700859 } else {
860 break;
msarett95f192d2015-02-13 09:05:41 -0800861 }
862 }
msarettb23e6aa2015-06-09 13:56:10 -0700863 fCurrentSubsetType = 0;
864 fCurrentColorType++;
msarett95f192d2015-02-13 09:05:41 -0800865 }
msarettb23e6aa2015-06-09 13:56:10 -0700866 fCurrentColorType = 0;
867 fCurrentSubsetImage++;
msarett95f192d2015-02-13 09:05:41 -0800868 }
msarettb23e6aa2015-06-09 13:56:10 -0700869 fCurrentSubsetImage = 0;
870 fUseCodec++;
msarett95f192d2015-02-13 09:05:41 -0800871 }
872
mtkleine714e752014-07-31 12:13:48 -0700873 return NULL;
874 }
mtklein92007582014-08-01 07:46:52 -0700875
876 void fillCurrentOptions(ResultsWriter* log) const {
877 log->configOption("source_type", fSourceType);
mtkleinfd731ce2014-09-10 12:19:30 -0700878 log->configOption("bench_type", fBenchType);
mtklein92007582014-08-01 07:46:52 -0700879 if (0 == strcmp(fSourceType, "skp")) {
880 log->configOption("clip",
881 SkStringPrintf("%d %d %d %d", fClip.fLeft, fClip.fTop,
882 fClip.fRight, fClip.fBottom).c_str());
883 log->configOption("scale", SkStringPrintf("%.2g", fScales[fCurrentScale]).c_str());
robertphillips5b693772014-11-21 06:19:36 -0800884 if (fCurrentUseMPD > 0) {
885 SkASSERT(1 == fCurrentUseMPD || 2 == fCurrentUseMPD);
886 log->configOption("multi_picture_draw", fUseMPDs[fCurrentUseMPD-1] ? "true" : "false");
887 }
mtklein92007582014-08-01 07:46:52 -0700888 }
mtklein051e56d2014-12-04 08:46:51 -0800889 if (0 == strcmp(fBenchType, "recording")) {
890 log->metric("bytes", fSKPBytes);
891 log->metric("ops", fSKPOps);
892 }
mtklein92007582014-08-01 07:46:52 -0700893 }
894
mtkleine714e752014-07-31 12:13:48 -0700895private:
msarettb23e6aa2015-06-09 13:56:10 -0700896 enum SubsetType {
897 kTopLeft_SubsetType = 0,
898 kTopRight_SubsetType = 1,
msarettab80e352015-06-17 10:28:22 -0700899 kMiddle_SubsetType = 2,
900 kBottomLeft_SubsetType = 3,
901 kBottomRight_SubsetType = 4,
902 kTranslate_SubsetType = 5,
903 kZoom_SubsetType = 6,
msarettb23e6aa2015-06-09 13:56:10 -0700904 kLast_SubsetType = kZoom_SubsetType
905 };
906
mtkleine714e752014-07-31 12:13:48 -0700907 const BenchRegistry* fBenches;
908 const skiagm::GMRegistry* fGMs;
mtklein92007582014-08-01 07:46:52 -0700909 SkIRect fClip;
910 SkTArray<SkScalar> fScales;
911 SkTArray<SkString> fSKPs;
robertphillips5b693772014-11-21 06:19:36 -0800912 SkTArray<bool> fUseMPDs;
msarett95f192d2015-02-13 09:05:41 -0800913 SkTArray<SkString> fImages;
914 SkTArray<SkColorType> fColorTypes;
cdalton63a82852015-06-29 14:06:10 -0700915 SkScalar fZoomMax;
916 double fZoomPeriodMs;
mtklein92007582014-08-01 07:46:52 -0700917
mtklein051e56d2014-12-04 08:46:51 -0800918 double fSKPBytes, fSKPOps;
919
mtkleinfd731ce2014-09-10 12:19:30 -0700920 const char* fSourceType; // What we're benching: bench, GM, SKP, ...
921 const char* fBenchType; // How we bench it: micro, recording, playback, ...
922 int fCurrentRecording;
mtklein92007582014-08-01 07:46:52 -0700923 int fCurrentScale;
924 int fCurrentSKP;
robertphillips5b693772014-11-21 06:19:36 -0800925 int fCurrentUseMPD;
scroggo60869a42015-04-01 12:09:17 -0700926 int fCurrentCodec;
msarett95f192d2015-02-13 09:05:41 -0800927 int fCurrentImage;
928 int fCurrentSubsetImage;
929 int fCurrentColorType;
msarettb23e6aa2015-06-09 13:56:10 -0700930 int fCurrentSubsetType;
931 int fUseCodec;
joshualitt261c3ad2015-04-27 09:16:57 -0700932 int fCurrentAnimSKP;
mtkleine714e752014-07-31 12:13:48 -0700933};
934
jcgregorio3b27ade2014-11-13 08:06:40 -0800935int nanobench_main();
caryclark17f0b6d2014-07-22 10:15:34 -0700936int nanobench_main() {
jcgregorio3b27ade2014-11-13 08:06:40 -0800937 SetupCrashHandler();
mtkleinf3723212014-06-25 14:08:00 -0700938 SkAutoGraphics ag;
mtkleincc29d262015-07-09 10:04:56 -0700939 SkTaskGroup::Enabler enabled(FLAGS_threads);
mtkleinf3723212014-06-25 14:08:00 -0700940
krajcevski69a55602014-08-13 10:46:31 -0700941#if SK_SUPPORT_GPU
bsalomon682c2692015-05-22 14:01:46 -0700942 GrContextOptions grContextOpts;
krajcevski12b35442014-08-13 12:06:26 -0700943 grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks;
944 gGrFactory.reset(SkNEW_ARGS(GrContextFactory, (grContextOpts)));
krajcevski69a55602014-08-13 10:46:31 -0700945#endif
946
bsalomon06cddec2014-10-24 10:40:50 -0700947 if (FLAGS_veryVerbose) {
948 FLAGS_verbose = true;
949 }
950
cdaltone1b89582015-06-25 19:17:08 -0700951 double samplingTimeMs = 0;
952 if (0 != strcmp("0", FLAGS_samplingTime[0])) {
953 SkSTArray<8, char> timeUnit;
954 timeUnit.push_back_n(static_cast<int>(strlen(FLAGS_samplingTime[0])) + 1);
955 if (2 != sscanf(FLAGS_samplingTime[0], "%lf%s", &samplingTimeMs, timeUnit.begin()) ||
956 (0 != strcmp("s", timeUnit.begin()) && 0 != strcmp("ms", timeUnit.begin()))) {
957 SkDebugf("Invalid --samplingTime \"%s\". Must be \"0\", \"%%lfs\", or \"%%lfms\"\n",
958 FLAGS_samplingTime[0]);
959 exit(0);
960 }
961 if (0 == strcmp("s", timeUnit.begin())) {
962 samplingTimeMs *= 1000;
963 }
964 if (samplingTimeMs) {
965 FLAGS_samples = kTimedSampling;
966 }
967 }
968
bsalomon6eb03cc2014-08-07 14:28:50 -0700969 if (kAutoTuneLoops != FLAGS_loops) {
mtkleina189ccd2014-07-14 12:28:47 -0700970 FLAGS_samples = 1;
971 FLAGS_gpuFrameLag = 0;
972 }
973
bsalomon6eb03cc2014-08-07 14:28:50 -0700974 if (!FLAGS_writePath.isEmpty()) {
975 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]);
976 if (!sk_mkdir(FLAGS_writePath[0])) {
977 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_writePath[0]);
978 FLAGS_writePath.set(0, NULL);
979 }
980 }
981
mtklein1915b622014-08-20 11:45:00 -0700982 SkAutoTDelete<ResultsWriter> log(SkNEW(ResultsWriter));
mtklein60317d0f2014-07-14 11:30:37 -0700983 if (!FLAGS_outResultsFile.isEmpty()) {
mtklein1915b622014-08-20 11:45:00 -0700984 log.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0])));
mtklein60317d0f2014-07-14 11:30:37 -0700985 }
mtklein1915b622014-08-20 11:45:00 -0700986
987 if (1 == FLAGS_properties.count() % 2) {
988 SkDebugf("ERROR: --properties must be passed with an even number of arguments.\n");
989 return 1;
990 }
991 for (int i = 1; i < FLAGS_properties.count(); i += 2) {
992 log->property(FLAGS_properties[i-1], FLAGS_properties[i]);
993 }
jcgregoriobf5e5232014-07-17 13:14:16 -0700994
995 if (1 == FLAGS_key.count() % 2) {
996 SkDebugf("ERROR: --key must be passed with an even number of arguments.\n");
997 return 1;
998 }
999 for (int i = 1; i < FLAGS_key.count(); i += 2) {
mtklein1915b622014-08-20 11:45:00 -07001000 log->key(FLAGS_key[i-1], FLAGS_key[i]);
mtklein94e51562014-08-19 12:41:53 -07001001 }
mtklein60317d0f2014-07-14 11:30:37 -07001002
mtkleinf3723212014-06-25 14:08:00 -07001003 const double overhead = estimate_timer_overhead();
mtklein55b0ffc2014-07-17 08:38:23 -07001004 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
Mike Klein91294772014-07-16 19:59:32 -04001005
cdaltone1b89582015-06-25 19:17:08 -07001006 SkTArray<double> samples;
mtkleinbb6a0282014-07-01 08:43:42 -07001007
bsalomon6eb03cc2014-08-07 14:28:50 -07001008 if (kAutoTuneLoops != FLAGS_loops) {
1009 SkDebugf("Fixed number of loops; times would only be misleading so we won't print them.\n");
mtkleinf3723212014-06-25 14:08:00 -07001010 } else if (FLAGS_quiet) {
mtklein40b32be2014-07-09 08:46:49 -07001011 SkDebugf("median\tbench\tconfig\n");
cdaltone1b89582015-06-25 19:17:08 -07001012 } else if (kTimedSampling == FLAGS_samples) {
1013 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\n");
mtkleinf3723212014-06-25 14:08:00 -07001014 } else {
mtkleind75c4662015-04-30 07:11:22 -07001015 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n",
qiankun.miao8247ec32014-09-09 19:24:36 -07001016 FLAGS_samples, "samples");
mtkleinf3723212014-06-25 14:08:00 -07001017 }
1018
bsalomonc2553372014-07-22 13:09:05 -07001019 SkTDArray<Config> configs;
1020 create_configs(&configs);
1021
mtkleine070c2b2014-10-14 08:40:43 -07001022 int runs = 0;
mtklein92007582014-08-01 07:46:52 -07001023 BenchmarkStream benchStream;
1024 while (Benchmark* b = benchStream.next()) {
mtkleine714e752014-07-31 12:13:48 -07001025 SkAutoTDelete<Benchmark> bench(b);
mtklein96289052014-09-10 12:05:59 -07001026 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getUniqueName())) {
mtkleinf3723212014-06-25 14:08:00 -07001027 continue;
1028 }
1029
egdaniel3bf92062015-06-26 08:12:46 -07001030 if (!configs.isEmpty()) {
mtklein96289052014-09-10 12:05:59 -07001031 log->bench(bench->getUniqueName(), bench->getSize().fX, bench->getSize().fY);
jcgregoriobf5e5232014-07-17 13:14:16 -07001032 bench->preDraw();
1033 }
egdaniel3bf92062015-06-26 08:12:46 -07001034 for (int i = 0; i < configs.count(); ++i) {
1035 Target* target = is_enabled(b, configs[i]);
1036 if (!target) {
1037 continue;
1038 }
mtkleinf3723212014-06-25 14:08:00 -07001039
egdaniel3bf92062015-06-26 08:12:46 -07001040 // During HWUI output this canvas may be NULL.
1041 SkCanvas* canvas = target->getCanvas();
1042 const char* config = target->config.name;
1043
1044 target->setup();
robertphillips5b693772014-11-21 06:19:36 -08001045 bench->perCanvasPreDraw(canvas);
1046
cdaltone1b89582015-06-25 19:17:08 -07001047 int maxFrameLag;
egdaniel3bf92062015-06-26 08:12:46 -07001048 const int loops = target->needsFrameTiming(&maxFrameLag)
1049 ? setup_gpu_bench(target, bench.get(), maxFrameLag)
1050 : setup_cpu_bench(overhead, target, bench.get());
cdaltone1b89582015-06-25 19:17:08 -07001051
1052 if (kTimedSampling != FLAGS_samples) {
1053 samples.reset(FLAGS_samples);
1054 for (int s = 0; s < FLAGS_samples; s++) {
egdaniel3bf92062015-06-26 08:12:46 -07001055 samples[s] = time(loops, bench, target) / loops;
cdaltone1b89582015-06-25 19:17:08 -07001056 }
1057 } else if (samplingTimeMs) {
1058 samples.reset();
1059 if (FLAGS_verbose) {
1060 SkDebugf("Begin sampling %s for %ims\n",
1061 bench->getUniqueName(), static_cast<int>(samplingTimeMs));
1062 }
1063 WallTimer timer;
1064 timer.start();
1065 do {
egdaniel3bf92062015-06-26 08:12:46 -07001066 samples.push_back(time(loops, bench, target) / loops);
cdaltone1b89582015-06-25 19:17:08 -07001067 timer.end();
1068 } while (timer.fWall < samplingTimeMs);
1069 }
mtkleinf3723212014-06-25 14:08:00 -07001070
robertphillips5b693772014-11-21 06:19:36 -08001071 bench->perCanvasPostDraw(canvas);
1072
egdaniel3bf92062015-06-26 08:12:46 -07001073 if (Benchmark::kNonRendering_Backend != target->config.backend &&
tomhudsond968a6f2015-03-26 11:28:06 -07001074 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
bsalomon6eb03cc2014-08-07 14:28:50 -07001075 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config);
mtklein96289052014-09-10 12:05:59 -07001076 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName());
bsalomon6eb03cc2014-08-07 14:28:50 -07001077 pngFilename.append(".png");
egdaniel3bf92062015-06-26 08:12:46 -07001078 write_canvas_png(target, pngFilename);
bsalomon6eb03cc2014-08-07 14:28:50 -07001079 }
1080
1081 if (kFailedLoops == loops) {
mtklein2069e222014-08-04 13:57:39 -07001082 // Can't be timed. A warning note has already been printed.
egdaniel3bf92062015-06-26 08:12:46 -07001083 cleanup_run(target);
Mike Kleine3631362014-07-15 17:56:37 -04001084 continue;
1085 }
1086
cdaltone1b89582015-06-25 19:17:08 -07001087 Stats stats(samples);
mtklein1915b622014-08-20 11:45:00 -07001088 log->config(config);
mtklein96289052014-09-10 12:05:59 -07001089 log->configOption("name", bench->getName());
mtklein1915b622014-08-20 11:45:00 -07001090 benchStream.fillCurrentOptions(log.get());
egdaniel3bf92062015-06-26 08:12:46 -07001091 target->fillOptions(log.get());
mtklein051e56d2014-12-04 08:46:51 -08001092 log->metric("min_ms", stats.min);
mtkleine070c2b2014-10-14 08:40:43 -07001093 if (runs++ % FLAGS_flushEvery == 0) {
1094 log->flush();
1095 }
mtklein60317d0f2014-07-14 11:30:37 -07001096
bsalomon6eb03cc2014-08-07 14:28:50 -07001097 if (kAutoTuneLoops != FLAGS_loops) {
egdaniel3bf92062015-06-26 08:12:46 -07001098 if (configs.count() == 1) {
mtkleina189ccd2014-07-14 12:28:47 -07001099 config = ""; // Only print the config if we run the same bench on more than one.
1100 }
mtkleind75c4662015-04-30 07:11:22 -07001101 SkDebugf("%4d/%-4dMB\t%s\t%s\n"
1102 , sk_tools::getCurrResidentSetSizeMB()
1103 , sk_tools::getMaxResidentSetSizeMB()
mtklein53d25622014-09-18 07:39:42 -07001104 , bench->getUniqueName()
1105 , config);
mtkleinf3723212014-06-25 14:08:00 -07001106 } else if (FLAGS_quiet) {
egdaniel3bf92062015-06-26 08:12:46 -07001107 if (configs.count() == 1) {
mtkleinf3723212014-06-25 14:08:00 -07001108 config = ""; // Only print the config if we run the same bench on more than one.
1109 }
mtklein96289052014-09-10 12:05:59 -07001110 SkDebugf("%s\t%s\t%s\n", HUMANIZE(stats.median), bench->getUniqueName(), config);
mtkleinf3723212014-06-25 14:08:00 -07001111 } else {
1112 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean;
mtkleind75c4662015-04-30 07:11:22 -07001113 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n"
1114 , sk_tools::getCurrResidentSetSizeMB()
1115 , sk_tools::getMaxResidentSetSizeMB()
mtkleinf3723212014-06-25 14:08:00 -07001116 , loops
mtklein55b0ffc2014-07-17 08:38:23 -07001117 , HUMANIZE(stats.min)
1118 , HUMANIZE(stats.median)
1119 , HUMANIZE(stats.mean)
1120 , HUMANIZE(stats.max)
mtkleinf3723212014-06-25 14:08:00 -07001121 , stddev_percent
cdaltone1b89582015-06-25 19:17:08 -07001122 , kTimedSampling != FLAGS_samples ? stats.plot.c_str()
1123 : to_string(samples.count()).c_str()
mtkleinf3723212014-06-25 14:08:00 -07001124 , config
mtklein96289052014-09-10 12:05:59 -07001125 , bench->getUniqueName()
mtkleinf3723212014-06-25 14:08:00 -07001126 );
1127 }
bsalomonb12ea412015-02-02 21:19:50 -08001128#if SK_SUPPORT_GPU
1129 if (FLAGS_gpuStats &&
egdaniel3bf92062015-06-26 08:12:46 -07001130 Benchmark::kGPU_Backend == configs[i].backend) {
1131 gGrFactory->get(configs[i].ctxType)->printCacheStats();
1132 gGrFactory->get(configs[i].ctxType)->printGpuStats();
bsalomon06cddec2014-10-24 10:40:50 -07001133 }
1134#endif
cdalton2c56ba52015-06-26 13:32:53 -07001135 if (FLAGS_verbose) {
1136 SkDebugf("Samples: ");
1137 for (int i = 0; i < samples.count(); i++) {
1138 SkDebugf("%s ", HUMANIZE(samples[i]));
1139 }
1140 SkDebugf("%s\n", bench->getUniqueName());
1141 }
egdaniel3bf92062015-06-26 08:12:46 -07001142 cleanup_run(target);
mtkleinf3723212014-06-25 14:08:00 -07001143 }
mtkleinf3723212014-06-25 14:08:00 -07001144 }
1145
mtkleine1091452014-12-04 10:47:02 -08001146 log->bench("memory_usage", 0,0);
1147 log->config("meta");
1148 log->metric("max_rss_mb", sk_tools::getMaxResidentSetSizeMB());
1149
joshualitte0b19d42015-03-26 10:41:02 -07001150#if SK_SUPPORT_GPU
1151 // Make sure we clean up the global GrContextFactory here, otherwise we might race with the
1152 // SkEventTracer destructor
1153 gGrFactory.reset(NULL);
1154#endif
1155
mtkleinf3723212014-06-25 14:08:00 -07001156 return 0;
1157}
1158
jcgregorio3b27ade2014-11-13 08:06:40 -08001159#if !defined SK_BUILD_FOR_IOS
1160int main(int argc, char** argv) {
1161 SkCommandLineFlags::Parse(argc, argv);
1162 return nanobench_main();
1163}
1164#endif