blob: 2dfd33f594abea06cf4034dc34ffcafc0b7687a4 [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
mtkleinf3723212014-06-25 14:08:00 -070010#include "Benchmark.h"
11#include "CrashHandler.h"
mtkleine714e752014-07-31 12:13:48 -070012#include "GMBench.h"
mtklein60317d0f2014-07-14 11:30:37 -070013#include "ResultsWriter.h"
mtklein92007582014-08-01 07:46:52 -070014#include "SKPBench.h"
mtkleinf3723212014-06-25 14:08:00 -070015#include "Stats.h"
16#include "Timer.h"
17
mtklein92007582014-08-01 07:46:52 -070018#include "SkOSFile.h"
mtkleinf3723212014-06-25 14:08:00 -070019#include "SkCanvas.h"
caryclark17f0b6d2014-07-22 10:15:34 -070020#include "SkCommonFlags.h"
mtkleinf3723212014-06-25 14:08:00 -070021#include "SkForceLinking.h"
22#include "SkGraphics.h"
23#include "SkString.h"
24#include "SkSurface.h"
25
mtkleinbb6a0282014-07-01 08:43:42 -070026#if SK_SUPPORT_GPU
jcgregoriobf5e5232014-07-17 13:14:16 -070027 #include "gl/GrGLDefines.h"
mtkleinbb6a0282014-07-01 08:43:42 -070028 #include "GrContextFactory.h"
29 GrContextFactory gGrFactory;
30#endif
31
mtkleinf3723212014-06-25 14:08:00 -070032__SK_FORCE_IMAGE_DECODER_LINKING;
33
mtkleina189ccd2014-07-14 12:28:47 -070034#if SK_DEBUG
35 DEFINE_bool(runOnce, true, "Run each benchmark just once?");
36#else
37 DEFINE_bool(runOnce, false, "Run each benchmark just once?");
38#endif
39
mtkleinf3723212014-06-25 14:08:00 -070040DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
41DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
42DEFINE_double(overheadGoal, 0.0001,
43 "Loop until timer overhead is at most this fraction of our measurments.");
mtkleinbb6a0282014-07-01 08:43:42 -070044DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
45DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
mtkleinf3723212014-06-25 14:08:00 -070046
mtklein60317d0f2014-07-14 11:30:37 -070047DEFINE_string(outResultsFile, "", "If given, write results here as JSON.");
mtklein55b0ffc2014-07-17 08:38:23 -070048DEFINE_int32(maxCalibrationAttempts, 3,
49 "Try up to this many times to guess loops for a bench, or skip the bench.");
50DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this.");
jcgregoriobf5e5232014-07-17 13:14:16 -070051DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON.");
52DEFINE_string(gitHash, "", "Git hash to add to JSON.");
mtklein60317d0f2014-07-14 11:30:37 -070053
mtklein92007582014-08-01 07:46:52 -070054DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs.");
55DEFINE_string(scales, "1.0", "Space-separated scales for SKPs.");
56
mtkleinf3723212014-06-25 14:08:00 -070057static SkString humanize(double ms) {
58 if (ms > 1e+3) return SkStringPrintf("%.3gs", ms/1e3);
59 if (ms < 1e-3) return SkStringPrintf("%.3gns", ms*1e6);
mtklein62386882014-07-15 10:30:31 -070060#ifdef SK_BUILD_FOR_WIN
61 if (ms < 1) return SkStringPrintf("%.3gus", ms*1e3);
62#else
mtkleinf3723212014-06-25 14:08:00 -070063 if (ms < 1) return SkStringPrintf("%.3gµs", ms*1e3);
mtklein62386882014-07-15 10:30:31 -070064#endif
mtkleinf3723212014-06-25 14:08:00 -070065 return SkStringPrintf("%.3gms", ms);
66}
mtklein55b0ffc2014-07-17 08:38:23 -070067#define HUMANIZE(ms) humanize(ms).c_str()
mtkleinf3723212014-06-25 14:08:00 -070068
mtkleinbb6a0282014-07-01 08:43:42 -070069static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContextHelper* gl) {
70 WallTimer timer;
71 timer.start();
72 if (bench) {
73 bench->draw(loops, canvas);
74 }
75 if (canvas) {
76 canvas->flush();
77 }
78#if SK_SUPPORT_GPU
79 if (gl) {
80 SK_GL(*gl, Flush());
81 gl->swapBuffers();
82 }
83#endif
84 timer.end();
85 return timer.fWall;
86}
87
mtkleinf3723212014-06-25 14:08:00 -070088static double estimate_timer_overhead() {
89 double overhead = 0;
mtkleinf3723212014-06-25 14:08:00 -070090 for (int i = 0; i < FLAGS_overheadLoops; i++) {
mtkleinbb6a0282014-07-01 08:43:42 -070091 overhead += time(1, NULL, NULL, NULL);
mtkleinf3723212014-06-25 14:08:00 -070092 }
93 return overhead / FLAGS_overheadLoops;
94}
95
mtklein55b0ffc2014-07-17 08:38:23 -070096static int clamp_loops(int loops) {
97 if (loops < 1) {
98 SkDebugf("ERROR: clamping loops from %d to 1.\n", loops);
99 return 1;
100 }
101 if (loops > FLAGS_maxLoops) {
102 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops);
103 return FLAGS_maxLoops;
104 }
105 return loops;
106}
107
mtkleinbb6a0282014-07-01 08:43:42 -0700108static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas, double* samples) {
109 // First figure out approximately how many loops of bench it takes to make overhead negligible.
mtklein2069e222014-08-04 13:57:39 -0700110 double bench_plus_overhead = 0.0;
mtklein55b0ffc2014-07-17 08:38:23 -0700111 int round = 0;
mtklein2069e222014-08-04 13:57:39 -0700112 while (bench_plus_overhead < overhead) {
113 if (round++ == FLAGS_maxCalibrationAttempts) {
mtklein55b0ffc2014-07-17 08:38:23 -0700114 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
115 bench->getName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
116 return 0;
117 }
mtklein2069e222014-08-04 13:57:39 -0700118 bench_plus_overhead = time(1, bench, canvas, NULL);
119 }
mtkleinf3723212014-06-25 14:08:00 -0700120
mtkleinbb6a0282014-07-01 08:43:42 -0700121 // Later we'll just start and stop the timer once but loop N times.
mtkleinf3723212014-06-25 14:08:00 -0700122 // We'll pick N to make timer overhead negligible:
123 //
mtkleinbb6a0282014-07-01 08:43:42 -0700124 // overhead
125 // ------------------------- < FLAGS_overheadGoal
126 // overhead + N * Bench Time
mtkleinf3723212014-06-25 14:08:00 -0700127 //
mtkleinbb6a0282014-07-01 08:43:42 -0700128 // where bench_plus_overhead ≈ overhead + Bench Time.
mtkleinf3723212014-06-25 14:08:00 -0700129 //
130 // Doing some math, we get:
131 //
mtkleinbb6a0282014-07-01 08:43:42 -0700132 // (overhead / FLAGS_overheadGoal) - overhead
133 // ------------------------------------------ < N
134 // bench_plus_overhead - overhead)
mtkleinf3723212014-06-25 14:08:00 -0700135 //
136 // Luckily, this also works well in practice. :)
137 const double numer = overhead / FLAGS_overheadGoal - overhead;
mtkleinbb6a0282014-07-01 08:43:42 -0700138 const double denom = bench_plus_overhead - overhead;
mtklein55b0ffc2014-07-17 08:38:23 -0700139 const int loops = clamp_loops(FLAGS_runOnce ? 1 : (int)ceil(numer / denom));
mtkleinbb6a0282014-07-01 08:43:42 -0700140
141 for (int i = 0; i < FLAGS_samples; i++) {
142 samples[i] = time(loops, bench, canvas, NULL) / loops;
143 }
144 return loops;
mtkleinf3723212014-06-25 14:08:00 -0700145}
146
mtkleinbb6a0282014-07-01 08:43:42 -0700147#if SK_SUPPORT_GPU
148static int gpu_bench(SkGLContextHelper* gl,
149 Benchmark* bench,
150 SkCanvas* canvas,
151 double* samples) {
bsalomonc2553372014-07-22 13:09:05 -0700152 gl->makeCurrent();
mtkleinbb6a0282014-07-01 08:43:42 -0700153 // Make sure we're done with whatever came before.
mtklein9bc86ed2014-07-01 10:02:42 -0700154 SK_GL(*gl, Finish());
mtkleinbb6a0282014-07-01 08:43:42 -0700155
156 // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
157 int loops = 1;
mtkleina189ccd2014-07-14 12:28:47 -0700158 if (!FLAGS_runOnce) {
159 double elapsed = 0;
160 do {
161 loops *= 2;
162 // If the GPU lets frames lag at all, we need to make sure we're timing
163 // _this_ round, not still timing last round. We force this by looping
164 // more times than any reasonable GPU will allow frames to lag.
165 for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
166 elapsed = time(loops, bench, canvas, gl);
167 }
168 } while (elapsed < FLAGS_gpuMs);
mtkleinbb6a0282014-07-01 08:43:42 -0700169
mtkleina189ccd2014-07-14 12:28:47 -0700170 // We've overshot at least a little. Scale back linearly.
171 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed);
mtkleinbb6a0282014-07-01 08:43:42 -0700172
mtkleina189ccd2014-07-14 12:28:47 -0700173 // Might as well make sure we're not still timing our calibration.
174 SK_GL(*gl, Finish());
175 }
mtklein55b0ffc2014-07-17 08:38:23 -0700176 loops = clamp_loops(loops);
mtkleinbb6a0282014-07-01 08:43:42 -0700177
178 // Pretty much the same deal as the calibration: do some warmup to make
179 // sure we're timing steady-state pipelined frames.
180 for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
181 time(loops, bench, canvas, gl);
mtkleinf3723212014-06-25 14:08:00 -0700182 }
mtkleinbb6a0282014-07-01 08:43:42 -0700183
184 // Now, actually do the timing!
185 for (int i = 0; i < FLAGS_samples; i++) {
186 samples[i] = time(loops, bench, canvas, gl) / loops;
187 }
188 return loops;
189}
190#endif
191
192static SkString to_lower(const char* str) {
193 SkString lower(str);
194 for (size_t i = 0; i < lower.size(); i++) {
195 lower[i] = tolower(lower[i]);
196 }
197 return lower;
mtkleinf3723212014-06-25 14:08:00 -0700198}
199
bsalomonc2553372014-07-22 13:09:05 -0700200struct Config {
201 const char* name;
mtkleinbb6a0282014-07-01 08:43:42 -0700202 Benchmark::Backend backend;
bsalomonc2553372014-07-22 13:09:05 -0700203 SkColorType color;
204 SkAlphaType alpha;
205 int samples;
206#if SK_SUPPORT_GPU
207 GrContextFactory::GLContextType ctxType;
208#else
209 int bogusInt;
210#endif
211};
212
213struct Target {
214 explicit Target(const Config& c) : config(c) {}
215 const Config config;
mtkleinbb6a0282014-07-01 08:43:42 -0700216 SkAutoTDelete<SkSurface> surface;
217#if SK_SUPPORT_GPU
218 SkGLContextHelper* gl;
219#endif
220};
mtkleinf3723212014-06-25 14:08:00 -0700221
bsalomonc2553372014-07-22 13:09:05 -0700222static bool is_cpu_config_allowed(const char* name) {
mtkleinbb6a0282014-07-01 08:43:42 -0700223 for (int i = 0; i < FLAGS_config.count(); i++) {
bsalomonc2553372014-07-22 13:09:05 -0700224 if (to_lower(FLAGS_config[i]).equals(name)) {
225 return true;
mtkleinf3723212014-06-25 14:08:00 -0700226 }
227 }
bsalomonc2553372014-07-22 13:09:05 -0700228 return false;
mtkleinbb6a0282014-07-01 08:43:42 -0700229}
230
bsalomonc2553372014-07-22 13:09:05 -0700231#if SK_SUPPORT_GPU
232static bool is_gpu_config_allowed(const char* name, GrContextFactory::GLContextType ctxType,
233 int sampleCnt) {
234 if (!is_cpu_config_allowed(name)) {
235 return false;
236 }
237 if (const GrContext* ctx = gGrFactory.get(ctxType)) {
238 return sampleCnt <= ctx->getMaxSampleCount();
239 }
240 return false;
241}
242#endif
mtkleinbb6a0282014-07-01 08:43:42 -0700243
bsalomonc2553372014-07-22 13:09:05 -0700244#if SK_SUPPORT_GPU
245#define kBogusGLContextType GrContextFactory::kNative_GLContextType
246#else
247#define kBogusGLContextType 0
mtkleine714e752014-07-31 12:13:48 -0700248#endif
bsalomonc2553372014-07-22 13:09:05 -0700249
250// Append all configs that are enabled and supported.
251static void create_configs(SkTDArray<Config>* configs) {
252 #define CPU_CONFIG(name, backend, color, alpha) \
253 if (is_cpu_config_allowed(#name)) { \
254 Config config = { #name, Benchmark::backend, color, alpha, 0, kBogusGLContextType }; \
255 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700256 }
mtkleine714e752014-07-31 12:13:48 -0700257
mtklein40b32be2014-07-09 08:46:49 -0700258 if (FLAGS_cpu) {
bsalomonc2553372014-07-22 13:09:05 -0700259 CPU_CONFIG(nonrendering, kNonRendering_Backend, kUnknown_SkColorType, kUnpremul_SkAlphaType)
260 CPU_CONFIG(8888, kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType)
261 CPU_CONFIG(565, kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType)
mtklein40b32be2014-07-09 08:46:49 -0700262 }
mtkleinbb6a0282014-07-01 08:43:42 -0700263
264#if SK_SUPPORT_GPU
bsalomonc2553372014-07-22 13:09:05 -0700265 #define GPU_CONFIG(name, ctxType, samples) \
266 if (is_gpu_config_allowed(#name, GrContextFactory::ctxType, samples)) { \
267 Config config = { \
268 #name, \
269 Benchmark::kGPU_Backend, \
270 kN32_SkColorType, \
271 kPremul_SkAlphaType, \
272 samples, \
273 GrContextFactory::ctxType }; \
274 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700275 }
mtkleine714e752014-07-31 12:13:48 -0700276
mtklein40b32be2014-07-09 08:46:49 -0700277 if (FLAGS_gpu) {
bsalomonc2553372014-07-22 13:09:05 -0700278 GPU_CONFIG(gpu, kNative_GLContextType, 0)
279 GPU_CONFIG(msaa4, kNative_GLContextType, 4)
280 GPU_CONFIG(msaa16, kNative_GLContextType, 16)
281 GPU_CONFIG(nvprmsaa4, kNVPR_GLContextType, 4)
282 GPU_CONFIG(nvprmsaa16, kNVPR_GLContextType, 16)
283 GPU_CONFIG(debug, kDebug_GLContextType, 0)
284 GPU_CONFIG(nullgpu, kNull_GLContextType, 0)
mtklein40b32be2014-07-09 08:46:49 -0700285 }
mtkleinbb6a0282014-07-01 08:43:42 -0700286#endif
mtkleinf3723212014-06-25 14:08:00 -0700287}
288
bsalomonc2553372014-07-22 13:09:05 -0700289// If bench is enabled for config, returns a Target* for it, otherwise NULL.
290static Target* is_enabled(Benchmark* bench, const Config& config) {
291 if (!bench->isSuitableFor(config.backend)) {
292 return NULL;
293 }
294
295 SkImageInfo info;
296 info.fAlphaType = config.alpha;
297 info.fColorType = config.color;
298 info.fWidth = bench->getSize().fX;
299 info.fHeight = bench->getSize().fY;
300
301 Target* target = new Target(config);
302
303 if (Benchmark::kRaster_Backend == config.backend) {
304 target->surface.reset(SkSurface::NewRaster(info));
305 }
306#if SK_SUPPORT_GPU
307 else if (Benchmark::kGPU_Backend == config.backend) {
308 target->surface.reset(SkSurface::NewRenderTarget(gGrFactory.get(config.ctxType), info,
309 config.samples));
310 target->gl = gGrFactory.getGLContext(config.ctxType);
311 }
312#endif
313
314 if (Benchmark::kNonRendering_Backend != config.backend && !target->surface.get()) {
315 delete target;
316 return NULL;
317 }
318 return target;
319}
320
321// Creates targets for a benchmark and a set of configs.
322static void create_targets(SkTDArray<Target*>* targets, Benchmark* b,
323 const SkTDArray<Config>& configs) {
324 for (int i = 0; i < configs.count(); ++i) {
325 if (Target* t = is_enabled(b, configs[i])) {
326 targets->push(t);
327 }
mtkleine714e752014-07-31 12:13:48 -0700328
bsalomonc2553372014-07-22 13:09:05 -0700329 }
330}
331
mtklein60317d0f2014-07-14 11:30:37 -0700332static void fill_static_options(ResultsWriter* log) {
333#if defined(SK_BUILD_FOR_WIN32)
334 log->option("system", "WIN32");
335#elif defined(SK_BUILD_FOR_MAC)
336 log->option("system", "MAC");
337#elif defined(SK_BUILD_FOR_ANDROID)
338 log->option("system", "ANDROID");
339#elif defined(SK_BUILD_FOR_UNIX)
340 log->option("system", "UNIX");
341#else
342 log->option("system", "other");
343#endif
mtklein60317d0f2014-07-14 11:30:37 -0700344}
345
jcgregoriobf5e5232014-07-17 13:14:16 -0700346#if SK_SUPPORT_GPU
347static void fill_gpu_options(ResultsWriter* log, SkGLContextHelper* ctx) {
jcgregorio05c45602014-07-17 13:54:36 -0700348 const GrGLubyte* version;
jcgregoriobf5e5232014-07-17 13:14:16 -0700349 SK_GL_RET(*ctx, version, GetString(GR_GL_VERSION));
350 log->configOption("GL_VERSION", (const char*)(version));
351
352 SK_GL_RET(*ctx, version, GetString(GR_GL_RENDERER));
353 log->configOption("GL_RENDERER", (const char*) version);
354
355 SK_GL_RET(*ctx, version, GetString(GR_GL_VENDOR));
356 log->configOption("GL_VENDOR", (const char*) version);
357
358 SK_GL_RET(*ctx, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
359 log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
360}
361#endif
362
mtkleine714e752014-07-31 12:13:48 -0700363class BenchmarkStream {
364public:
mtklein92007582014-08-01 07:46:52 -0700365 BenchmarkStream() : fBenches(BenchRegistry::Head())
366 , fGMs(skiagm::GMRegistry::Head())
367 , fCurrentScale(0)
368 , fCurrentSKP(0) {
369 for (int i = 0; i < FLAGS_skps.count(); i++) {
370 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
371 fSKPs.push_back() = FLAGS_skps[i];
372 } else {
373 SkOSFile::Iter it(FLAGS_skps[i], ".skp");
374 SkString path;
375 while (it.next(&path)) {
376 fSKPs.push_back() = SkOSPath::Join(FLAGS_skps[0], path.c_str());
377 }
378 }
379 }
mtkleine714e752014-07-31 12:13:48 -0700380
mtklein92007582014-08-01 07:46:52 -0700381 if (4 != sscanf(FLAGS_clip[0], "%d,%d,%d,%d",
382 &fClip.fLeft, &fClip.fTop, &fClip.fRight, &fClip.fBottom)) {
383 SkDebugf("Can't parse %s from --clip as an SkIRect.\n", FLAGS_clip[0]);
384 exit(1);
385 }
386
387 for (int i = 0; i < FLAGS_scales.count(); i++) {
388 if (1 != sscanf(FLAGS_scales[i], "%f", &fScales.push_back())) {
389 SkDebugf("Can't parse %s from --scales as an SkScalar.\n", FLAGS_scales[i]);
390 exit(1);
391 }
392 }
393 }
394
395 Benchmark* next() {
mtkleine714e752014-07-31 12:13:48 -0700396 if (fBenches) {
397 Benchmark* bench = fBenches->factory()(NULL);
398 fBenches = fBenches->next();
mtklein92007582014-08-01 07:46:52 -0700399 fSourceType = "bench";
mtkleine714e752014-07-31 12:13:48 -0700400 return bench;
401 }
mtklein92007582014-08-01 07:46:52 -0700402
mtkleine714e752014-07-31 12:13:48 -0700403 while (fGMs) {
404 SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL));
405 fGMs = fGMs->next();
406 if (gm->getFlags() & skiagm::GM::kAsBench_Flag) {
mtklein92007582014-08-01 07:46:52 -0700407 fSourceType = "gm";
mtkleine714e752014-07-31 12:13:48 -0700408 return SkNEW_ARGS(GMBench, (gm.detach()));
409 }
410 }
mtklein92007582014-08-01 07:46:52 -0700411
412 while (fCurrentScale < fScales.count()) {
413 while (fCurrentSKP < fSKPs.count()) {
414 const SkString& path = fSKPs[fCurrentSKP++];
415
416 // Not strictly necessary, as it will be checked again later,
417 // but helps to avoid a lot of pointless work if we're going to skip it.
418 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path.c_str())) {
419 continue;
420 }
421
422 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path.c_str()));
423 if (stream.get() == NULL) {
424 SkDebugf("Could not read %s.\n", path.c_str());
425 exit(1);
426 }
427
428 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream.get()));
429 if (pic.get() == NULL) {
430 SkDebugf("Could not read %s as an SkPicture.\n", path.c_str());
431 exit(1);
432 }
433
434 SkString name = SkOSPath::Basename(path.c_str());
435
436 fSourceType = "skp";
437 return SkNEW_ARGS(SKPBench,
438 (name.c_str(), pic.get(), fClip, fScales[fCurrentScale]));
439 }
440 fCurrentSKP = 0;
441 fCurrentScale++;
442 }
443
mtkleine714e752014-07-31 12:13:48 -0700444 return NULL;
445 }
mtklein92007582014-08-01 07:46:52 -0700446
447 void fillCurrentOptions(ResultsWriter* log) const {
448 log->configOption("source_type", fSourceType);
449 if (0 == strcmp(fSourceType, "skp")) {
450 log->configOption("clip",
451 SkStringPrintf("%d %d %d %d", fClip.fLeft, fClip.fTop,
452 fClip.fRight, fClip.fBottom).c_str());
453 log->configOption("scale", SkStringPrintf("%.2g", fScales[fCurrentScale]).c_str());
454 }
455 }
456
mtkleine714e752014-07-31 12:13:48 -0700457private:
458 const BenchRegistry* fBenches;
459 const skiagm::GMRegistry* fGMs;
mtklein92007582014-08-01 07:46:52 -0700460 SkIRect fClip;
461 SkTArray<SkScalar> fScales;
462 SkTArray<SkString> fSKPs;
463
464 const char* fSourceType;
465 int fCurrentScale;
466 int fCurrentSKP;
mtkleine714e752014-07-31 12:13:48 -0700467};
468
caryclark17f0b6d2014-07-22 10:15:34 -0700469int nanobench_main();
470int nanobench_main() {
mtkleinf3723212014-06-25 14:08:00 -0700471 SetupCrashHandler();
472 SkAutoGraphics ag;
mtkleinf3723212014-06-25 14:08:00 -0700473
mtkleina189ccd2014-07-14 12:28:47 -0700474 if (FLAGS_runOnce) {
475 FLAGS_samples = 1;
476 FLAGS_gpuFrameLag = 0;
477 }
478
mtklein60317d0f2014-07-14 11:30:37 -0700479 MultiResultsWriter log;
jcgregoriobf5e5232014-07-17 13:14:16 -0700480 SkAutoTDelete<NanoJSONResultsWriter> json;
mtklein60317d0f2014-07-14 11:30:37 -0700481 if (!FLAGS_outResultsFile.isEmpty()) {
jcgregoriobf5e5232014-07-17 13:14:16 -0700482 const char* gitHash = FLAGS_gitHash.isEmpty() ? "unknown-revision" : FLAGS_gitHash[0];
483 json.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0], gitHash)));
mtklein60317d0f2014-07-14 11:30:37 -0700484 log.add(json.get());
485 }
486 CallEnd<MultiResultsWriter> ender(log);
jcgregoriobf5e5232014-07-17 13:14:16 -0700487
488 if (1 == FLAGS_key.count() % 2) {
489 SkDebugf("ERROR: --key must be passed with an even number of arguments.\n");
490 return 1;
491 }
492 for (int i = 1; i < FLAGS_key.count(); i += 2) {
493 log.key(FLAGS_key[i-1], FLAGS_key[i]);
494 }
mtklein60317d0f2014-07-14 11:30:37 -0700495 fill_static_options(&log);
496
mtkleinf3723212014-06-25 14:08:00 -0700497 const double overhead = estimate_timer_overhead();
mtklein55b0ffc2014-07-17 08:38:23 -0700498 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
Mike Klein91294772014-07-16 19:59:32 -0400499
mtkleinbb6a0282014-07-01 08:43:42 -0700500 SkAutoTMalloc<double> samples(FLAGS_samples);
501
mtkleina189ccd2014-07-14 12:28:47 -0700502 if (FLAGS_runOnce) {
503 SkDebugf("--runOnce is true; times would only be misleading so we won't print them.\n");
504 } else if (FLAGS_verbose) {
mtkleinf3723212014-06-25 14:08:00 -0700505 // No header.
506 } else if (FLAGS_quiet) {
mtklein40b32be2014-07-09 08:46:49 -0700507 SkDebugf("median\tbench\tconfig\n");
mtkleinf3723212014-06-25 14:08:00 -0700508 } else {
mtklein5d9d10e2014-07-11 11:57:07 -0700509 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\n");
mtkleinf3723212014-06-25 14:08:00 -0700510 }
511
bsalomonc2553372014-07-22 13:09:05 -0700512 SkTDArray<Config> configs;
513 create_configs(&configs);
514
mtklein92007582014-08-01 07:46:52 -0700515 BenchmarkStream benchStream;
516 while (Benchmark* b = benchStream.next()) {
mtkleine714e752014-07-31 12:13:48 -0700517 SkAutoTDelete<Benchmark> bench(b);
mtkleinf3723212014-06-25 14:08:00 -0700518 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
519 continue;
520 }
521
mtkleinbb6a0282014-07-01 08:43:42 -0700522 SkTDArray<Target*> targets;
bsalomonc2553372014-07-22 13:09:05 -0700523 create_targets(&targets, bench.get(), configs);
mtkleinf3723212014-06-25 14:08:00 -0700524
jcgregoriobf5e5232014-07-17 13:14:16 -0700525 if (!targets.isEmpty()) {
526 log.bench(bench->getName(), bench->getSize().fX, bench->getSize().fY);
527 bench->preDraw();
528 }
mtkleinbb6a0282014-07-01 08:43:42 -0700529 for (int j = 0; j < targets.count(); j++) {
530 SkCanvas* canvas = targets[j]->surface.get() ? targets[j]->surface->getCanvas() : NULL;
bsalomonc2553372014-07-22 13:09:05 -0700531 const char* config = targets[j]->config.name;
mtkleinf3723212014-06-25 14:08:00 -0700532
mtklein92007582014-08-01 07:46:52 -0700533#if SK_DEBUG
534 // skia:2797 Some SKPs SkASSERT in debug mode. Skip them for now.
mtklein6e33e232014-08-01 08:23:39 -0700535 if (0 == strcmp("565", config) && SkStrContains(bench->getName(), ".skp")) {
536 SkDebugf("Skipping 565 %s. See skia:2797\n", bench->getName());
mtklein92007582014-08-01 07:46:52 -0700537 continue;
538 }
539#endif
540
mtkleinbb6a0282014-07-01 08:43:42 -0700541 const int loops =
542#if SK_SUPPORT_GPU
bsalomonc2553372014-07-22 13:09:05 -0700543 Benchmark::kGPU_Backend == targets[j]->config.backend
mtkleinbb6a0282014-07-01 08:43:42 -0700544 ? gpu_bench(targets[j]->gl, bench.get(), canvas, samples.get())
545 :
546#endif
547 cpu_bench( overhead, bench.get(), canvas, samples.get());
mtkleinf3723212014-06-25 14:08:00 -0700548
Mike Kleine3631362014-07-15 17:56:37 -0400549 if (loops == 0) {
mtklein2069e222014-08-04 13:57:39 -0700550 // Can't be timed. A warning note has already been printed.
Mike Kleine3631362014-07-15 17:56:37 -0400551 continue;
552 }
553
mtkleinf3723212014-06-25 14:08:00 -0700554 Stats stats(samples.get(), FLAGS_samples);
mtklein60317d0f2014-07-14 11:30:37 -0700555 log.config(config);
mtklein92007582014-08-01 07:46:52 -0700556 benchStream.fillCurrentOptions(&log);
jcgregoriobf5e5232014-07-17 13:14:16 -0700557#if SK_SUPPORT_GPU
bsalomonc2553372014-07-22 13:09:05 -0700558 if (Benchmark::kGPU_Backend == targets[j]->config.backend) {
jcgregoriobf5e5232014-07-17 13:14:16 -0700559 fill_gpu_options(&log, targets[j]->gl);
560 }
561#endif
mtklein60317d0f2014-07-14 11:30:37 -0700562 log.timer("min_ms", stats.min);
563 log.timer("median_ms", stats.median);
564 log.timer("mean_ms", stats.mean);
565 log.timer("max_ms", stats.max);
566 log.timer("stddev_ms", sqrt(stats.var));
567
mtkleina189ccd2014-07-14 12:28:47 -0700568 if (FLAGS_runOnce) {
569 if (targets.count() == 1) {
570 config = ""; // Only print the config if we run the same bench on more than one.
571 }
572 SkDebugf("%s\t%s\n", bench->getName(), config);
573 } else if (FLAGS_verbose) {
mtkleinf3723212014-06-25 14:08:00 -0700574 for (int i = 0; i < FLAGS_samples; i++) {
mtklein55b0ffc2014-07-17 08:38:23 -0700575 SkDebugf("%s ", HUMANIZE(samples[i]));
mtkleinf3723212014-06-25 14:08:00 -0700576 }
577 SkDebugf("%s\n", bench->getName());
578 } else if (FLAGS_quiet) {
mtkleinbb6a0282014-07-01 08:43:42 -0700579 if (targets.count() == 1) {
mtkleinf3723212014-06-25 14:08:00 -0700580 config = ""; // Only print the config if we run the same bench on more than one.
581 }
mtklein55b0ffc2014-07-17 08:38:23 -0700582 SkDebugf("%s\t%s\t%s\n", HUMANIZE(stats.median), bench->getName(), config);
mtkleinf3723212014-06-25 14:08:00 -0700583 } else {
584 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean;
mtklein5d9d10e2014-07-11 11:57:07 -0700585 SkDebugf("%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n"
mtkleinf3723212014-06-25 14:08:00 -0700586 , loops
mtklein55b0ffc2014-07-17 08:38:23 -0700587 , HUMANIZE(stats.min)
588 , HUMANIZE(stats.median)
589 , HUMANIZE(stats.mean)
590 , HUMANIZE(stats.max)
mtkleinf3723212014-06-25 14:08:00 -0700591 , stddev_percent
mtklein5d9d10e2014-07-11 11:57:07 -0700592 , stats.plot.c_str()
mtkleinf3723212014-06-25 14:08:00 -0700593 , config
mtkleinbb6a0282014-07-01 08:43:42 -0700594 , bench->getName()
mtkleinf3723212014-06-25 14:08:00 -0700595 );
596 }
597 }
mtkleinbb6a0282014-07-01 08:43:42 -0700598 targets.deleteAll();
Mike Klein3944a1d2014-07-15 13:40:19 -0400599
600 #if SK_SUPPORT_GPU
bsalomon2354f842014-07-28 13:48:36 -0700601 if (FLAGS_abandonGpuContext) {
602 gGrFactory.abandonContexts();
603 }
604 if (FLAGS_resetGpuContext || FLAGS_abandonGpuContext) {
Mike Klein3944a1d2014-07-15 13:40:19 -0400605 gGrFactory.destroyContexts();
606 }
607 #endif
mtkleinf3723212014-06-25 14:08:00 -0700608 }
609
610 return 0;
611}
612
613#if !defined SK_BUILD_FOR_IOS
caryclark17f0b6d2014-07-22 10:15:34 -0700614int main(int argc, char** argv) {
615 SkCommandLineFlags::Parse(argc, argv);
616 return nanobench_main();
mtkleinf3723212014-06-25 14:08:00 -0700617}
618#endif