Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(334)

Side by Side Diff: bench/nanobench.cpp

Issue 450743002: Add option to dump images from nanobench. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: move the clear Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | include/core/SkOSFile.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include <ctype.h> 8 #include <ctype.h>
9 9
10 #include "Benchmark.h" 10 #include "Benchmark.h"
(...skipping 13 matching lines...) Expand all
24 #include "SkSurface.h" 24 #include "SkSurface.h"
25 25
26 #if SK_SUPPORT_GPU 26 #if SK_SUPPORT_GPU
27 #include "gl/GrGLDefines.h" 27 #include "gl/GrGLDefines.h"
28 #include "GrContextFactory.h" 28 #include "GrContextFactory.h"
29 GrContextFactory gGrFactory; 29 GrContextFactory gGrFactory;
30 #endif 30 #endif
31 31
32 __SK_FORCE_IMAGE_DECODER_LINKING; 32 __SK_FORCE_IMAGE_DECODER_LINKING;
33 33
34 #if SK_DEBUG 34 static const int kAutoTuneLoops = -1;
35 DEFINE_bool(runOnce, true, "Run each benchmark just once?"); 35
36 static const int kDefaultLoops =
37 #ifdef SK_DEBUG
38 1;
36 #else 39 #else
37 DEFINE_bool(runOnce, false, "Run each benchmark just once?"); 40 kAutoTuneLoops;
38 #endif 41 #endif
39 42
43 static SkString loops_help_txt() {
44 SkString help;
45 help.printf("Number of times to run each bench. Set this to %d to auto-"
46 "tune for each bench. Timings are only reported when auto-tuning .",
47 kAutoTuneLoops);
48 return help;
49 }
50
51 DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str());
52
53 DEFINE_string2(writePath, w, "", "If set, write benches here as .pngs.");
54
40 DEFINE_int32(samples, 10, "Number of samples to measure for each bench."); 55 DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
41 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead."); 56 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
42 DEFINE_double(overheadGoal, 0.0001, 57 DEFINE_double(overheadGoal, 0.0001,
43 "Loop until timer overhead is at most this fraction of our measurm ents."); 58 "Loop until timer overhead is at most this fraction of our measurm ents.");
44 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); 59 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
45 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allow s to lag."); 60 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allow s to lag.");
46 61
47 DEFINE_string(outResultsFile, "", "If given, write results here as JSON."); 62 DEFINE_string(outResultsFile, "", "If given, write results here as JSON.");
48 DEFINE_int32(maxCalibrationAttempts, 3, 63 DEFINE_int32(maxCalibrationAttempts, 3,
49 "Try up to this many times to guess loops for a bench, or skip the bench."); 64 "Try up to this many times to guess loops for a bench, or skip the bench.");
(...skipping 10 matching lines...) Expand all
60 #ifdef SK_BUILD_FOR_WIN 75 #ifdef SK_BUILD_FOR_WIN
61 if (ms < 1) return SkStringPrintf("%.3gus", ms*1e3); 76 if (ms < 1) return SkStringPrintf("%.3gus", ms*1e3);
62 #else 77 #else
63 if (ms < 1) return SkStringPrintf("%.3gµs", ms*1e3); 78 if (ms < 1) return SkStringPrintf("%.3gµs", ms*1e3);
64 #endif 79 #endif
65 return SkStringPrintf("%.3gms", ms); 80 return SkStringPrintf("%.3gms", ms);
66 } 81 }
67 #define HUMANIZE(ms) humanize(ms).c_str() 82 #define HUMANIZE(ms) humanize(ms).c_str()
68 83
69 static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContextHel per* gl) { 84 static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContextHel per* gl) {
85 if (canvas) {
86 canvas->clear(SK_ColorWHITE);
87 }
70 WallTimer timer; 88 WallTimer timer;
71 timer.start(); 89 timer.start();
72 if (bench) { 90 if (bench) {
73 bench->draw(loops, canvas); 91 bench->draw(loops, canvas);
74 } 92 }
75 if (canvas) { 93 if (canvas) {
76 canvas->flush(); 94 canvas->flush();
77 } 95 }
78 #if SK_SUPPORT_GPU 96 #if SK_SUPPORT_GPU
79 if (gl) { 97 if (gl) {
(...skipping 18 matching lines...) Expand all
98 SkDebugf("ERROR: clamping loops from %d to 1.\n", loops); 116 SkDebugf("ERROR: clamping loops from %d to 1.\n", loops);
99 return 1; 117 return 1;
100 } 118 }
101 if (loops > FLAGS_maxLoops) { 119 if (loops > FLAGS_maxLoops) {
102 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loo ps, FLAGS_maxLoops); 120 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loo ps, FLAGS_maxLoops);
103 return FLAGS_maxLoops; 121 return FLAGS_maxLoops;
104 } 122 }
105 return loops; 123 return loops;
106 } 124 }
107 125
126 static bool write_canvas_png(SkCanvas* canvas, const SkString& filename) {
127 if (filename.isEmpty()) {
128 return false;
129 }
130 if (kUnknown_SkColorType == canvas->imageInfo().fColorType) {
131 return false;
132 }
133 SkBitmap bmp;
134 bmp.setInfo(canvas->imageInfo());
135 if (!canvas->readPixels(&bmp, 0, 0)) {
136 SkDebugf("Can't read canvas pixels.\n");
137 return false;
138 }
139 SkString dir = SkOSPath::Dirname(filename.c_str());
140 if (!sk_mkdir(dir.c_str())) {
141 SkDebugf("Can't make dir %s.\n", dir.c_str());
142 return false;
143 }
144 SkFILEWStream stream(filename.c_str());
145 if (!stream.isValid()) {
146 SkDebugf("Can't write %s.\n", filename.c_str());
147 return false;
148 }
149 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 1 00)) {
150 SkDebugf("Can't encode a PNG.\n");
151 return false;
152 }
153 return true;
154 }
155
156 static int kFailedLoops = -2;
108 static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas, double* samples) { 157 static 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 o verhead negligible. 158 // First figure out approximately how many loops of bench it takes to make o verhead negligible.
110 double bench_plus_overhead = 0.0; 159 double bench_plus_overhead = 0.0;
111 int round = 0; 160 int round = 0;
112 while (bench_plus_overhead < overhead) { 161 if (kAutoTuneLoops == FLAGS_loops) {
113 if (round++ == FLAGS_maxCalibrationAttempts) { 162 while (bench_plus_overhead < overhead) {
114 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping .\n", 163 if (round++ == FLAGS_maxCalibrationAttempts) {
115 bench->getName(), HUMANIZE(bench_plus_overhead), HUMANIZE(o verhead)); 164 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skip ping.\n",
116 return 0; 165 bench->getName(), HUMANIZE(bench_plus_overhead), HUMANI ZE(overhead));
166 return kFailedLoops;
167 }
168 bench_plus_overhead = time(1, bench, canvas, NULL);
117 } 169 }
118 bench_plus_overhead = time(1, bench, canvas, NULL);
119 } 170 }
120 171
121 // Later we'll just start and stop the timer once but loop N times. 172 // Later we'll just start and stop the timer once but loop N times.
122 // We'll pick N to make timer overhead negligible: 173 // We'll pick N to make timer overhead negligible:
123 // 174 //
124 // overhead 175 // overhead
125 // ------------------------- < FLAGS_overheadGoal 176 // ------------------------- < FLAGS_overheadGoal
126 // overhead + N * Bench Time 177 // overhead + N * Bench Time
127 // 178 //
128 // where bench_plus_overhead ≈ overhead + Bench Time. 179 // where bench_plus_overhead ≈ overhead + Bench Time.
129 // 180 //
130 // Doing some math, we get: 181 // Doing some math, we get:
131 // 182 //
132 // (overhead / FLAGS_overheadGoal) - overhead 183 // (overhead / FLAGS_overheadGoal) - overhead
133 // ------------------------------------------ < N 184 // ------------------------------------------ < N
134 // bench_plus_overhead - overhead) 185 // bench_plus_overhead - overhead)
135 // 186 //
136 // Luckily, this also works well in practice. :) 187 // Luckily, this also works well in practice. :)
137 const double numer = overhead / FLAGS_overheadGoal - overhead; 188 int loops = FLAGS_loops;
138 const double denom = bench_plus_overhead - overhead; 189 if (kAutoTuneLoops == loops) {
139 const int loops = clamp_loops(FLAGS_runOnce ? 1 : (int)ceil(numer / denom)); 190 const double numer = overhead / FLAGS_overheadGoal - overhead;
191 const double denom = bench_plus_overhead - overhead;
192 loops = (int)ceil(numer / denom);
193 }
194 loops = clamp_loops(loops);
140 195
141 for (int i = 0; i < FLAGS_samples; i++) { 196 for (int i = 0; i < FLAGS_samples; i++) {
142 samples[i] = time(loops, bench, canvas, NULL) / loops; 197 samples[i] = time(loops, bench, canvas, NULL) / loops;
143 } 198 }
144 return loops; 199 return loops;
145 } 200 }
146 201
147 #if SK_SUPPORT_GPU 202 #if SK_SUPPORT_GPU
148 static int gpu_bench(SkGLContextHelper* gl, 203 static int gpu_bench(SkGLContextHelper* gl,
149 Benchmark* bench, 204 Benchmark* bench,
150 SkCanvas* canvas, 205 SkCanvas* canvas,
151 double* samples) { 206 double* samples) {
152 gl->makeCurrent(); 207 gl->makeCurrent();
153 // Make sure we're done with whatever came before. 208 // Make sure we're done with whatever came before.
154 SK_GL(*gl, Finish()); 209 SK_GL(*gl, Finish());
155 210
156 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp uMs. 211 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp uMs.
157 int loops = 1; 212 int loops = FLAGS_loops;
158 if (!FLAGS_runOnce) { 213 if (kAutoTuneLoops == loops) {
214 loops = 1;
159 double elapsed = 0; 215 double elapsed = 0;
160 do { 216 do {
161 loops *= 2; 217 loops *= 2;
162 // If the GPU lets frames lag at all, we need to make sure we're tim ing 218 // If the GPU lets frames lag at all, we need to make sure we're tim ing
163 // _this_ round, not still timing last round. We force this by loop ing 219 // _this_ round, not still timing last round. We force this by loop ing
164 // more times than any reasonable GPU will allow frames to lag. 220 // more times than any reasonable GPU will allow frames to lag.
165 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { 221 for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
166 elapsed = time(loops, bench, canvas, gl); 222 elapsed = time(loops, bench, canvas, gl);
167 } 223 }
168 } while (elapsed < FLAGS_gpuMs); 224 } while (elapsed < FLAGS_gpuMs);
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 const char* fSourceType; 523 const char* fSourceType;
468 int fCurrentScale; 524 int fCurrentScale;
469 int fCurrentSKP; 525 int fCurrentSKP;
470 }; 526 };
471 527
472 int nanobench_main(); 528 int nanobench_main();
473 int nanobench_main() { 529 int nanobench_main() {
474 SetupCrashHandler(); 530 SetupCrashHandler();
475 SkAutoGraphics ag; 531 SkAutoGraphics ag;
476 532
477 if (FLAGS_runOnce) { 533 if (kAutoTuneLoops != FLAGS_loops) {
478 FLAGS_samples = 1; 534 FLAGS_samples = 1;
479 FLAGS_gpuFrameLag = 0; 535 FLAGS_gpuFrameLag = 0;
480 } 536 }
481 537
538 if (!FLAGS_writePath.isEmpty()) {
539 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]);
540 if (!sk_mkdir(FLAGS_writePath[0])) {
541 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_wri tePath[0]);
542 FLAGS_writePath.set(0, NULL);
543 }
544 }
545
482 MultiResultsWriter log; 546 MultiResultsWriter log;
483 SkAutoTDelete<NanoJSONResultsWriter> json; 547 SkAutoTDelete<NanoJSONResultsWriter> json;
484 if (!FLAGS_outResultsFile.isEmpty()) { 548 if (!FLAGS_outResultsFile.isEmpty()) {
485 const char* gitHash = FLAGS_gitHash.isEmpty() ? "unknown-revision" : FLA GS_gitHash[0]; 549 const char* gitHash = FLAGS_gitHash.isEmpty() ? "unknown-revision" : FLA GS_gitHash[0];
486 json.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0], gitHash) )); 550 json.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0], gitHash) ));
487 log.add(json.get()); 551 log.add(json.get());
488 } 552 }
489 CallEnd<MultiResultsWriter> ender(log); 553 CallEnd<MultiResultsWriter> ender(log);
490 554
491 if (1 == FLAGS_key.count() % 2) { 555 if (1 == FLAGS_key.count() % 2) {
492 SkDebugf("ERROR: --key must be passed with an even number of arguments.\ n"); 556 SkDebugf("ERROR: --key must be passed with an even number of arguments.\ n");
493 return 1; 557 return 1;
494 } 558 }
495 for (int i = 1; i < FLAGS_key.count(); i += 2) { 559 for (int i = 1; i < FLAGS_key.count(); i += 2) {
496 log.key(FLAGS_key[i-1], FLAGS_key[i]); 560 log.key(FLAGS_key[i-1], FLAGS_key[i]);
497 } 561 }
498 fill_static_options(&log); 562 fill_static_options(&log);
499 563
500 const double overhead = estimate_timer_overhead(); 564 const double overhead = estimate_timer_overhead();
501 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead)); 565 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
502 566
503 SkAutoTMalloc<double> samples(FLAGS_samples); 567 SkAutoTMalloc<double> samples(FLAGS_samples);
504 568
505 if (FLAGS_runOnce) { 569 if (kAutoTuneLoops != FLAGS_loops) {
506 SkDebugf("--runOnce is true; times would only be misleading so we won't print them.\n"); 570 SkDebugf("Fixed number of loops; times would only be misleading so we wo n't print them.\n");
507 } else if (FLAGS_verbose) { 571 } else if (FLAGS_verbose) {
508 // No header. 572 // No header.
509 } else if (FLAGS_quiet) { 573 } else if (FLAGS_quiet) {
510 SkDebugf("median\tbench\tconfig\n"); 574 SkDebugf("median\tbench\tconfig\n");
511 } else { 575 } else {
512 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\ n"); 576 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\ n");
513 } 577 }
514 578
515 SkTDArray<Config> configs; 579 SkTDArray<Config> configs;
516 create_configs(&configs); 580 create_configs(&configs);
(...skipping 25 matching lines...) Expand all
542 #endif 606 #endif
543 607
544 const int loops = 608 const int loops =
545 #if SK_SUPPORT_GPU 609 #if SK_SUPPORT_GPU
546 Benchmark::kGPU_Backend == targets[j]->config.backend 610 Benchmark::kGPU_Backend == targets[j]->config.backend
547 ? gpu_bench(targets[j]->gl, bench.get(), canvas, samples.get()) 611 ? gpu_bench(targets[j]->gl, bench.get(), canvas, samples.get())
548 : 612 :
549 #endif 613 #endif
550 cpu_bench( overhead, bench.get(), canvas, samples.get()); 614 cpu_bench( overhead, bench.get(), canvas, samples.get());
551 615
552 if (loops == 0) { 616 if (canvas && !FLAGS_writePath.isEmpty() && NULL != FLAGS_writePath[ 0]) {
617 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config );
618 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getName ());
619 pngFilename.append(".png");
620 write_canvas_png(canvas, pngFilename);
621 }
622
623 if (kFailedLoops == loops) {
553 // Can't be timed. A warning note has already been printed. 624 // Can't be timed. A warning note has already been printed.
554 continue; 625 continue;
555 } 626 }
556 627
557 Stats stats(samples.get(), FLAGS_samples); 628 Stats stats(samples.get(), FLAGS_samples);
558 log.config(config); 629 log.config(config);
559 benchStream.fillCurrentOptions(&log); 630 benchStream.fillCurrentOptions(&log);
560 #if SK_SUPPORT_GPU 631 #if SK_SUPPORT_GPU
561 if (Benchmark::kGPU_Backend == targets[j]->config.backend) { 632 if (Benchmark::kGPU_Backend == targets[j]->config.backend) {
562 fill_gpu_options(&log, targets[j]->gl); 633 fill_gpu_options(&log, targets[j]->gl);
563 } 634 }
564 #endif 635 #endif
565 log.timer("min_ms", stats.min); 636 log.timer("min_ms", stats.min);
566 log.timer("median_ms", stats.median); 637 log.timer("median_ms", stats.median);
567 log.timer("mean_ms", stats.mean); 638 log.timer("mean_ms", stats.mean);
568 log.timer("max_ms", stats.max); 639 log.timer("max_ms", stats.max);
569 log.timer("stddev_ms", sqrt(stats.var)); 640 log.timer("stddev_ms", sqrt(stats.var));
570 641
571 if (FLAGS_runOnce) { 642 if (kAutoTuneLoops != FLAGS_loops) {
572 if (targets.count() == 1) { 643 if (targets.count() == 1) {
573 config = ""; // Only print the config if we run the same ben ch on more than one. 644 config = ""; // Only print the config if we run the same ben ch on more than one.
574 } 645 }
575 SkDebugf("%s\t%s\n", bench->getName(), config); 646 SkDebugf("%s\t%s\n", bench->getName(), config);
576 } else if (FLAGS_verbose) { 647 } else if (FLAGS_verbose) {
577 for (int i = 0; i < FLAGS_samples; i++) { 648 for (int i = 0; i < FLAGS_samples; i++) {
578 SkDebugf("%s ", HUMANIZE(samples[i])); 649 SkDebugf("%s ", HUMANIZE(samples[i]));
579 } 650 }
580 SkDebugf("%s\n", bench->getName()); 651 SkDebugf("%s\n", bench->getName());
581 } else if (FLAGS_quiet) { 652 } else if (FLAGS_quiet) {
(...skipping 30 matching lines...) Expand all
612 683
613 return 0; 684 return 0;
614 } 685 }
615 686
616 #if !defined SK_BUILD_FOR_IOS 687 #if !defined SK_BUILD_FOR_IOS
617 int main(int argc, char** argv) { 688 int main(int argc, char** argv) {
618 SkCommandLineFlags::Parse(argc, argv); 689 SkCommandLineFlags::Parse(argc, argv);
619 return nanobench_main(); 690 return nanobench_main();
620 } 691 }
621 #endif 692 #endif
OLDNEW
« no previous file with comments | « no previous file | include/core/SkOSFile.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698