Index: bench/benchmain.cpp |
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp |
index 3a57f2de334ea6687db22971557a13b4230fbb15..9873c72fd6d38312005bb5c01f6d7a80a07496fa 100644 |
--- a/bench/benchmain.cpp |
+++ b/bench/benchmain.cpp |
@@ -37,7 +37,9 @@ enum BenchMode { |
kRecord_BenchMode, |
kPictureRecord_BenchMode |
}; |
-const char* BenchMode_Name[] = { "normal", "deferred", "deferredSilent", "record", "picturerecord" }; |
+const char* BenchMode_Name[] = { |
+ "normal", "deferred", "deferredSilent", "record", "picturerecord" |
+}; |
/////////////////////////////////////////////////////////////////////////////// |
@@ -271,8 +273,23 @@ DEFINE_string(mode, "normal", |
"picturerecord: draw from an SkPicture to an SkPicture.\n"); |
DEFINE_string(config, "", "Run configs given. If empty, runs the defaults set in gConfigs."); |
DEFINE_string(logFile, "", "Also write stdout here."); |
-DEFINE_int32(benchMs, 20, "Target time in ms to run each benchmark config."); |
+DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run."); |
+DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run."); |
+DEFINE_double(error, 0.01, |
+ "Ratio of subsequent bench measurements must drop within 1±error to converge."); |
DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops."); |
+DEFINE_bool2(verbose, v, false, "Print more."); |
+ |
+// Has this bench converged? First arguments are milliseconds / loop iteration, |
+// last is overall runtime in milliseconds. |
+static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw) { |
+ if (currRaw < FLAGS_minMs) { |
+ return false; |
+ } |
+ const double low = 1 - FLAGS_error, high = 1 + FLAGS_error; |
+ const double ratio = currPerLoop / prevPerLoop; |
+ return low < ratio && ratio < high; |
+} |
int tool_main(int argc, char** argv); |
int tool_main(int argc, char** argv) { |
@@ -339,20 +356,17 @@ int tool_main(int argc, char** argv) { |
if (kGPU_Backend == config.backend) { |
GrContext* context = gContextFactory.get(config.contextType); |
if (NULL == context) { |
- SkString error; |
- error.printf("Error creating GrContext for config %s. Config will be skipped.\n", |
- config.name); |
- logger.logError(error); |
+ logger.logError(SkStringPrintf( |
+ "Error creating GrContext for config %s. Config will be skipped.\n", |
+ config.name)); |
configs.remove(i); |
--i; |
continue; |
} |
if (config.sampleCount > context->getMaxSampleCount()){ |
- SkString error; |
- error.printf("Sample count (%d) for config %s is unsupported. " |
- "Config will be skipped.\n", |
- config.sampleCount, config.name); |
- logger.logError(error); |
+ logger.logError(SkStringPrintf( |
+ "Sample count (%d) for config %s is unsupported. Config will be skipped.\n", |
+ config.sampleCount, config.name)); |
configs.remove(i); |
--i; |
continue; |
@@ -484,9 +498,8 @@ int tool_main(int argc, char** argv) { |
config.sampleCount, |
context)); |
if (!device.get()) { |
- SkString error; |
- error.printf("Device creation failure for config %s. Will skip.\n", config.name); |
- logger.logError(error); |
+ logger.logError(SkStringPrintf( |
+ "Device creation failure for config %s. Will skip.\n", config.name)); |
continue; |
} |
@@ -536,20 +549,23 @@ int tool_main(int argc, char** argv) { |
BenchTimer timer; |
#endif |
+ double previous = 1.0/0.0; |
+ bool converged = false; |
bench->setLoops(0); |
+ if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.name); } |
do { |
// Ramp up 1 -> 4 -> 16 -> ... -> ~1 billion. |
const int loops = bench->getLoops(); |
- if (loops >= (1<<30)) { |
+ if (loops >= (1<<30) || timer.fWall > FLAGS_maxMs) { |
// If you find it takes more than a billion loops to get up to 20ms of runtime, |
// you've got a computer clocked at several THz or have a broken benchmark. ;) |
// "1B ought to be enough for anybody." |
- SkString str; |
- str.printf("Can't ramp %s to %dms.\n", bench->getName(), FLAGS_benchMs); |
- logger.logError(str); |
+ logger.logError(SkStringPrintf( |
+ "Can't get %s %s to converge in %dms.\n", |
+ bench->getName(), config.name, FLAGS_maxMs)); |
break; |
} |
- bench->setLoops(loops == 0 ? 1 : loops * 4); |
+ bench->setLoops(loops == 0 ? 1 : loops * 2); |
if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) { |
// Clear the recorded commands so that they do not accumulate. |
@@ -586,7 +602,13 @@ int tool_main(int argc, char** argv) { |
} |
#endif |
timer.end(); |
- } while (!kIsDebug && timer.fWall < FLAGS_benchMs); // One loop only in debug mode. |
+ const double current = timer.fWall / bench->getLoops(); |
+ if (FLAGS_verbose && current > previous) { SkDebugf("↑"); } |
+ if (FLAGS_verbose) { SkDebugf("%.3g ", current); } |
+ converged = HasConverged(previous, current, timer.fWall); |
+ previous = current; |
+ } while (!kIsDebug && !converged); |
+ if (FLAGS_verbose) { SkDebugf("\n"); } |
if (FLAGS_outDir.count() && kNonRendering_Backend != config.backend) { |
saveFile(bench->getName(), |