aboutsummaryrefslogtreecommitdiffhomepage
path: root/bench
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2014-08-07 14:28:50 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-07 14:28:50 -0700
commit6eb03cc06d0bc60da5277a83aa0251a475794b04 (patch)
treef359945cb7d54f915bb91f28f44949fffd42e864 /bench
parent72ebb9f1dc1ed4d64127b02fed93446b278069d1 (diff)
Add option to dump images from nanobench.
Add option to set the repeat count to any number, replacs the --runOnce flag. R=mtklein@google.com Author: bsalomon@google.com Review URL: https://codereview.chromium.org/450743002
Diffstat (limited to 'bench')
-rw-r--r--bench/nanobench.cpp109
1 files changed, 90 insertions, 19 deletions
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index c808183b19..245aa0ed1d 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -31,12 +31,27 @@
__SK_FORCE_IMAGE_DECODER_LINKING;
-#if SK_DEBUG
- DEFINE_bool(runOnce, true, "Run each benchmark just once?");
+static const int kAutoTuneLoops = -1;
+
+static const int kDefaultLoops =
+#ifdef SK_DEBUG
+ 1;
#else
- DEFINE_bool(runOnce, false, "Run each benchmark just once?");
+ kAutoTuneLoops;
#endif
+static SkString loops_help_txt() {
+ SkString help;
+ help.printf("Number of times to run each bench. Set this to %d to auto-"
+ "tune for each bench. Timings are only reported when auto-tuning.",
+ kAutoTuneLoops);
+ return help;
+}
+
+DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str());
+
+DEFINE_string2(writePath, w, "", "If set, write benches here as .pngs.");
+
DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
DEFINE_double(overheadGoal, 0.0001,
@@ -67,6 +82,9 @@ static SkString humanize(double ms) {
#define HUMANIZE(ms) humanize(ms).c_str()
static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContextHelper* gl) {
+ if (canvas) {
+ canvas->clear(SK_ColorWHITE);
+ }
WallTimer timer;
timer.start();
if (bench) {
@@ -105,17 +123,50 @@ static int clamp_loops(int loops) {
return loops;
}
+static bool write_canvas_png(SkCanvas* canvas, const SkString& filename) {
+ if (filename.isEmpty()) {
+ return false;
+ }
+ if (kUnknown_SkColorType == canvas->imageInfo().fColorType) {
+ return false;
+ }
+ SkBitmap bmp;
+ bmp.setInfo(canvas->imageInfo());
+ if (!canvas->readPixels(&bmp, 0, 0)) {
+ SkDebugf("Can't read canvas pixels.\n");
+ return false;
+ }
+ SkString dir = SkOSPath::Dirname(filename.c_str());
+ if (!sk_mkdir(dir.c_str())) {
+ SkDebugf("Can't make dir %s.\n", dir.c_str());
+ return false;
+ }
+ SkFILEWStream stream(filename.c_str());
+ if (!stream.isValid()) {
+ SkDebugf("Can't write %s.\n", filename.c_str());
+ return false;
+ }
+ if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 100)) {
+ SkDebugf("Can't encode a PNG.\n");
+ return false;
+ }
+ return true;
+}
+
+static int kFailedLoops = -2;
static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas, double* samples) {
// First figure out approximately how many loops of bench it takes to make overhead negligible.
double bench_plus_overhead = 0.0;
int round = 0;
- while (bench_plus_overhead < overhead) {
- if (round++ == FLAGS_maxCalibrationAttempts) {
- SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
- bench->getName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
- return 0;
+ if (kAutoTuneLoops == FLAGS_loops) {
+ while (bench_plus_overhead < overhead) {
+ if (round++ == FLAGS_maxCalibrationAttempts) {
+ SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
+ bench->getName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
+ return kFailedLoops;
+ }
+ bench_plus_overhead = time(1, bench, canvas, NULL);
}
- bench_plus_overhead = time(1, bench, canvas, NULL);
}
// Later we'll just start and stop the timer once but loop N times.
@@ -134,9 +185,13 @@ static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas,
// bench_plus_overhead - overhead)
//
// Luckily, this also works well in practice. :)
- const double numer = overhead / FLAGS_overheadGoal - overhead;
- const double denom = bench_plus_overhead - overhead;
- const int loops = clamp_loops(FLAGS_runOnce ? 1 : (int)ceil(numer / denom));
+ int loops = FLAGS_loops;
+ if (kAutoTuneLoops == loops) {
+ const double numer = overhead / FLAGS_overheadGoal - overhead;
+ const double denom = bench_plus_overhead - overhead;
+ loops = (int)ceil(numer / denom);
+ }
+ loops = clamp_loops(loops);
for (int i = 0; i < FLAGS_samples; i++) {
samples[i] = time(loops, bench, canvas, NULL) / loops;
@@ -154,8 +209,9 @@ static int gpu_bench(SkGLContextHelper* gl,
SK_GL(*gl, Finish());
// First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
- int loops = 1;
- if (!FLAGS_runOnce) {
+ int loops = FLAGS_loops;
+ if (kAutoTuneLoops == loops) {
+ loops = 1;
double elapsed = 0;
do {
loops *= 2;
@@ -474,11 +530,19 @@ int nanobench_main() {
SetupCrashHandler();
SkAutoGraphics ag;
- if (FLAGS_runOnce) {
+ if (kAutoTuneLoops != FLAGS_loops) {
FLAGS_samples = 1;
FLAGS_gpuFrameLag = 0;
}
+ if (!FLAGS_writePath.isEmpty()) {
+ SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]);
+ if (!sk_mkdir(FLAGS_writePath[0])) {
+ SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_writePath[0]);
+ FLAGS_writePath.set(0, NULL);
+ }
+ }
+
MultiResultsWriter log;
SkAutoTDelete<NanoJSONResultsWriter> json;
if (!FLAGS_outResultsFile.isEmpty()) {
@@ -502,8 +566,8 @@ int nanobench_main() {
SkAutoTMalloc<double> samples(FLAGS_samples);
- if (FLAGS_runOnce) {
- SkDebugf("--runOnce is true; times would only be misleading so we won't print them.\n");
+ if (kAutoTuneLoops != FLAGS_loops) {
+ SkDebugf("Fixed number of loops; times would only be misleading so we won't print them.\n");
} else if (FLAGS_verbose) {
// No header.
} else if (FLAGS_quiet) {
@@ -549,7 +613,14 @@ int nanobench_main() {
#endif
cpu_bench( overhead, bench.get(), canvas, samples.get());
- if (loops == 0) {
+ if (canvas && !FLAGS_writePath.isEmpty() && NULL != FLAGS_writePath[0]) {
+ SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config);
+ pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getName());
+ pngFilename.append(".png");
+ write_canvas_png(canvas, pngFilename);
+ }
+
+ if (kFailedLoops == loops) {
// Can't be timed. A warning note has already been printed.
continue;
}
@@ -568,7 +639,7 @@ int nanobench_main() {
log.timer("max_ms", stats.max);
log.timer("stddev_ms", sqrt(stats.var));
- if (FLAGS_runOnce) {
+ if (kAutoTuneLoops != FLAGS_loops) {
if (targets.count() == 1) {
config = ""; // Only print the config if we run the same bench on more than one.
}