blob: 7f87f3792801741b281e49b83bd40870b0776ddb [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"
23#include "SubsetDivisorBench.h"
24#include "SubsetSingleBench.h"
25#include "SubsetTranslateBench.h"
26#include "SubsetZoomBench.h"
mtkleinf3723212014-06-25 14:08:00 -070027#include "Stats.h"
28#include "Timer.h"
29
mtklein6838d852014-10-29 14:15:10 -070030#include "SkBBoxHierarchy.h"
mtkleinf3723212014-06-25 14:08:00 -070031#include "SkCanvas.h"
scroggo60869a42015-04-01 12:09:17 -070032#include "SkCodec.h"
caryclark17f0b6d2014-07-22 10:15:34 -070033#include "SkCommonFlags.h"
msarett95f192d2015-02-13 09:05:41 -080034#include "SkData.h"
mtkleinf3723212014-06-25 14:08:00 -070035#include "SkForceLinking.h"
36#include "SkGraphics.h"
mtklein20840502014-08-21 15:51:22 -070037#include "SkOSFile.h"
38#include "SkPictureRecorder.h"
mtklein051e56d2014-12-04 08:46:51 -080039#include "SkPictureUtils.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
reed53249782014-10-10 09:09:52 -070059static const int kAutoTuneLoops = 0;
bsalomon6eb03cc2014-08-07 14:28:50 -070060
mtkleinb5110422014-08-07 15:20:02 -070061static const int kDefaultLoops =
bsalomon6eb03cc2014-08-07 14:28:50 -070062#ifdef SK_DEBUG
63 1;
mtkleina189ccd2014-07-14 12:28:47 -070064#else
bsalomon6eb03cc2014-08-07 14:28:50 -070065 kAutoTuneLoops;
mtkleina189ccd2014-07-14 12:28:47 -070066#endif
67
bsalomon6eb03cc2014-08-07 14:28:50 -070068static SkString loops_help_txt() {
69 SkString help;
70 help.printf("Number of times to run each bench. Set this to %d to auto-"
71 "tune for each bench. Timings are only reported when auto-tuning.",
72 kAutoTuneLoops);
73 return help;
74}
75
76DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str());
77
mtkleinf3723212014-06-25 14:08:00 -070078DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
79DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
80DEFINE_double(overheadGoal, 0.0001,
81 "Loop until timer overhead is at most this fraction of our measurments.");
mtkleinbb6a0282014-07-01 08:43:42 -070082DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
83DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
krajcevski12b35442014-08-13 12:06:26 -070084DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to "
85 "software path rendering.");
mtkleinf3723212014-06-25 14:08:00 -070086
mtklein60317d0f2014-07-14 11:30:37 -070087DEFINE_string(outResultsFile, "", "If given, write results here as JSON.");
mtklein55b0ffc2014-07-17 08:38:23 -070088DEFINE_int32(maxCalibrationAttempts, 3,
89 "Try up to this many times to guess loops for a bench, or skip the bench.");
90DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this.");
mtklein92007582014-08-01 07:46:52 -070091DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs.");
92DEFINE_string(scales, "1.0", "Space-separated scales for SKPs.");
joshualitt261c3ad2015-04-27 09:16:57 -070093DEFINE_string(zoom, "1.0,1", "Comma-separated scale,step zoom factors for SKPs.");
mtklein20840502014-08-21 15:51:22 -070094DEFINE_bool(bbh, true, "Build a BBH for SKPs?");
robertphillips5b693772014-11-21 06:19:36 -080095DEFINE_bool(mpd, true, "Use MultiPictureDraw for the SKPs?");
mtkleine070c2b2014-10-14 08:40:43 -070096DEFINE_int32(flushEvery, 10, "Flush --outResultsFile every Nth run.");
mtklein55e88b22015-01-21 15:50:13 -080097DEFINE_bool(resetGpuContext, true, "Reset the GrContext before running each test.");
bsalomonb12ea412015-02-02 21:19:50 -080098DEFINE_bool(gpuStats, false, "Print GPU stats after each gpu benchmark?");
mtklein92007582014-08-01 07:46:52 -070099
mtkleinf3723212014-06-25 14:08:00 -0700100static SkString humanize(double ms) {
mtkleindc5bbab2014-09-24 06:34:09 -0700101 if (FLAGS_verbose) return SkStringPrintf("%llu", (uint64_t)(ms*1e6));
mtklein748ca3b2015-01-15 10:56:12 -0800102 return HumanizeMs(ms);
mtkleinf3723212014-06-25 14:08:00 -0700103}
mtklein55b0ffc2014-07-17 08:38:23 -0700104#define HUMANIZE(ms) humanize(ms).c_str()
mtkleinf3723212014-06-25 14:08:00 -0700105
tomhudsond968a6f2015-03-26 11:28:06 -0700106bool Target::init(SkImageInfo info, Benchmark* bench) {
107 if (Benchmark::kRaster_Backend == config.backend) {
108 this->surface.reset(SkSurface::NewRaster(info));
109 if (!this->surface.get()) {
110 return false;
111 }
112 }
113 return true;
114}
115bool Target::capturePixels(SkBitmap* bmp) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700116 SkCanvas* canvas = this->getCanvas();
tomhudsond968a6f2015-03-26 11:28:06 -0700117 if (!canvas) {
118 return false;
119 }
120 bmp->setInfo(canvas->imageInfo());
121 if (!canvas->readPixels(bmp, 0, 0)) {
122 SkDebugf("Can't read canvas pixels.\n");
123 return false;
124 }
125 return true;
126}
127
128#if SK_SUPPORT_GPU
129struct GPUTarget : public Target {
130 explicit GPUTarget(const Config& c) : Target(c), gl(NULL) { }
131 SkGLContext* gl;
132
133 void setup() override {
134 this->gl->makeCurrent();
135 // Make sure we're done with whatever came before.
136 SK_GL(*this->gl, Finish());
137 }
138 void endTiming() override {
139 if (this->gl) {
140 SK_GL(*this->gl, Flush());
141 this->gl->swapBuffers();
142 }
143 }
144 void fence() override {
145 SK_GL(*this->gl, Finish());
146 }
mtkleind75c4662015-04-30 07:11:22 -0700147
tomhudsond968a6f2015-03-26 11:28:06 -0700148 bool needsFrameTiming() const override { return true; }
149 bool init(SkImageInfo info, Benchmark* bench) override {
150 uint32_t flags = this->config.useDFText ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
151 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
152 this->surface.reset(SkSurface::NewRenderTarget(gGrFactory->get(this->config.ctxType),
153 SkSurface::kNo_Budgeted, info,
154 this->config.samples, &props));
155 this->gl = gGrFactory->getGLContext(this->config.ctxType);
156 if (!this->surface.get()) {
157 return false;
158 }
159 return true;
160 }
161 void fillOptions(ResultsWriter* log) override {
162 const GrGLubyte* version;
163 SK_GL_RET(*this->gl, version, GetString(GR_GL_VERSION));
164 log->configOption("GL_VERSION", (const char*)(version));
165
166 SK_GL_RET(*this->gl, version, GetString(GR_GL_RENDERER));
167 log->configOption("GL_RENDERER", (const char*) version);
168
169 SK_GL_RET(*this->gl, version, GetString(GR_GL_VENDOR));
170 log->configOption("GL_VENDOR", (const char*) version);
171
172 SK_GL_RET(*this->gl, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
173 log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
174 }
175};
mtkleind75c4662015-04-30 07:11:22 -0700176
tomhudsond968a6f2015-03-26 11:28:06 -0700177#endif
178
tomhudson75a0ebb2015-03-27 12:11:44 -0700179static double time(int loops, Benchmark* bench, Target* target) {
180 SkCanvas* canvas = target->getCanvas();
bsalomon6eb03cc2014-08-07 14:28:50 -0700181 if (canvas) {
182 canvas->clear(SK_ColorWHITE);
183 }
mtkleinbb6a0282014-07-01 08:43:42 -0700184 WallTimer timer;
185 timer.start();
tomhudson75a0ebb2015-03-27 12:11:44 -0700186 canvas = target->beginTiming(canvas);
187 bench->draw(loops, canvas);
mtkleinbb6a0282014-07-01 08:43:42 -0700188 if (canvas) {
189 canvas->flush();
190 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700191 target->endTiming();
mtkleinbb6a0282014-07-01 08:43:42 -0700192 timer.end();
193 return timer.fWall;
194}
195
mtkleinf3723212014-06-25 14:08:00 -0700196static double estimate_timer_overhead() {
197 double overhead = 0;
mtkleinf3723212014-06-25 14:08:00 -0700198 for (int i = 0; i < FLAGS_overheadLoops; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700199 WallTimer timer;
200 timer.start();
201 timer.end();
202 overhead += timer.fWall;
mtkleinf3723212014-06-25 14:08:00 -0700203 }
204 return overhead / FLAGS_overheadLoops;
205}
206
reed53249782014-10-10 09:09:52 -0700207static int detect_forever_loops(int loops) {
208 // look for a magic run-forever value
209 if (loops < 0) {
210 loops = SK_MaxS32;
211 }
212 return loops;
213}
214
mtklein55b0ffc2014-07-17 08:38:23 -0700215static int clamp_loops(int loops) {
216 if (loops < 1) {
mtklein527930f2014-11-06 08:04:34 -0800217 SkDebugf("ERROR: clamping loops from %d to 1. "
218 "There's probably something wrong with the bench.\n", loops);
mtklein55b0ffc2014-07-17 08:38:23 -0700219 return 1;
220 }
221 if (loops > FLAGS_maxLoops) {
222 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops);
223 return FLAGS_maxLoops;
224 }
225 return loops;
226}
227
tomhudsond968a6f2015-03-26 11:28:06 -0700228static bool write_canvas_png(Target* target, const SkString& filename) {
229
bsalomon6eb03cc2014-08-07 14:28:50 -0700230 if (filename.isEmpty()) {
231 return false;
232 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700233 if (target->getCanvas() &&
234 kUnknown_SkColorType == target->getCanvas()->imageInfo().colorType()) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700235 return false;
236 }
tomhudsond968a6f2015-03-26 11:28:06 -0700237
bsalomon6eb03cc2014-08-07 14:28:50 -0700238 SkBitmap bmp;
tomhudsond968a6f2015-03-26 11:28:06 -0700239
240 if (!target->capturePixels(&bmp)) {
bsalomon6eb03cc2014-08-07 14:28:50 -0700241 return false;
242 }
tomhudsond968a6f2015-03-26 11:28:06 -0700243
bsalomon6eb03cc2014-08-07 14:28:50 -0700244 SkString dir = SkOSPath::Dirname(filename.c_str());
245 if (!sk_mkdir(dir.c_str())) {
246 SkDebugf("Can't make dir %s.\n", dir.c_str());
247 return false;
248 }
249 SkFILEWStream stream(filename.c_str());
250 if (!stream.isValid()) {
251 SkDebugf("Can't write %s.\n", filename.c_str());
252 return false;
253 }
254 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 100)) {
255 SkDebugf("Can't encode a PNG.\n");
256 return false;
257 }
258 return true;
259}
260
261static int kFailedLoops = -2;
tomhudson75a0ebb2015-03-27 12:11:44 -0700262static int cpu_bench(const double overhead, Target* target, Benchmark* bench, double* samples) {
mtkleinbb6a0282014-07-01 08:43:42 -0700263 // First figure out approximately how many loops of bench it takes to make overhead negligible.
mtklein2069e222014-08-04 13:57:39 -0700264 double bench_plus_overhead = 0.0;
mtklein55b0ffc2014-07-17 08:38:23 -0700265 int round = 0;
bsalomon6eb03cc2014-08-07 14:28:50 -0700266 if (kAutoTuneLoops == FLAGS_loops) {
267 while (bench_plus_overhead < overhead) {
268 if (round++ == FLAGS_maxCalibrationAttempts) {
269 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
mtklein96289052014-09-10 12:05:59 -0700270 bench->getUniqueName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
bsalomon6eb03cc2014-08-07 14:28:50 -0700271 return kFailedLoops;
272 }
tomhudson75a0ebb2015-03-27 12:11:44 -0700273 bench_plus_overhead = time(1, bench, target);
mtklein55b0ffc2014-07-17 08:38:23 -0700274 }
mtklein2069e222014-08-04 13:57:39 -0700275 }
mtkleinf3723212014-06-25 14:08:00 -0700276
mtkleinbb6a0282014-07-01 08:43:42 -0700277 // Later we'll just start and stop the timer once but loop N times.
mtkleinf3723212014-06-25 14:08:00 -0700278 // We'll pick N to make timer overhead negligible:
279 //
mtkleinbb6a0282014-07-01 08:43:42 -0700280 // overhead
281 // ------------------------- < FLAGS_overheadGoal
282 // overhead + N * Bench Time
mtkleinf3723212014-06-25 14:08:00 -0700283 //
mtkleinbb6a0282014-07-01 08:43:42 -0700284 // where bench_plus_overhead ≈ overhead + Bench Time.
mtkleinf3723212014-06-25 14:08:00 -0700285 //
286 // Doing some math, we get:
287 //
mtkleinbb6a0282014-07-01 08:43:42 -0700288 // (overhead / FLAGS_overheadGoal) - overhead
289 // ------------------------------------------ < N
290 // bench_plus_overhead - overhead)
mtkleinf3723212014-06-25 14:08:00 -0700291 //
292 // Luckily, this also works well in practice. :)
bsalomon6eb03cc2014-08-07 14:28:50 -0700293 int loops = FLAGS_loops;
294 if (kAutoTuneLoops == loops) {
295 const double numer = overhead / FLAGS_overheadGoal - overhead;
296 const double denom = bench_plus_overhead - overhead;
297 loops = (int)ceil(numer / denom);
reed53249782014-10-10 09:09:52 -0700298 loops = clamp_loops(loops);
299 } else {
300 loops = detect_forever_loops(loops);
bsalomon6eb03cc2014-08-07 14:28:50 -0700301 }
mtkleinbb6a0282014-07-01 08:43:42 -0700302
303 for (int i = 0; i < FLAGS_samples; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700304 samples[i] = time(loops, bench, target) / loops;
mtkleinbb6a0282014-07-01 08:43:42 -0700305 }
306 return loops;
mtkleinf3723212014-06-25 14:08:00 -0700307}
308
tomhudsond968a6f2015-03-26 11:28:06 -0700309static int gpu_bench(Target* target,
mtkleinbb6a0282014-07-01 08:43:42 -0700310 Benchmark* bench,
mtkleinbb6a0282014-07-01 08:43:42 -0700311 double* samples) {
mtkleinbb6a0282014-07-01 08:43:42 -0700312 // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
bsalomon6eb03cc2014-08-07 14:28:50 -0700313 int loops = FLAGS_loops;
314 if (kAutoTuneLoops == loops) {
315 loops = 1;
mtkleina189ccd2014-07-14 12:28:47 -0700316 double elapsed = 0;
317 do {
mtklein527930f2014-11-06 08:04:34 -0800318 if (1<<30 == loops) {
319 // We're about to wrap. Something's wrong with the bench.
320 loops = 0;
321 break;
322 }
mtkleina189ccd2014-07-14 12:28:47 -0700323 loops *= 2;
324 // If the GPU lets frames lag at all, we need to make sure we're timing
325 // _this_ round, not still timing last round. We force this by looping
326 // more times than any reasonable GPU will allow frames to lag.
327 for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700328 elapsed = time(loops, bench, target);
mtkleina189ccd2014-07-14 12:28:47 -0700329 }
330 } while (elapsed < FLAGS_gpuMs);
mtkleinbb6a0282014-07-01 08:43:42 -0700331
mtkleina189ccd2014-07-14 12:28:47 -0700332 // We've overshot at least a little. Scale back linearly.
333 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed);
reed53249782014-10-10 09:09:52 -0700334 loops = clamp_loops(loops);
mtkleinbb6a0282014-07-01 08:43:42 -0700335
tomhudsond968a6f2015-03-26 11:28:06 -0700336 // Make sure we're not still timing our calibration.
337 target->fence();
reed53249782014-10-10 09:09:52 -0700338 } else {
339 loops = detect_forever_loops(loops);
mtkleina189ccd2014-07-14 12:28:47 -0700340 }
mtkleinbb6a0282014-07-01 08:43:42 -0700341
342 // Pretty much the same deal as the calibration: do some warmup to make
343 // sure we're timing steady-state pipelined frames.
344 for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700345 time(loops, bench, target);
mtkleinf3723212014-06-25 14:08:00 -0700346 }
mtkleinbb6a0282014-07-01 08:43:42 -0700347
348 // Now, actually do the timing!
349 for (int i = 0; i < FLAGS_samples; i++) {
tomhudson75a0ebb2015-03-27 12:11:44 -0700350 samples[i] = time(loops, bench, target) / loops;
mtkleinbb6a0282014-07-01 08:43:42 -0700351 }
tomhudsond968a6f2015-03-26 11:28:06 -0700352
mtkleinbb6a0282014-07-01 08:43:42 -0700353 return loops;
354}
mtkleinbb6a0282014-07-01 08:43:42 -0700355
356static SkString to_lower(const char* str) {
357 SkString lower(str);
358 for (size_t i = 0; i < lower.size(); i++) {
359 lower[i] = tolower(lower[i]);
360 }
361 return lower;
mtkleinf3723212014-06-25 14:08:00 -0700362}
363
bsalomonc2553372014-07-22 13:09:05 -0700364static bool is_cpu_config_allowed(const char* name) {
mtkleinbb6a0282014-07-01 08:43:42 -0700365 for (int i = 0; i < FLAGS_config.count(); i++) {
bsalomonc2553372014-07-22 13:09:05 -0700366 if (to_lower(FLAGS_config[i]).equals(name)) {
367 return true;
mtkleinf3723212014-06-25 14:08:00 -0700368 }
369 }
bsalomonc2553372014-07-22 13:09:05 -0700370 return false;
mtkleinbb6a0282014-07-01 08:43:42 -0700371}
372
bsalomonc2553372014-07-22 13:09:05 -0700373#if SK_SUPPORT_GPU
374static bool is_gpu_config_allowed(const char* name, GrContextFactory::GLContextType ctxType,
375 int sampleCnt) {
376 if (!is_cpu_config_allowed(name)) {
377 return false;
378 }
krajcevski69a55602014-08-13 10:46:31 -0700379 if (const GrContext* ctx = gGrFactory->get(ctxType)) {
bsalomon76228632015-05-29 08:02:10 -0700380 return sampleCnt <= ctx->caps()->maxSampleCount();
bsalomonc2553372014-07-22 13:09:05 -0700381 }
382 return false;
383}
384#endif
mtkleinbb6a0282014-07-01 08:43:42 -0700385
bsalomonc2553372014-07-22 13:09:05 -0700386#if SK_SUPPORT_GPU
387#define kBogusGLContextType GrContextFactory::kNative_GLContextType
388#else
389#define kBogusGLContextType 0
mtkleine714e752014-07-31 12:13:48 -0700390#endif
bsalomonc2553372014-07-22 13:09:05 -0700391
392// Append all configs that are enabled and supported.
393static void create_configs(SkTDArray<Config>* configs) {
jvanverth4736e142014-11-07 07:12:46 -0800394 #define CPU_CONFIG(name, backend, color, alpha) \
395 if (is_cpu_config_allowed(#name)) { \
396 Config config = { #name, Benchmark::backend, color, alpha, 0, \
397 kBogusGLContextType, false }; \
398 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700399 }
mtkleine714e752014-07-31 12:13:48 -0700400
mtklein40b32be2014-07-09 08:46:49 -0700401 if (FLAGS_cpu) {
bsalomonc2553372014-07-22 13:09:05 -0700402 CPU_CONFIG(nonrendering, kNonRendering_Backend, kUnknown_SkColorType, kUnpremul_SkAlphaType)
403 CPU_CONFIG(8888, kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType)
404 CPU_CONFIG(565, kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType)
mtklein40b32be2014-07-09 08:46:49 -0700405 }
mtkleinbb6a0282014-07-01 08:43:42 -0700406
407#if SK_SUPPORT_GPU
jvanverth4736e142014-11-07 07:12:46 -0800408 #define GPU_CONFIG(name, ctxType, samples, useDFText) \
bsalomonc2553372014-07-22 13:09:05 -0700409 if (is_gpu_config_allowed(#name, GrContextFactory::ctxType, samples)) { \
410 Config config = { \
411 #name, \
412 Benchmark::kGPU_Backend, \
413 kN32_SkColorType, \
414 kPremul_SkAlphaType, \
415 samples, \
jvanverth4736e142014-11-07 07:12:46 -0800416 GrContextFactory::ctxType, \
417 useDFText }; \
bsalomonc2553372014-07-22 13:09:05 -0700418 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700419 }
mtkleine714e752014-07-31 12:13:48 -0700420
mtklein40b32be2014-07-09 08:46:49 -0700421 if (FLAGS_gpu) {
jvanverth4736e142014-11-07 07:12:46 -0800422 GPU_CONFIG(gpu, kNative_GLContextType, 0, false)
423 GPU_CONFIG(msaa4, kNative_GLContextType, 4, false)
424 GPU_CONFIG(msaa16, kNative_GLContextType, 16, false)
425 GPU_CONFIG(nvprmsaa4, kNVPR_GLContextType, 4, false)
426 GPU_CONFIG(nvprmsaa16, kNVPR_GLContextType, 16, false)
427 GPU_CONFIG(gpudft, kNative_GLContextType, 0, true)
428 GPU_CONFIG(debug, kDebug_GLContextType, 0, false)
429 GPU_CONFIG(nullgpu, kNull_GLContextType, 0, false)
bsalomon3b4d0772014-08-06 10:52:33 -0700430#ifdef SK_ANGLE
jvanverth4736e142014-11-07 07:12:46 -0800431 GPU_CONFIG(angle, kANGLE_GLContextType, 0, false)
bsalomon3b4d0772014-08-06 10:52:33 -0700432#endif
mtklein40b32be2014-07-09 08:46:49 -0700433 }
mtkleinbb6a0282014-07-01 08:43:42 -0700434#endif
tomhudsond968a6f2015-03-26 11:28:06 -0700435
436#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
437 if (is_cpu_config_allowed("hwui")) {
438 Config config = { "hwui", Benchmark::kHWUI_Backend, kRGBA_8888_SkColorType,
439 kPremul_SkAlphaType, 0, kBogusGLContextType, false };
440 configs->push(config);
441 }
442#endif
mtkleinf3723212014-06-25 14:08:00 -0700443}
444
bsalomonc2553372014-07-22 13:09:05 -0700445// If bench is enabled for config, returns a Target* for it, otherwise NULL.
446static Target* is_enabled(Benchmark* bench, const Config& config) {
447 if (!bench->isSuitableFor(config.backend)) {
448 return NULL;
449 }
450
reede5ea5002014-09-03 11:54:58 -0700451 SkImageInfo info = SkImageInfo::Make(bench->getSize().fX, bench->getSize().fY,
452 config.color, config.alpha);
bsalomonc2553372014-07-22 13:09:05 -0700453
tomhudsond968a6f2015-03-26 11:28:06 -0700454 Target* target = NULL;
bsalomonc2553372014-07-22 13:09:05 -0700455
tomhudsond968a6f2015-03-26 11:28:06 -0700456 switch (config.backend) {
bsalomonc2553372014-07-22 13:09:05 -0700457#if SK_SUPPORT_GPU
tomhudsond968a6f2015-03-26 11:28:06 -0700458 case Benchmark::kGPU_Backend:
459 target = new GPUTarget(config);
460 break;
bsalomonc2553372014-07-22 13:09:05 -0700461#endif
tomhudsond968a6f2015-03-26 11:28:06 -0700462#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
463 case Benchmark::kHWUI_Backend:
464 target = new HWUITarget(config, bench);
465 break;
466#endif
467 default:
468 target = new Target(config);
469 break;
470 }
bsalomonc2553372014-07-22 13:09:05 -0700471
tomhudsond968a6f2015-03-26 11:28:06 -0700472 if (!target->init(info, bench)) {
bsalomonc2553372014-07-22 13:09:05 -0700473 delete target;
474 return NULL;
475 }
476 return target;
477}
478
479// Creates targets for a benchmark and a set of configs.
480static void create_targets(SkTDArray<Target*>* targets, Benchmark* b,
481 const SkTDArray<Config>& configs) {
482 for (int i = 0; i < configs.count(); ++i) {
483 if (Target* t = is_enabled(b, configs[i])) {
484 targets->push(t);
485 }
mtkleine714e752014-07-31 12:13:48 -0700486
bsalomonc2553372014-07-22 13:09:05 -0700487 }
488}
489
msarettb23e6aa2015-06-09 13:56:10 -0700490/*
491 * Returns true if set up for a subset decode succeeds, false otherwise
492 * If the set-up succeeds, the width and height parameters will be set
493 */
494static bool valid_subset_bench(const SkString& path, SkColorType colorType, bool useCodec,
495 int* width, int* height) {
496 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
497 SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(encoded));
498
499 if (useCodec) {
500 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach()));
501 if (NULL == codec) {
502 SkDebugf("Could not create codec for %s. Skipping bench.\n", path.c_str());
503 return false;
504 }
505
506 // These will be initialized by SkCodec if the color type is kIndex8 and
507 // unused otherwise.
508 SkPMColor colors[256];
509 int colorCount;
510 const SkImageInfo info = codec->getInfo().makeColorType(colorType);
511 SkAutoTDeleteArray<uint8_t> row(SkNEW_ARRAY(uint8_t, info.minRowBytes()));
512 SkScanlineDecoder* scanlineDecoder = codec->getScanlineDecoder(info, NULL,
513 colors, &colorCount);
514 if (NULL == scanlineDecoder) {
515 SkDebugf("Could not create scanline decoder for %s with color type %s. "
516 "Skipping bench.\n", path.c_str(), get_color_name(colorType));
517 return false;
518 }
519 *width = info.width();
520 *height = info.height();
521 } else {
522 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
523 if (NULL == decoder) {
524 SkDebugf("Could not create decoder for %s. Skipping bench.\n", path.c_str());
525 return false;
526 }
527 //FIXME: See skbug.com/3921
528 if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) {
529 SkDebugf("Cannot use image subset decoder for %s with color type %s. "
530 "Skipping bench.\n", path.c_str(), get_color_name(colorType));
531 return false;
532 }
533 if (!decoder->buildTileIndex(stream.detach(), width, height)) {
534 SkDebugf("Could not build tile index for %s. Skipping bench.\n", path.c_str());
535 return false;
536 }
537 }
538 return true;
539}
jcgregoriobf5e5232014-07-17 13:14:16 -0700540
mtkleine714e752014-07-31 12:13:48 -0700541class BenchmarkStream {
542public:
mtklein92007582014-08-01 07:46:52 -0700543 BenchmarkStream() : fBenches(BenchRegistry::Head())
544 , fGMs(skiagm::GMRegistry::Head())
mtkleinfd731ce2014-09-10 12:19:30 -0700545 , fCurrentRecording(0)
mtklein92007582014-08-01 07:46:52 -0700546 , fCurrentScale(0)
robertphillips5b693772014-11-21 06:19:36 -0800547 , fCurrentSKP(0)
msarett95f192d2015-02-13 09:05:41 -0800548 , fCurrentUseMPD(0)
scroggo60869a42015-04-01 12:09:17 -0700549 , fCurrentCodec(0)
msarett95f192d2015-02-13 09:05:41 -0800550 , fCurrentImage(0)
551 , fCurrentSubsetImage(0)
552 , fCurrentColorType(0)
msarettb23e6aa2015-06-09 13:56:10 -0700553 , fCurrentSubsetType(0)
554 , fUseCodec(0)
555 , fCurrentAnimSKP(0) {
mtklein92007582014-08-01 07:46:52 -0700556 for (int i = 0; i < FLAGS_skps.count(); i++) {
557 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
558 fSKPs.push_back() = FLAGS_skps[i];
559 } else {
560 SkOSFile::Iter it(FLAGS_skps[i], ".skp");
561 SkString path;
562 while (it.next(&path)) {
563 fSKPs.push_back() = SkOSPath::Join(FLAGS_skps[0], path.c_str());
564 }
565 }
566 }
mtkleine714e752014-07-31 12:13:48 -0700567
mtklein92007582014-08-01 07:46:52 -0700568 if (4 != sscanf(FLAGS_clip[0], "%d,%d,%d,%d",
569 &fClip.fLeft, &fClip.fTop, &fClip.fRight, &fClip.fBottom)) {
570 SkDebugf("Can't parse %s from --clip as an SkIRect.\n", FLAGS_clip[0]);
571 exit(1);
572 }
573
574 for (int i = 0; i < FLAGS_scales.count(); i++) {
575 if (1 != sscanf(FLAGS_scales[i], "%f", &fScales.push_back())) {
576 SkDebugf("Can't parse %s from --scales as an SkScalar.\n", FLAGS_scales[i]);
577 exit(1);
578 }
579 }
robertphillips5b693772014-11-21 06:19:36 -0800580
joshualitt261c3ad2015-04-27 09:16:57 -0700581 if (2 != sscanf(FLAGS_zoom[0], "%f,%d", &fZoomScale, &fZoomSteps)) {
582 SkDebugf("Can't parse %s from --zoom as a scale,step.\n", FLAGS_zoom[0]);
583 exit(1);
584 }
585
robertphillips5b693772014-11-21 06:19:36 -0800586 fUseMPDs.push_back() = false;
587 if (FLAGS_mpd) {
588 fUseMPDs.push_back() = true;
589 }
mtklein95553d92015-03-12 08:24:21 -0700590
msarett95f192d2015-02-13 09:05:41 -0800591 // Prepare the images for decoding
592 for (int i = 0; i < FLAGS_images.count(); i++) {
593 const char* flag = FLAGS_images[i];
594 if (sk_isdir(flag)) {
595 // If the value passed in is a directory, add all the images
596 SkOSFile::Iter it(flag);
597 SkString file;
598 while (it.next(&file)) {
599 fImages.push_back() = SkOSPath::Join(flag, file.c_str());
600 }
601 } else if (sk_exists(flag)) {
602 // Also add the value if it is a single image
603 fImages.push_back() = flag;
604 }
605 }
mtklein95553d92015-03-12 08:24:21 -0700606
msarett95f192d2015-02-13 09:05:41 -0800607 // Choose the candidate color types for image decoding
608 const SkColorType colorTypes[] =
msarettb23e6aa2015-06-09 13:56:10 -0700609 { kN32_SkColorType,
610 kRGB_565_SkColorType,
611 kAlpha_8_SkColorType,
612 kIndex_8_SkColorType,
613 kGray_8_SkColorType };
msarett95f192d2015-02-13 09:05:41 -0800614 fColorTypes.push_back_n(SK_ARRAY_COUNT(colorTypes), colorTypes);
mtklein92007582014-08-01 07:46:52 -0700615 }
616
mtkleinfd731ce2014-09-10 12:19:30 -0700617 static bool ReadPicture(const char* path, SkAutoTUnref<SkPicture>* pic) {
618 // Not strictly necessary, as it will be checked again later,
619 // but helps to avoid a lot of pointless work if we're going to skip it.
620 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path)) {
621 return false;
622 }
623
scroggoa1193e42015-01-21 12:09:53 -0800624 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path));
mtkleinfd731ce2014-09-10 12:19:30 -0700625 if (stream.get() == NULL) {
626 SkDebugf("Could not read %s.\n", path);
627 return false;
628 }
629
mtklein57f27bd2015-02-09 11:58:41 -0800630 pic->reset(SkPicture::CreateFromStream(stream.get()));
mtkleinfd731ce2014-09-10 12:19:30 -0700631 if (pic->get() == NULL) {
632 SkDebugf("Could not read %s as an SkPicture.\n", path);
633 return false;
634 }
635 return true;
636 }
637
mtklein92007582014-08-01 07:46:52 -0700638 Benchmark* next() {
mtkleine714e752014-07-31 12:13:48 -0700639 if (fBenches) {
640 Benchmark* bench = fBenches->factory()(NULL);
641 fBenches = fBenches->next();
mtklein92007582014-08-01 07:46:52 -0700642 fSourceType = "bench";
mtkleinfd731ce2014-09-10 12:19:30 -0700643 fBenchType = "micro";
mtkleine714e752014-07-31 12:13:48 -0700644 return bench;
645 }
mtklein92007582014-08-01 07:46:52 -0700646
mtkleine714e752014-07-31 12:13:48 -0700647 while (fGMs) {
648 SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL));
649 fGMs = fGMs->next();
mtkleincf5d9c92015-01-23 10:31:45 -0800650 if (gm->runAsBench()) {
mtklein92007582014-08-01 07:46:52 -0700651 fSourceType = "gm";
mtkleinfd731ce2014-09-10 12:19:30 -0700652 fBenchType = "micro";
mtkleine714e752014-07-31 12:13:48 -0700653 return SkNEW_ARGS(GMBench, (gm.detach()));
654 }
655 }
mtklein92007582014-08-01 07:46:52 -0700656
mtkleinfd731ce2014-09-10 12:19:30 -0700657 // First add all .skps as RecordingBenches.
658 while (fCurrentRecording < fSKPs.count()) {
659 const SkString& path = fSKPs[fCurrentRecording++];
660 SkAutoTUnref<SkPicture> pic;
661 if (!ReadPicture(path.c_str(), &pic)) {
662 continue;
663 }
664 SkString name = SkOSPath::Basename(path.c_str());
665 fSourceType = "skp";
666 fBenchType = "recording";
bsalomon0aa5cea2014-12-15 09:13:35 -0800667 fSKPBytes = static_cast<double>(SkPictureUtils::ApproximateBytesUsed(pic));
mtklein051e56d2014-12-04 08:46:51 -0800668 fSKPOps = pic->approximateOpCount();
mtkleinfd731ce2014-09-10 12:19:30 -0700669 return SkNEW_ARGS(RecordingBench, (name.c_str(), pic.get(), FLAGS_bbh));
670 }
671
672 // Then once each for each scale as SKPBenches (playback).
mtklein92007582014-08-01 07:46:52 -0700673 while (fCurrentScale < fScales.count()) {
674 while (fCurrentSKP < fSKPs.count()) {
robertphillips5b693772014-11-21 06:19:36 -0800675 const SkString& path = fSKPs[fCurrentSKP];
mtkleinfd731ce2014-09-10 12:19:30 -0700676 SkAutoTUnref<SkPicture> pic;
677 if (!ReadPicture(path.c_str(), &pic)) {
robertphillips5b693772014-11-21 06:19:36 -0800678 fCurrentSKP++;
mtklein92007582014-08-01 07:46:52 -0700679 continue;
680 }
robertphillips5b693772014-11-21 06:19:36 -0800681
682 while (fCurrentUseMPD < fUseMPDs.count()) {
683 if (FLAGS_bbh) {
684 // The SKP we read off disk doesn't have a BBH. Re-record so it grows one.
685 SkRTreeFactory factory;
686 SkPictureRecorder recorder;
687 static const int kFlags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
688 pic->playback(recorder.beginRecording(pic->cullRect().width(),
689 pic->cullRect().height(),
mtklein748ca3b2015-01-15 10:56:12 -0800690 &factory,
robertphillipse451c4d2014-12-09 10:28:00 -0800691 fUseMPDs[fCurrentUseMPD] ? kFlags : 0));
robertphillips5b693772014-11-21 06:19:36 -0800692 pic.reset(recorder.endRecording());
693 }
694 SkString name = SkOSPath::Basename(path.c_str());
695 fSourceType = "skp";
696 fBenchType = "playback";
697 return SkNEW_ARGS(SKPBench,
joshualitt261c3ad2015-04-27 09:16:57 -0700698 (name.c_str(), pic.get(), fClip,
699 fScales[fCurrentScale], fUseMPDs[fCurrentUseMPD++]));
700
mtklein20840502014-08-21 15:51:22 -0700701 }
robertphillips5b693772014-11-21 06:19:36 -0800702 fCurrentUseMPD = 0;
703 fCurrentSKP++;
mtklein92007582014-08-01 07:46:52 -0700704 }
705 fCurrentSKP = 0;
706 fCurrentScale++;
707 }
708
joshualitt261c3ad2015-04-27 09:16:57 -0700709 // Now loop over each skp again if we have an animation
710 if (fZoomScale != 1.0f && fZoomSteps != 1) {
711 while (fCurrentAnimSKP < fSKPs.count()) {
712 const SkString& path = fSKPs[fCurrentAnimSKP];
713 SkAutoTUnref<SkPicture> pic;
714 if (!ReadPicture(path.c_str(), &pic)) {
715 fCurrentAnimSKP++;
716 continue;
717 }
718
719 fCurrentAnimSKP++;
720 SkString name = SkOSPath::Basename(path.c_str());
721 SkMatrix anim = SkMatrix::I();
722 anim.setScale(fZoomScale, fZoomScale);
723 return SkNEW_ARGS(SKPAnimationBench, (name.c_str(), pic.get(), fClip, anim,
724 fZoomSteps));
725 }
726 }
727
728
scroggo60869a42015-04-01 12:09:17 -0700729 for (; fCurrentCodec < fImages.count(); fCurrentCodec++) {
730 const SkString& path = fImages[fCurrentCodec];
731 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
732 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
scroggo60869a42015-04-01 12:09:17 -0700733 if (!codec) {
734 // Nothing to time.
msarett9d9725c2015-04-24 11:41:55 -0700735 SkDebugf("Cannot find codec for %s\n", path.c_str());
scroggo60869a42015-04-01 12:09:17 -0700736 continue;
737 }
scroggo21027992015-04-02 13:22:38 -0700738
scroggo60869a42015-04-01 12:09:17 -0700739 while (fCurrentColorType < fColorTypes.count()) {
scroggo21027992015-04-02 13:22:38 -0700740 const SkColorType colorType = fColorTypes[fCurrentColorType];
scroggo60869a42015-04-01 12:09:17 -0700741 fCurrentColorType++;
scroggo21027992015-04-02 13:22:38 -0700742
scroggo60869a42015-04-01 12:09:17 -0700743 // Make sure we can decode to this color type.
scroggo60869a42015-04-01 12:09:17 -0700744 SkImageInfo info = codec->getInfo().makeColorType(colorType);
scroggo21027992015-04-02 13:22:38 -0700745 SkAlphaType alphaType;
746 if (!SkColorTypeValidateAlphaType(colorType, info.alphaType(),
747 &alphaType)) {
748 continue;
749 }
750 if (alphaType != info.alphaType()) {
751 info = info.makeAlphaType(alphaType);
752 }
753
754 const size_t rowBytes = info.minRowBytes();
755 SkAutoMalloc storage(info.getSafeSize(rowBytes));
756
757 // Used if fCurrentColorType is kIndex_8_SkColorType
758 int colorCount = 256;
759 SkPMColor colors[256];
760
scroggo60869a42015-04-01 12:09:17 -0700761 const SkImageGenerator::Result result = codec->getPixels(
scroggo21027992015-04-02 13:22:38 -0700762 info, storage.get(), rowBytes, NULL, colors,
763 &colorCount);
scroggo60869a42015-04-01 12:09:17 -0700764 switch (result) {
765 case SkImageGenerator::kSuccess:
766 case SkImageGenerator::kIncompleteInput:
767 return new CodecBench(SkOSPath::Basename(path.c_str()),
768 encoded, colorType);
769 case SkImageGenerator::kInvalidConversion:
770 // This is okay. Not all conversions are valid.
771 break;
scroggo60869a42015-04-01 12:09:17 -0700772 default:
773 // This represents some sort of failure.
774 SkASSERT(false);
775 break;
776 }
777 }
778 fCurrentColorType = 0;
779 }
780
msarett95f192d2015-02-13 09:05:41 -0800781 // Run the DecodingBenches
782 while (fCurrentImage < fImages.count()) {
783 while (fCurrentColorType < fColorTypes.count()) {
784 const SkString& path = fImages[fCurrentImage];
785 SkColorType colorType = fColorTypes[fCurrentColorType];
786 fCurrentColorType++;
scroggo60869a42015-04-01 12:09:17 -0700787 // Check if the image decodes to the right color type
788 // before creating the benchmark
msarett95f192d2015-02-13 09:05:41 -0800789 SkBitmap bitmap;
790 if (SkImageDecoder::DecodeFile(path.c_str(), &bitmap,
scroggo60869a42015-04-01 12:09:17 -0700791 colorType, SkImageDecoder::kDecodePixels_Mode)
792 && bitmap.colorType() == colorType) {
msarett95f192d2015-02-13 09:05:41 -0800793 return new DecodingBench(path, colorType);
794 }
795 }
796 fCurrentColorType = 0;
797 fCurrentImage++;
798 }
799
msarettb23e6aa2015-06-09 13:56:10 -0700800 // Run the SubsetBenches
801 bool useCodecOpts[] = { true, false };
802 while (fUseCodec < 2) {
803 bool useCodec = useCodecOpts[fUseCodec];
804 while (fCurrentSubsetImage < fImages.count()) {
805 while (fCurrentColorType < fColorTypes.count()) {
806 const SkString& path = fImages[fCurrentSubsetImage];
807 SkColorType colorType = fColorTypes[fCurrentColorType];
808 while (fCurrentSubsetType <= kLast_SubsetType) {
809 int width = 0;
810 int height = 0;
811 int currentSubsetType = fCurrentSubsetType++;
812 if (valid_subset_bench(path, colorType, useCodec, &width, &height)) {
813 switch (currentSubsetType) {
814 case kTopLeft_SubsetType:
815 return new SubsetSingleBench(path, colorType, width/2,
816 height/2, 0, 0, useCodec);
817 case kTopRight_SubsetType:
818 return new SubsetSingleBench(path, colorType, width/2,
819 height/2, width/2, 0, useCodec);
820 case kBottomLeft_SubsetType:
821 return new SubsetSingleBench(path, colorType, width/2,
822 height/2, 0, height/2, useCodec);
823 case kBottomRight_SubsetType:
824 return new SubsetSingleBench(path, colorType, width/2,
825 height/2, width/2, height/2, useCodec);
826 case k2x2_SubsetType:
827 return new SubsetDivisorBench(path, colorType, 2, useCodec);
828 case k3x3_SubsetType:
829 return new SubsetDivisorBench(path, colorType, 3, useCodec);
830 case kTranslate_SubsetType:
831 return new SubsetTranslateBench(path, colorType, 512, 512,
832 useCodec);
833 case kZoom_SubsetType:
834 return new SubsetZoomBench(path, colorType, 512, 512,
835 useCodec);
msarett95f192d2015-02-13 09:05:41 -0800836 }
msarettb23e6aa2015-06-09 13:56:10 -0700837 } else {
838 break;
msarett95f192d2015-02-13 09:05:41 -0800839 }
840 }
msarettb23e6aa2015-06-09 13:56:10 -0700841 fCurrentSubsetType = 0;
842 fCurrentColorType++;
msarett95f192d2015-02-13 09:05:41 -0800843 }
msarettb23e6aa2015-06-09 13:56:10 -0700844 fCurrentColorType = 0;
845 fCurrentSubsetImage++;
msarett95f192d2015-02-13 09:05:41 -0800846 }
msarettb23e6aa2015-06-09 13:56:10 -0700847 fCurrentSubsetImage = 0;
848 fUseCodec++;
msarett95f192d2015-02-13 09:05:41 -0800849 }
850
mtkleine714e752014-07-31 12:13:48 -0700851 return NULL;
852 }
mtklein92007582014-08-01 07:46:52 -0700853
854 void fillCurrentOptions(ResultsWriter* log) const {
855 log->configOption("source_type", fSourceType);
mtkleinfd731ce2014-09-10 12:19:30 -0700856 log->configOption("bench_type", fBenchType);
mtklein92007582014-08-01 07:46:52 -0700857 if (0 == strcmp(fSourceType, "skp")) {
858 log->configOption("clip",
859 SkStringPrintf("%d %d %d %d", fClip.fLeft, fClip.fTop,
860 fClip.fRight, fClip.fBottom).c_str());
861 log->configOption("scale", SkStringPrintf("%.2g", fScales[fCurrentScale]).c_str());
robertphillips5b693772014-11-21 06:19:36 -0800862 if (fCurrentUseMPD > 0) {
863 SkASSERT(1 == fCurrentUseMPD || 2 == fCurrentUseMPD);
864 log->configOption("multi_picture_draw", fUseMPDs[fCurrentUseMPD-1] ? "true" : "false");
865 }
mtklein92007582014-08-01 07:46:52 -0700866 }
mtklein051e56d2014-12-04 08:46:51 -0800867 if (0 == strcmp(fBenchType, "recording")) {
868 log->metric("bytes", fSKPBytes);
869 log->metric("ops", fSKPOps);
870 }
mtklein92007582014-08-01 07:46:52 -0700871 }
872
mtkleine714e752014-07-31 12:13:48 -0700873private:
msarettb23e6aa2015-06-09 13:56:10 -0700874 enum SubsetType {
875 kTopLeft_SubsetType = 0,
876 kTopRight_SubsetType = 1,
877 kBottomLeft_SubsetType = 2,
878 kBottomRight_SubsetType = 3,
879 k2x2_SubsetType = 4,
880 k3x3_SubsetType = 5,
881 kTranslate_SubsetType = 6,
882 kZoom_SubsetType = 7,
883 kLast_SubsetType = kZoom_SubsetType
884 };
885
mtkleine714e752014-07-31 12:13:48 -0700886 const BenchRegistry* fBenches;
887 const skiagm::GMRegistry* fGMs;
mtklein92007582014-08-01 07:46:52 -0700888 SkIRect fClip;
889 SkTArray<SkScalar> fScales;
890 SkTArray<SkString> fSKPs;
robertphillips5b693772014-11-21 06:19:36 -0800891 SkTArray<bool> fUseMPDs;
msarett95f192d2015-02-13 09:05:41 -0800892 SkTArray<SkString> fImages;
893 SkTArray<SkColorType> fColorTypes;
joshualitt261c3ad2015-04-27 09:16:57 -0700894 SkScalar fZoomScale;
895 int fZoomSteps;
mtklein92007582014-08-01 07:46:52 -0700896
mtklein051e56d2014-12-04 08:46:51 -0800897 double fSKPBytes, fSKPOps;
898
mtkleinfd731ce2014-09-10 12:19:30 -0700899 const char* fSourceType; // What we're benching: bench, GM, SKP, ...
900 const char* fBenchType; // How we bench it: micro, recording, playback, ...
901 int fCurrentRecording;
mtklein92007582014-08-01 07:46:52 -0700902 int fCurrentScale;
903 int fCurrentSKP;
robertphillips5b693772014-11-21 06:19:36 -0800904 int fCurrentUseMPD;
scroggo60869a42015-04-01 12:09:17 -0700905 int fCurrentCodec;
msarett95f192d2015-02-13 09:05:41 -0800906 int fCurrentImage;
907 int fCurrentSubsetImage;
908 int fCurrentColorType;
msarettb23e6aa2015-06-09 13:56:10 -0700909 int fCurrentSubsetType;
910 int fUseCodec;
joshualitt261c3ad2015-04-27 09:16:57 -0700911 int fCurrentAnimSKP;
mtkleine714e752014-07-31 12:13:48 -0700912};
913
jcgregorio3b27ade2014-11-13 08:06:40 -0800914int nanobench_main();
caryclark17f0b6d2014-07-22 10:15:34 -0700915int nanobench_main() {
jcgregorio3b27ade2014-11-13 08:06:40 -0800916 SetupCrashHandler();
mtkleinf3723212014-06-25 14:08:00 -0700917 SkAutoGraphics ag;
mtklein4f108442014-12-03 13:07:39 -0800918 SkTaskGroup::Enabler enabled;
mtkleinf3723212014-06-25 14:08:00 -0700919
krajcevski69a55602014-08-13 10:46:31 -0700920#if SK_SUPPORT_GPU
bsalomon682c2692015-05-22 14:01:46 -0700921 GrContextOptions grContextOpts;
krajcevski12b35442014-08-13 12:06:26 -0700922 grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks;
923 gGrFactory.reset(SkNEW_ARGS(GrContextFactory, (grContextOpts)));
krajcevski69a55602014-08-13 10:46:31 -0700924#endif
925
bsalomon06cddec2014-10-24 10:40:50 -0700926 if (FLAGS_veryVerbose) {
927 FLAGS_verbose = true;
928 }
929
bsalomon6eb03cc2014-08-07 14:28:50 -0700930 if (kAutoTuneLoops != FLAGS_loops) {
mtkleina189ccd2014-07-14 12:28:47 -0700931 FLAGS_samples = 1;
932 FLAGS_gpuFrameLag = 0;
933 }
934
bsalomon6eb03cc2014-08-07 14:28:50 -0700935 if (!FLAGS_writePath.isEmpty()) {
936 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]);
937 if (!sk_mkdir(FLAGS_writePath[0])) {
938 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_writePath[0]);
939 FLAGS_writePath.set(0, NULL);
940 }
941 }
942
mtklein1915b622014-08-20 11:45:00 -0700943 SkAutoTDelete<ResultsWriter> log(SkNEW(ResultsWriter));
mtklein60317d0f2014-07-14 11:30:37 -0700944 if (!FLAGS_outResultsFile.isEmpty()) {
mtklein1915b622014-08-20 11:45:00 -0700945 log.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0])));
mtklein60317d0f2014-07-14 11:30:37 -0700946 }
mtklein1915b622014-08-20 11:45:00 -0700947
948 if (1 == FLAGS_properties.count() % 2) {
949 SkDebugf("ERROR: --properties must be passed with an even number of arguments.\n");
950 return 1;
951 }
952 for (int i = 1; i < FLAGS_properties.count(); i += 2) {
953 log->property(FLAGS_properties[i-1], FLAGS_properties[i]);
954 }
jcgregoriobf5e5232014-07-17 13:14:16 -0700955
956 if (1 == FLAGS_key.count() % 2) {
957 SkDebugf("ERROR: --key must be passed with an even number of arguments.\n");
958 return 1;
959 }
960 for (int i = 1; i < FLAGS_key.count(); i += 2) {
mtklein1915b622014-08-20 11:45:00 -0700961 log->key(FLAGS_key[i-1], FLAGS_key[i]);
mtklein94e51562014-08-19 12:41:53 -0700962 }
mtklein60317d0f2014-07-14 11:30:37 -0700963
mtkleinf3723212014-06-25 14:08:00 -0700964 const double overhead = estimate_timer_overhead();
mtklein55b0ffc2014-07-17 08:38:23 -0700965 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
Mike Klein91294772014-07-16 19:59:32 -0400966
mtkleinbb6a0282014-07-01 08:43:42 -0700967 SkAutoTMalloc<double> samples(FLAGS_samples);
968
bsalomon6eb03cc2014-08-07 14:28:50 -0700969 if (kAutoTuneLoops != FLAGS_loops) {
970 SkDebugf("Fixed number of loops; times would only be misleading so we won't print them.\n");
mtkleina189ccd2014-07-14 12:28:47 -0700971 } else if (FLAGS_verbose) {
mtkleinf3723212014-06-25 14:08:00 -0700972 // No header.
973 } else if (FLAGS_quiet) {
mtklein40b32be2014-07-09 08:46:49 -0700974 SkDebugf("median\tbench\tconfig\n");
mtkleinf3723212014-06-25 14:08:00 -0700975 } else {
mtkleind75c4662015-04-30 07:11:22 -0700976 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n",
qiankun.miao8247ec32014-09-09 19:24:36 -0700977 FLAGS_samples, "samples");
mtkleinf3723212014-06-25 14:08:00 -0700978 }
979
bsalomonc2553372014-07-22 13:09:05 -0700980 SkTDArray<Config> configs;
981 create_configs(&configs);
982
mtkleine070c2b2014-10-14 08:40:43 -0700983 int runs = 0;
mtklein92007582014-08-01 07:46:52 -0700984 BenchmarkStream benchStream;
985 while (Benchmark* b = benchStream.next()) {
mtkleine714e752014-07-31 12:13:48 -0700986 SkAutoTDelete<Benchmark> bench(b);
mtklein96289052014-09-10 12:05:59 -0700987 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getUniqueName())) {
mtkleinf3723212014-06-25 14:08:00 -0700988 continue;
989 }
990
mtkleinbb6a0282014-07-01 08:43:42 -0700991 SkTDArray<Target*> targets;
bsalomonc2553372014-07-22 13:09:05 -0700992 create_targets(&targets, bench.get(), configs);
mtkleinf3723212014-06-25 14:08:00 -0700993
jcgregoriobf5e5232014-07-17 13:14:16 -0700994 if (!targets.isEmpty()) {
mtklein96289052014-09-10 12:05:59 -0700995 log->bench(bench->getUniqueName(), bench->getSize().fX, bench->getSize().fY);
jcgregoriobf5e5232014-07-17 13:14:16 -0700996 bench->preDraw();
997 }
mtkleinbb6a0282014-07-01 08:43:42 -0700998 for (int j = 0; j < targets.count(); j++) {
tomhudsond968a6f2015-03-26 11:28:06 -0700999 // During HWUI output this canvas may be NULL.
tomhudson75a0ebb2015-03-27 12:11:44 -07001000 SkCanvas* canvas = targets[j]->getCanvas();
bsalomonc2553372014-07-22 13:09:05 -07001001 const char* config = targets[j]->config.name;
mtkleinf3723212014-06-25 14:08:00 -07001002
tomhudsond968a6f2015-03-26 11:28:06 -07001003 targets[j]->setup();
robertphillips5b693772014-11-21 06:19:36 -08001004 bench->perCanvasPreDraw(canvas);
1005
mtkleinbb6a0282014-07-01 08:43:42 -07001006 const int loops =
tomhudsond968a6f2015-03-26 11:28:06 -07001007 targets[j]->needsFrameTiming()
tomhudson75a0ebb2015-03-27 12:11:44 -07001008 ? gpu_bench(targets[j], bench.get(), samples.get())
1009 : cpu_bench(overhead, targets[j], bench.get(), samples.get());
mtkleinf3723212014-06-25 14:08:00 -07001010
robertphillips5b693772014-11-21 06:19:36 -08001011 bench->perCanvasPostDraw(canvas);
1012
tomhudsond968a6f2015-03-26 11:28:06 -07001013 if (Benchmark::kNonRendering_Backend != targets[j]->config.backend &&
1014 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
bsalomon6eb03cc2014-08-07 14:28:50 -07001015 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config);
mtklein96289052014-09-10 12:05:59 -07001016 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName());
bsalomon6eb03cc2014-08-07 14:28:50 -07001017 pngFilename.append(".png");
tomhudsond968a6f2015-03-26 11:28:06 -07001018 write_canvas_png(targets[j], pngFilename);
bsalomon6eb03cc2014-08-07 14:28:50 -07001019 }
1020
1021 if (kFailedLoops == loops) {
mtklein2069e222014-08-04 13:57:39 -07001022 // Can't be timed. A warning note has already been printed.
Mike Kleine3631362014-07-15 17:56:37 -04001023 continue;
1024 }
1025
mtkleinf3723212014-06-25 14:08:00 -07001026 Stats stats(samples.get(), FLAGS_samples);
mtklein1915b622014-08-20 11:45:00 -07001027 log->config(config);
mtklein96289052014-09-10 12:05:59 -07001028 log->configOption("name", bench->getName());
mtklein1915b622014-08-20 11:45:00 -07001029 benchStream.fillCurrentOptions(log.get());
tomhudsond968a6f2015-03-26 11:28:06 -07001030 targets[j]->fillOptions(log.get());
mtklein051e56d2014-12-04 08:46:51 -08001031 log->metric("min_ms", stats.min);
mtkleine070c2b2014-10-14 08:40:43 -07001032 if (runs++ % FLAGS_flushEvery == 0) {
1033 log->flush();
1034 }
mtklein60317d0f2014-07-14 11:30:37 -07001035
bsalomon6eb03cc2014-08-07 14:28:50 -07001036 if (kAutoTuneLoops != FLAGS_loops) {
mtkleina189ccd2014-07-14 12:28:47 -07001037 if (targets.count() == 1) {
1038 config = ""; // Only print the config if we run the same bench on more than one.
1039 }
mtkleind75c4662015-04-30 07:11:22 -07001040 SkDebugf("%4d/%-4dMB\t%s\t%s\n"
1041 , sk_tools::getCurrResidentSetSizeMB()
1042 , sk_tools::getMaxResidentSetSizeMB()
mtklein53d25622014-09-18 07:39:42 -07001043 , bench->getUniqueName()
1044 , config);
mtkleina189ccd2014-07-14 12:28:47 -07001045 } else if (FLAGS_verbose) {
mtkleinf3723212014-06-25 14:08:00 -07001046 for (int i = 0; i < FLAGS_samples; i++) {
mtklein55b0ffc2014-07-17 08:38:23 -07001047 SkDebugf("%s ", HUMANIZE(samples[i]));
mtkleinf3723212014-06-25 14:08:00 -07001048 }
mtklein96289052014-09-10 12:05:59 -07001049 SkDebugf("%s\n", bench->getUniqueName());
mtkleinf3723212014-06-25 14:08:00 -07001050 } else if (FLAGS_quiet) {
mtkleinbb6a0282014-07-01 08:43:42 -07001051 if (targets.count() == 1) {
mtkleinf3723212014-06-25 14:08:00 -07001052 config = ""; // Only print the config if we run the same bench on more than one.
1053 }
mtklein96289052014-09-10 12:05:59 -07001054 SkDebugf("%s\t%s\t%s\n", HUMANIZE(stats.median), bench->getUniqueName(), config);
mtkleinf3723212014-06-25 14:08:00 -07001055 } else {
1056 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean;
mtkleind75c4662015-04-30 07:11:22 -07001057 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n"
1058 , sk_tools::getCurrResidentSetSizeMB()
1059 , sk_tools::getMaxResidentSetSizeMB()
mtkleinf3723212014-06-25 14:08:00 -07001060 , loops
mtklein55b0ffc2014-07-17 08:38:23 -07001061 , HUMANIZE(stats.min)
1062 , HUMANIZE(stats.median)
1063 , HUMANIZE(stats.mean)
1064 , HUMANIZE(stats.max)
mtkleinf3723212014-06-25 14:08:00 -07001065 , stddev_percent
mtklein5d9d10e2014-07-11 11:57:07 -07001066 , stats.plot.c_str()
mtkleinf3723212014-06-25 14:08:00 -07001067 , config
mtklein96289052014-09-10 12:05:59 -07001068 , bench->getUniqueName()
mtkleinf3723212014-06-25 14:08:00 -07001069 );
1070 }
bsalomonb12ea412015-02-02 21:19:50 -08001071#if SK_SUPPORT_GPU
1072 if (FLAGS_gpuStats &&
bsalomon06cddec2014-10-24 10:40:50 -07001073 Benchmark::kGPU_Backend == targets[j]->config.backend) {
mtklein6838d852014-10-29 14:15:10 -07001074 gGrFactory->get(targets[j]->config.ctxType)->printCacheStats();
bsalomonb12ea412015-02-02 21:19:50 -08001075 gGrFactory->get(targets[j]->config.ctxType)->printGpuStats();
bsalomon06cddec2014-10-24 10:40:50 -07001076 }
1077#endif
mtkleinf3723212014-06-25 14:08:00 -07001078 }
mtkleinbb6a0282014-07-01 08:43:42 -07001079 targets.deleteAll();
Mike Klein3944a1d2014-07-15 13:40:19 -04001080
bsalomon06cddec2014-10-24 10:40:50 -07001081#if SK_SUPPORT_GPU
bsalomon2354f842014-07-28 13:48:36 -07001082 if (FLAGS_abandonGpuContext) {
krajcevski69a55602014-08-13 10:46:31 -07001083 gGrFactory->abandonContexts();
bsalomon2354f842014-07-28 13:48:36 -07001084 }
1085 if (FLAGS_resetGpuContext || FLAGS_abandonGpuContext) {
krajcevski69a55602014-08-13 10:46:31 -07001086 gGrFactory->destroyContexts();
Mike Klein3944a1d2014-07-15 13:40:19 -04001087 }
bsalomon06cddec2014-10-24 10:40:50 -07001088#endif
mtkleinf3723212014-06-25 14:08:00 -07001089 }
1090
mtkleine1091452014-12-04 10:47:02 -08001091 log->bench("memory_usage", 0,0);
1092 log->config("meta");
1093 log->metric("max_rss_mb", sk_tools::getMaxResidentSetSizeMB());
1094
joshualitte0b19d42015-03-26 10:41:02 -07001095#if SK_SUPPORT_GPU
1096 // Make sure we clean up the global GrContextFactory here, otherwise we might race with the
1097 // SkEventTracer destructor
1098 gGrFactory.reset(NULL);
1099#endif
1100
mtkleinf3723212014-06-25 14:08:00 -07001101 return 0;
1102}
1103
jcgregorio3b27ade2014-11-13 08:06:40 -08001104#if !defined SK_BUILD_FOR_IOS
1105int main(int argc, char** argv) {
1106 SkCommandLineFlags::Parse(argc, argv);
1107 return nanobench_main();
1108}
1109#endif