blob: 3cc03a805da678be64746f273b32d88c5d5d1b88 [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"
mtklein60317d0f2014-07-14 11:30:37 -070012#include "ResultsWriter.h"
mtkleinf3723212014-06-25 14:08:00 -070013#include "Stats.h"
14#include "Timer.h"
15
16#include "SkCanvas.h"
caryclark17f0b6d2014-07-22 10:15:34 -070017#include "SkCommonFlags.h"
mtkleinf3723212014-06-25 14:08:00 -070018#include "SkForceLinking.h"
19#include "SkGraphics.h"
20#include "SkString.h"
21#include "SkSurface.h"
22
mtkleinbb6a0282014-07-01 08:43:42 -070023#if SK_SUPPORT_GPU
jcgregoriobf5e5232014-07-17 13:14:16 -070024 #include "gl/GrGLDefines.h"
mtkleinbb6a0282014-07-01 08:43:42 -070025 #include "GrContextFactory.h"
26 GrContextFactory gGrFactory;
27#endif
28
mtkleinf3723212014-06-25 14:08:00 -070029__SK_FORCE_IMAGE_DECODER_LINKING;
30
mtkleina189ccd2014-07-14 12:28:47 -070031#if SK_DEBUG
32 DEFINE_bool(runOnce, true, "Run each benchmark just once?");
33#else
34 DEFINE_bool(runOnce, false, "Run each benchmark just once?");
35#endif
36
mtkleinf3723212014-06-25 14:08:00 -070037DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
38DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
39DEFINE_double(overheadGoal, 0.0001,
40 "Loop until timer overhead is at most this fraction of our measurments.");
mtkleinbb6a0282014-07-01 08:43:42 -070041DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
42DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
mtkleinf3723212014-06-25 14:08:00 -070043
mtklein60317d0f2014-07-14 11:30:37 -070044DEFINE_string(outResultsFile, "", "If given, write results here as JSON.");
mtklein55b0ffc2014-07-17 08:38:23 -070045DEFINE_int32(maxCalibrationAttempts, 3,
46 "Try up to this many times to guess loops for a bench, or skip the bench.");
47DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this.");
jcgregoriobf5e5232014-07-17 13:14:16 -070048DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON.");
49DEFINE_string(gitHash, "", "Git hash to add to JSON.");
mtklein60317d0f2014-07-14 11:30:37 -070050
mtkleinf3723212014-06-25 14:08:00 -070051static SkString humanize(double ms) {
52 if (ms > 1e+3) return SkStringPrintf("%.3gs", ms/1e3);
53 if (ms < 1e-3) return SkStringPrintf("%.3gns", ms*1e6);
mtklein62386882014-07-15 10:30:31 -070054#ifdef SK_BUILD_FOR_WIN
55 if (ms < 1) return SkStringPrintf("%.3gus", ms*1e3);
56#else
mtkleinf3723212014-06-25 14:08:00 -070057 if (ms < 1) return SkStringPrintf("%.3gµs", ms*1e3);
mtklein62386882014-07-15 10:30:31 -070058#endif
mtkleinf3723212014-06-25 14:08:00 -070059 return SkStringPrintf("%.3gms", ms);
60}
mtklein55b0ffc2014-07-17 08:38:23 -070061#define HUMANIZE(ms) humanize(ms).c_str()
mtkleinf3723212014-06-25 14:08:00 -070062
mtkleinbb6a0282014-07-01 08:43:42 -070063static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContextHelper* gl) {
64 WallTimer timer;
65 timer.start();
66 if (bench) {
67 bench->draw(loops, canvas);
68 }
69 if (canvas) {
70 canvas->flush();
71 }
72#if SK_SUPPORT_GPU
73 if (gl) {
74 SK_GL(*gl, Flush());
75 gl->swapBuffers();
76 }
77#endif
78 timer.end();
79 return timer.fWall;
80}
81
mtkleinf3723212014-06-25 14:08:00 -070082static double estimate_timer_overhead() {
83 double overhead = 0;
mtkleinf3723212014-06-25 14:08:00 -070084 for (int i = 0; i < FLAGS_overheadLoops; i++) {
mtkleinbb6a0282014-07-01 08:43:42 -070085 overhead += time(1, NULL, NULL, NULL);
mtkleinf3723212014-06-25 14:08:00 -070086 }
87 return overhead / FLAGS_overheadLoops;
88}
89
mtklein55b0ffc2014-07-17 08:38:23 -070090static int clamp_loops(int loops) {
91 if (loops < 1) {
92 SkDebugf("ERROR: clamping loops from %d to 1.\n", loops);
93 return 1;
94 }
95 if (loops > FLAGS_maxLoops) {
96 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops);
97 return FLAGS_maxLoops;
98 }
99 return loops;
100}
101
mtkleinbb6a0282014-07-01 08:43:42 -0700102static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas, double* samples) {
103 // First figure out approximately how many loops of bench it takes to make overhead negligible.
104 double bench_plus_overhead;
mtklein55b0ffc2014-07-17 08:38:23 -0700105 int round = 0;
mtkleinf3723212014-06-25 14:08:00 -0700106 do {
mtkleinbb6a0282014-07-01 08:43:42 -0700107 bench_plus_overhead = time(1, bench, canvas, NULL);
mtklein55b0ffc2014-07-17 08:38:23 -0700108 if (++round == FLAGS_maxCalibrationAttempts) {
109 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
110 bench->getName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
111 return 0;
112 }
Mike Kleine3631362014-07-15 17:56:37 -0400113 } while (bench_plus_overhead < overhead);
mtkleinf3723212014-06-25 14:08:00 -0700114
mtkleinbb6a0282014-07-01 08:43:42 -0700115 // Later we'll just start and stop the timer once but loop N times.
mtkleinf3723212014-06-25 14:08:00 -0700116 // We'll pick N to make timer overhead negligible:
117 //
mtkleinbb6a0282014-07-01 08:43:42 -0700118 // overhead
119 // ------------------------- < FLAGS_overheadGoal
120 // overhead + N * Bench Time
mtkleinf3723212014-06-25 14:08:00 -0700121 //
mtkleinbb6a0282014-07-01 08:43:42 -0700122 // where bench_plus_overhead ≈ overhead + Bench Time.
mtkleinf3723212014-06-25 14:08:00 -0700123 //
124 // Doing some math, we get:
125 //
mtkleinbb6a0282014-07-01 08:43:42 -0700126 // (overhead / FLAGS_overheadGoal) - overhead
127 // ------------------------------------------ < N
128 // bench_plus_overhead - overhead)
mtkleinf3723212014-06-25 14:08:00 -0700129 //
130 // Luckily, this also works well in practice. :)
131 const double numer = overhead / FLAGS_overheadGoal - overhead;
mtkleinbb6a0282014-07-01 08:43:42 -0700132 const double denom = bench_plus_overhead - overhead;
mtklein55b0ffc2014-07-17 08:38:23 -0700133 const int loops = clamp_loops(FLAGS_runOnce ? 1 : (int)ceil(numer / denom));
mtkleinbb6a0282014-07-01 08:43:42 -0700134
135 for (int i = 0; i < FLAGS_samples; i++) {
136 samples[i] = time(loops, bench, canvas, NULL) / loops;
137 }
138 return loops;
mtkleinf3723212014-06-25 14:08:00 -0700139}
140
mtkleinbb6a0282014-07-01 08:43:42 -0700141#if SK_SUPPORT_GPU
142static int gpu_bench(SkGLContextHelper* gl,
143 Benchmark* bench,
144 SkCanvas* canvas,
145 double* samples) {
bsalomonc2553372014-07-22 13:09:05 -0700146 gl->makeCurrent();
mtkleinbb6a0282014-07-01 08:43:42 -0700147 // Make sure we're done with whatever came before.
mtklein9bc86ed2014-07-01 10:02:42 -0700148 SK_GL(*gl, Finish());
mtkleinbb6a0282014-07-01 08:43:42 -0700149
150 // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
151 int loops = 1;
mtkleina189ccd2014-07-14 12:28:47 -0700152 if (!FLAGS_runOnce) {
153 double elapsed = 0;
154 do {
155 loops *= 2;
156 // If the GPU lets frames lag at all, we need to make sure we're timing
157 // _this_ round, not still timing last round. We force this by looping
158 // more times than any reasonable GPU will allow frames to lag.
159 for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
160 elapsed = time(loops, bench, canvas, gl);
161 }
162 } while (elapsed < FLAGS_gpuMs);
mtkleinbb6a0282014-07-01 08:43:42 -0700163
mtkleina189ccd2014-07-14 12:28:47 -0700164 // We've overshot at least a little. Scale back linearly.
165 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed);
mtkleinbb6a0282014-07-01 08:43:42 -0700166
mtkleina189ccd2014-07-14 12:28:47 -0700167 // Might as well make sure we're not still timing our calibration.
168 SK_GL(*gl, Finish());
169 }
mtklein55b0ffc2014-07-17 08:38:23 -0700170 loops = clamp_loops(loops);
mtkleinbb6a0282014-07-01 08:43:42 -0700171
172 // Pretty much the same deal as the calibration: do some warmup to make
173 // sure we're timing steady-state pipelined frames.
174 for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
175 time(loops, bench, canvas, gl);
mtkleinf3723212014-06-25 14:08:00 -0700176 }
mtkleinbb6a0282014-07-01 08:43:42 -0700177
178 // Now, actually do the timing!
179 for (int i = 0; i < FLAGS_samples; i++) {
180 samples[i] = time(loops, bench, canvas, gl) / loops;
181 }
182 return loops;
183}
184#endif
185
186static SkString to_lower(const char* str) {
187 SkString lower(str);
188 for (size_t i = 0; i < lower.size(); i++) {
189 lower[i] = tolower(lower[i]);
190 }
191 return lower;
mtkleinf3723212014-06-25 14:08:00 -0700192}
193
bsalomonc2553372014-07-22 13:09:05 -0700194struct Config {
195 const char* name;
mtkleinbb6a0282014-07-01 08:43:42 -0700196 Benchmark::Backend backend;
bsalomonc2553372014-07-22 13:09:05 -0700197 SkColorType color;
198 SkAlphaType alpha;
199 int samples;
200#if SK_SUPPORT_GPU
201 GrContextFactory::GLContextType ctxType;
202#else
203 int bogusInt;
204#endif
205};
206
207struct Target {
208 explicit Target(const Config& c) : config(c) {}
209 const Config config;
mtkleinbb6a0282014-07-01 08:43:42 -0700210 SkAutoTDelete<SkSurface> surface;
211#if SK_SUPPORT_GPU
212 SkGLContextHelper* gl;
213#endif
214};
mtkleinf3723212014-06-25 14:08:00 -0700215
bsalomonc2553372014-07-22 13:09:05 -0700216static bool is_cpu_config_allowed(const char* name) {
mtkleinbb6a0282014-07-01 08:43:42 -0700217 for (int i = 0; i < FLAGS_config.count(); i++) {
bsalomonc2553372014-07-22 13:09:05 -0700218 if (to_lower(FLAGS_config[i]).equals(name)) {
219 return true;
mtkleinf3723212014-06-25 14:08:00 -0700220 }
221 }
bsalomonc2553372014-07-22 13:09:05 -0700222 return false;
mtkleinbb6a0282014-07-01 08:43:42 -0700223}
224
bsalomonc2553372014-07-22 13:09:05 -0700225#if SK_SUPPORT_GPU
226static bool is_gpu_config_allowed(const char* name, GrContextFactory::GLContextType ctxType,
227 int sampleCnt) {
228 if (!is_cpu_config_allowed(name)) {
229 return false;
230 }
231 if (const GrContext* ctx = gGrFactory.get(ctxType)) {
232 return sampleCnt <= ctx->getMaxSampleCount();
233 }
234 return false;
235}
236#endif
mtkleinbb6a0282014-07-01 08:43:42 -0700237
bsalomonc2553372014-07-22 13:09:05 -0700238#if SK_SUPPORT_GPU
239#define kBogusGLContextType GrContextFactory::kNative_GLContextType
240#else
241#define kBogusGLContextType 0
242#endif
243
244// Append all configs that are enabled and supported.
245static void create_configs(SkTDArray<Config>* configs) {
246 #define CPU_CONFIG(name, backend, color, alpha) \
247 if (is_cpu_config_allowed(#name)) { \
248 Config config = { #name, Benchmark::backend, color, alpha, 0, kBogusGLContextType }; \
249 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700250 }
bsalomonc2553372014-07-22 13:09:05 -0700251
mtklein40b32be2014-07-09 08:46:49 -0700252 if (FLAGS_cpu) {
bsalomonc2553372014-07-22 13:09:05 -0700253 CPU_CONFIG(nonrendering, kNonRendering_Backend, kUnknown_SkColorType, kUnpremul_SkAlphaType)
254 CPU_CONFIG(8888, kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType)
255 CPU_CONFIG(565, kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType)
mtklein40b32be2014-07-09 08:46:49 -0700256 }
mtkleinbb6a0282014-07-01 08:43:42 -0700257
258#if SK_SUPPORT_GPU
bsalomonc2553372014-07-22 13:09:05 -0700259 #define GPU_CONFIG(name, ctxType, samples) \
260 if (is_gpu_config_allowed(#name, GrContextFactory::ctxType, samples)) { \
261 Config config = { \
262 #name, \
263 Benchmark::kGPU_Backend, \
264 kN32_SkColorType, \
265 kPremul_SkAlphaType, \
266 samples, \
267 GrContextFactory::ctxType }; \
268 configs->push(config); \
mtkleinbb6a0282014-07-01 08:43:42 -0700269 }
bsalomonc2553372014-07-22 13:09:05 -0700270
mtklein40b32be2014-07-09 08:46:49 -0700271 if (FLAGS_gpu) {
bsalomonc2553372014-07-22 13:09:05 -0700272 GPU_CONFIG(gpu, kNative_GLContextType, 0)
273 GPU_CONFIG(msaa4, kNative_GLContextType, 4)
274 GPU_CONFIG(msaa16, kNative_GLContextType, 16)
275 GPU_CONFIG(nvprmsaa4, kNVPR_GLContextType, 4)
276 GPU_CONFIG(nvprmsaa16, kNVPR_GLContextType, 16)
277 GPU_CONFIG(debug, kDebug_GLContextType, 0)
278 GPU_CONFIG(nullgpu, kNull_GLContextType, 0)
mtklein40b32be2014-07-09 08:46:49 -0700279 }
mtkleinbb6a0282014-07-01 08:43:42 -0700280#endif
mtkleinf3723212014-06-25 14:08:00 -0700281}
282
bsalomonc2553372014-07-22 13:09:05 -0700283// If bench is enabled for config, returns a Target* for it, otherwise NULL.
284static Target* is_enabled(Benchmark* bench, const Config& config) {
285 if (!bench->isSuitableFor(config.backend)) {
286 return NULL;
287 }
288
289 SkImageInfo info;
290 info.fAlphaType = config.alpha;
291 info.fColorType = config.color;
292 info.fWidth = bench->getSize().fX;
293 info.fHeight = bench->getSize().fY;
294
295 Target* target = new Target(config);
296
297 if (Benchmark::kRaster_Backend == config.backend) {
298 target->surface.reset(SkSurface::NewRaster(info));
299 }
300#if SK_SUPPORT_GPU
301 else if (Benchmark::kGPU_Backend == config.backend) {
302 target->surface.reset(SkSurface::NewRenderTarget(gGrFactory.get(config.ctxType), info,
303 config.samples));
304 target->gl = gGrFactory.getGLContext(config.ctxType);
305 }
306#endif
307
308 if (Benchmark::kNonRendering_Backend != config.backend && !target->surface.get()) {
309 delete target;
310 return NULL;
311 }
312 return target;
313}
314
315// Creates targets for a benchmark and a set of configs.
316static void create_targets(SkTDArray<Target*>* targets, Benchmark* b,
317 const SkTDArray<Config>& configs) {
318 for (int i = 0; i < configs.count(); ++i) {
319 if (Target* t = is_enabled(b, configs[i])) {
320 targets->push(t);
321 }
322
323 }
324}
325
mtklein60317d0f2014-07-14 11:30:37 -0700326static void fill_static_options(ResultsWriter* log) {
327#if defined(SK_BUILD_FOR_WIN32)
328 log->option("system", "WIN32");
329#elif defined(SK_BUILD_FOR_MAC)
330 log->option("system", "MAC");
331#elif defined(SK_BUILD_FOR_ANDROID)
332 log->option("system", "ANDROID");
333#elif defined(SK_BUILD_FOR_UNIX)
334 log->option("system", "UNIX");
335#else
336 log->option("system", "other");
337#endif
mtklein60317d0f2014-07-14 11:30:37 -0700338}
339
jcgregoriobf5e5232014-07-17 13:14:16 -0700340#if SK_SUPPORT_GPU
341static void fill_gpu_options(ResultsWriter* log, SkGLContextHelper* ctx) {
jcgregorio05c45602014-07-17 13:54:36 -0700342 const GrGLubyte* version;
jcgregoriobf5e5232014-07-17 13:14:16 -0700343 SK_GL_RET(*ctx, version, GetString(GR_GL_VERSION));
344 log->configOption("GL_VERSION", (const char*)(version));
345
346 SK_GL_RET(*ctx, version, GetString(GR_GL_RENDERER));
347 log->configOption("GL_RENDERER", (const char*) version);
348
349 SK_GL_RET(*ctx, version, GetString(GR_GL_VENDOR));
350 log->configOption("GL_VENDOR", (const char*) version);
351
352 SK_GL_RET(*ctx, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
353 log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
354}
355#endif
356
caryclark17f0b6d2014-07-22 10:15:34 -0700357int nanobench_main();
358int nanobench_main() {
mtkleinf3723212014-06-25 14:08:00 -0700359 SetupCrashHandler();
360 SkAutoGraphics ag;
mtkleinf3723212014-06-25 14:08:00 -0700361
mtkleina189ccd2014-07-14 12:28:47 -0700362 if (FLAGS_runOnce) {
363 FLAGS_samples = 1;
364 FLAGS_gpuFrameLag = 0;
365 }
366
mtklein60317d0f2014-07-14 11:30:37 -0700367 MultiResultsWriter log;
jcgregoriobf5e5232014-07-17 13:14:16 -0700368 SkAutoTDelete<NanoJSONResultsWriter> json;
mtklein60317d0f2014-07-14 11:30:37 -0700369 if (!FLAGS_outResultsFile.isEmpty()) {
jcgregoriobf5e5232014-07-17 13:14:16 -0700370 const char* gitHash = FLAGS_gitHash.isEmpty() ? "unknown-revision" : FLAGS_gitHash[0];
371 json.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0], gitHash)));
mtklein60317d0f2014-07-14 11:30:37 -0700372 log.add(json.get());
373 }
374 CallEnd<MultiResultsWriter> ender(log);
jcgregoriobf5e5232014-07-17 13:14:16 -0700375
376 if (1 == FLAGS_key.count() % 2) {
377 SkDebugf("ERROR: --key must be passed with an even number of arguments.\n");
378 return 1;
379 }
380 for (int i = 1; i < FLAGS_key.count(); i += 2) {
381 log.key(FLAGS_key[i-1], FLAGS_key[i]);
382 }
mtklein60317d0f2014-07-14 11:30:37 -0700383 fill_static_options(&log);
384
mtkleinf3723212014-06-25 14:08:00 -0700385 const double overhead = estimate_timer_overhead();
mtklein55b0ffc2014-07-17 08:38:23 -0700386 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
Mike Klein91294772014-07-16 19:59:32 -0400387
mtkleinbb6a0282014-07-01 08:43:42 -0700388 SkAutoTMalloc<double> samples(FLAGS_samples);
389
mtkleina189ccd2014-07-14 12:28:47 -0700390 if (FLAGS_runOnce) {
391 SkDebugf("--runOnce is true; times would only be misleading so we won't print them.\n");
392 } else if (FLAGS_verbose) {
mtkleinf3723212014-06-25 14:08:00 -0700393 // No header.
394 } else if (FLAGS_quiet) {
mtklein40b32be2014-07-09 08:46:49 -0700395 SkDebugf("median\tbench\tconfig\n");
mtkleinf3723212014-06-25 14:08:00 -0700396 } else {
mtklein5d9d10e2014-07-11 11:57:07 -0700397 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\n");
mtkleinf3723212014-06-25 14:08:00 -0700398 }
399
bsalomonc2553372014-07-22 13:09:05 -0700400 SkTDArray<Config> configs;
401 create_configs(&configs);
402
mtkleinf3723212014-06-25 14:08:00 -0700403 for (const BenchRegistry* r = BenchRegistry::Head(); r != NULL; r = r->next()) {
404 SkAutoTDelete<Benchmark> bench(r->factory()(NULL));
405 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
406 continue;
407 }
408
mtkleinbb6a0282014-07-01 08:43:42 -0700409 SkTDArray<Target*> targets;
bsalomonc2553372014-07-22 13:09:05 -0700410 create_targets(&targets, bench.get(), configs);
mtkleinf3723212014-06-25 14:08:00 -0700411
jcgregoriobf5e5232014-07-17 13:14:16 -0700412 if (!targets.isEmpty()) {
413 log.bench(bench->getName(), bench->getSize().fX, bench->getSize().fY);
414 bench->preDraw();
415 }
mtkleinbb6a0282014-07-01 08:43:42 -0700416 for (int j = 0; j < targets.count(); j++) {
417 SkCanvas* canvas = targets[j]->surface.get() ? targets[j]->surface->getCanvas() : NULL;
bsalomonc2553372014-07-22 13:09:05 -0700418 const char* config = targets[j]->config.name;
mtkleinf3723212014-06-25 14:08:00 -0700419
mtkleinbb6a0282014-07-01 08:43:42 -0700420 const int loops =
421#if SK_SUPPORT_GPU
bsalomonc2553372014-07-22 13:09:05 -0700422 Benchmark::kGPU_Backend == targets[j]->config.backend
mtkleinbb6a0282014-07-01 08:43:42 -0700423 ? gpu_bench(targets[j]->gl, bench.get(), canvas, samples.get())
424 :
425#endif
426 cpu_bench( overhead, bench.get(), canvas, samples.get());
mtkleinf3723212014-06-25 14:08:00 -0700427
Mike Kleine3631362014-07-15 17:56:37 -0400428 if (loops == 0) {
mtklein04d53a52014-07-17 11:23:07 -0700429 SkDebugf("Unable to time %s\t%s (overhead %s)\n",
430 bench->getName(), config, HUMANIZE(overhead));
Mike Kleine3631362014-07-15 17:56:37 -0400431 continue;
432 }
433
mtkleinf3723212014-06-25 14:08:00 -0700434 Stats stats(samples.get(), FLAGS_samples);
mtklein60317d0f2014-07-14 11:30:37 -0700435 log.config(config);
jcgregoriobf5e5232014-07-17 13:14:16 -0700436#if SK_SUPPORT_GPU
bsalomonc2553372014-07-22 13:09:05 -0700437 if (Benchmark::kGPU_Backend == targets[j]->config.backend) {
jcgregoriobf5e5232014-07-17 13:14:16 -0700438 fill_gpu_options(&log, targets[j]->gl);
439 }
440#endif
mtklein60317d0f2014-07-14 11:30:37 -0700441 log.timer("min_ms", stats.min);
442 log.timer("median_ms", stats.median);
443 log.timer("mean_ms", stats.mean);
444 log.timer("max_ms", stats.max);
445 log.timer("stddev_ms", sqrt(stats.var));
446
mtkleina189ccd2014-07-14 12:28:47 -0700447 if (FLAGS_runOnce) {
448 if (targets.count() == 1) {
449 config = ""; // Only print the config if we run the same bench on more than one.
450 }
451 SkDebugf("%s\t%s\n", bench->getName(), config);
452 } else if (FLAGS_verbose) {
mtkleinf3723212014-06-25 14:08:00 -0700453 for (int i = 0; i < FLAGS_samples; i++) {
mtklein55b0ffc2014-07-17 08:38:23 -0700454 SkDebugf("%s ", HUMANIZE(samples[i]));
mtkleinf3723212014-06-25 14:08:00 -0700455 }
456 SkDebugf("%s\n", bench->getName());
457 } else if (FLAGS_quiet) {
mtkleinbb6a0282014-07-01 08:43:42 -0700458 if (targets.count() == 1) {
mtkleinf3723212014-06-25 14:08:00 -0700459 config = ""; // Only print the config if we run the same bench on more than one.
460 }
mtklein55b0ffc2014-07-17 08:38:23 -0700461 SkDebugf("%s\t%s\t%s\n", HUMANIZE(stats.median), bench->getName(), config);
mtkleinf3723212014-06-25 14:08:00 -0700462 } else {
463 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean;
mtklein5d9d10e2014-07-11 11:57:07 -0700464 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 -0700465 , loops
mtklein55b0ffc2014-07-17 08:38:23 -0700466 , HUMANIZE(stats.min)
467 , HUMANIZE(stats.median)
468 , HUMANIZE(stats.mean)
469 , HUMANIZE(stats.max)
mtkleinf3723212014-06-25 14:08:00 -0700470 , stddev_percent
mtklein5d9d10e2014-07-11 11:57:07 -0700471 , stats.plot.c_str()
mtkleinf3723212014-06-25 14:08:00 -0700472 , config
mtkleinbb6a0282014-07-01 08:43:42 -0700473 , bench->getName()
mtkleinf3723212014-06-25 14:08:00 -0700474 );
475 }
476 }
mtkleinbb6a0282014-07-01 08:43:42 -0700477 targets.deleteAll();
Mike Klein3944a1d2014-07-15 13:40:19 -0400478
479 #if SK_SUPPORT_GPU
480 if (FLAGS_resetGpuContext) {
481 gGrFactory.destroyContexts();
482 }
483 #endif
mtkleinf3723212014-06-25 14:08:00 -0700484 }
485
486 return 0;
487}
488
489#if !defined SK_BUILD_FOR_IOS
caryclark17f0b6d2014-07-22 10:15:34 -0700490int main(int argc, char** argv) {
491 SkCommandLineFlags::Parse(argc, argv);
492 return nanobench_main();
mtkleinf3723212014-06-25 14:08:00 -0700493}
494#endif