From 5772eaa91d6a10d74959d7732513c5ab9c057e03 Mon Sep 17 00:00:00 2001 From: csmartdalton Date: Tue, 11 Oct 2016 18:28:54 -0700 Subject: skpbench: add warmup run Does actual work while waiting for hardware settings to kick in, rather than just sleeping. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2410373002 Review-Url: https://codereview.chromium.org/2410373002 --- tools/skpbench/_hardware.py | 2 +- tools/skpbench/_hardware_android.py | 2 +- tools/skpbench/skpbench.cpp | 70 +++++++++++++++++++++++++++---------- tools/skpbench/skpbench.py | 42 +++++++++++++++------- 4 files changed, 84 insertions(+), 32 deletions(-) (limited to 'tools/skpbench') diff --git a/tools/skpbench/_hardware.py b/tools/skpbench/_hardware.py index 9c929c43db..525c4c1e49 100644 --- a/tools/skpbench/_hardware.py +++ b/tools/skpbench/_hardware.py @@ -21,7 +21,7 @@ class Hardware: """ def __init__(self): - self.kick_in_time = 0 + self.warmup_time = 0 def __enter__(self): return self diff --git a/tools/skpbench/_hardware_android.py b/tools/skpbench/_hardware_android.py index d7990dcd81..abeab71d76 100644 --- a/tools/skpbench/_hardware_android.py +++ b/tools/skpbench/_hardware_android.py @@ -11,7 +11,7 @@ import time class HardwareAndroid(Hardware): def __init__(self, adb): Hardware.__init__(self) - self.kick_in_time = 5 + self.warmup_time = 5 self._adb = adb self._is_root = self._adb.attempt_root() if self._is_root: diff --git a/tools/skpbench/skpbench.cpp b/tools/skpbench/skpbench.cpp index 6d0381a28d..f452d9d025 100644 --- a/tools/skpbench/skpbench.cpp +++ b/tools/skpbench/skpbench.cpp @@ -9,11 +9,14 @@ #include "GrContextFactory.h" #include "SkCanvas.h" #include "SkOSFile.h" +#include "SkPerlinNoiseShader.h" #include "SkPicture.h" +#include "SkPictureRecorder.h" #include "SkStream.h" #include "SkSurface.h" #include "SkSurfaceProps.h" #include "picture_utils.h" +#include "sk_tool_utils.h" #include "flags/SkCommandLineFlags.h" #include "flags/SkCommonFlagsConfig.h" #include @@ -38,7 +41,7 @@ DEFINE_int32(duration, 5000, "number of milliseconds to run the benchmark"); DEFINE_int32(sampleMs, 50, "minimum duration of a sample"); DEFINE_bool(gpuClock, false, "time on the gpu clock (gpu work only)"); DEFINE_bool(fps, false, "use fps instead of ms"); -DEFINE_string(skp, "", "path to a single .skp file to benchmark"); +DEFINE_string(skp, "", "path to a single .skp file, or 'warmup' for a builtin warmup run"); DEFINE_string(png, "", "if set, save a .png proof to disk at this file location"); DEFINE_int32(verbosity, 4, "level of verbosity (0=none to 5=debug)"); DEFINE_bool(suppressHeader, false, "don't print a header row before the results"); @@ -86,6 +89,7 @@ enum class ExitErr { }; static void draw_skp_and_flush(SkCanvas*, const SkPicture*); +static sk_sp create_warmup_skp(); static bool mkdir_p(const SkString& name); static SkString join(const SkCommandLineFlags::StringArray&); static void exitf(ExitErr, const char* format, ...); @@ -230,31 +234,38 @@ int main(int argc, char** argv) { SkCommandLineConfigArray configs; ParseConfigs(FLAGS_config, &configs); if (configs.count() != 1 || !(config = configs[0]->asConfigGpu())) { - exitf(ExitErr::kUsage, "invalid config %s, must specify one (and only one) GPU config", + exitf(ExitErr::kUsage, "invalid config '%s': must specify one (and only one) GPU config", join(FLAGS_config).c_str()); } // Parse the skp. if (FLAGS_skp.count() != 1) { - exitf(ExitErr::kUsage, "invalid skp %s, must specify (and only one) skp path name.", + exitf(ExitErr::kUsage, "invalid skp '%s': must specify a single skp file, or 'warmup'", join(FLAGS_skp).c_str()); } - const char* skpfile = FLAGS_skp[0]; - std::unique_ptr skpstream(SkStream::MakeFromFile(skpfile)); - if (!skpstream) { - exitf(ExitErr::kIO, "failed to open skp file %s", skpfile); - } - sk_sp skp = SkPicture::MakeFromStream(skpstream.get()); - if (!skp) { - exitf(ExitErr::kData, "failed to parse skp file %s", skpfile); + sk_sp skp; + SkString skpname; + if (0 == strcmp(FLAGS_skp[0], "warmup")) { + skp = create_warmup_skp(); + skpname = "warmup"; + } else { + const char* skpfile = FLAGS_skp[0]; + std::unique_ptr skpstream(SkStream::MakeFromFile(skpfile)); + if (!skpstream) { + exitf(ExitErr::kIO, "failed to open skp file %s", skpfile); + } + skp = SkPicture::MakeFromStream(skpstream.get()); + if (!skp) { + exitf(ExitErr::kData, "failed to parse skp file %s", skpfile); + } + skpname = SkOSPath::Basename(skpfile); } int width = SkTMin(SkScalarCeilToInt(skp->cullRect().width()), 2048), height = SkTMin(SkScalarCeilToInt(skp->cullRect().height()), 2048); if (FLAGS_verbosity >= 3 && (width != skp->cullRect().width() || height != skp->cullRect().height())) { fprintf(stderr, "%s is too large (%ix%i), cropping to %ix%i.\n", - SkOSPath::Basename(skpfile).c_str(), - SkScalarCeilToInt(skp->cullRect().width()), + skpname.c_str(), SkScalarCeilToInt(skp->cullRect().width()), SkScalarCeilToInt(skp->cullRect().height()), width, height); } @@ -295,6 +306,7 @@ int main(int argc, char** argv) { width, height, config->getTag().c_str()); } + // Run the benchmark. std::vector samples; if (FLAGS_sampleMs > 0) { // +1 because we might take one more sample in order to have an odd number. @@ -302,8 +314,6 @@ int main(int argc, char** argv) { } else { samples.reserve(2 * FLAGS_duration); } - - // Run the benchmark. SkCanvas* canvas = surface->getCanvas(); canvas->translate(-skp->cullRect().x(), -skp->cullRect().y()); if (!FLAGS_gpuClock) { @@ -315,7 +325,7 @@ int main(int argc, char** argv) { run_gpu_time_benchmark(testCtx->gpuTimer(), testCtx->fenceSync(), canvas, skp.get(), &samples); } - print_result(samples, config->getTag().c_str(), SkOSPath::Basename(skpfile).c_str()); + print_result(samples, config->getTag().c_str(), skpname.c_str()); // Save a proof (if one was requested). if (!FLAGS_png.isEmpty()) { @@ -342,6 +352,30 @@ static void draw_skp_and_flush(SkCanvas* canvas, const SkPicture* skp) { canvas->flush(); } +static sk_sp create_warmup_skp() { + static constexpr SkRect bounds{0, 0, 500, 500}; + SkPictureRecorder recorder; + SkCanvas* recording = recorder.beginRecording(bounds); + + recording->clear(SK_ColorWHITE); + + SkPaint stroke; + stroke.setStyle(SkPaint::kStroke_Style); + stroke.setStrokeWidth(2); + + // Use a big path to (theoretically) warmup the CPU. + SkPath bigPath; + sk_tool_utils::make_big_path(bigPath); + recording->drawPath(bigPath, stroke); + + // Use a perlin shader to warmup the GPU. + SkPaint perlin; + perlin.setShader(SkPerlinNoiseShader::MakeTurbulence(0.1f, 0.1f, 1, 0, nullptr)); + recording->drawRect(bounds, perlin); + + return recorder.finishRecordingAsPicture(); +} + bool mkdir_p(const SkString& dirname) { if (dirname.isEmpty()) { return true; @@ -351,8 +385,8 @@ bool mkdir_p(const SkString& dirname) { static SkString join(const SkCommandLineFlags::StringArray& stringArray) { SkString joined; - for (int i = 0; i < FLAGS_config.count(); ++i) { - joined.appendf(i ? " %s" : "%s", FLAGS_config[i]); + for (int i = 0; i < stringArray.count(); ++i) { + joined.appendf(i ? " %s" : "%s", stringArray[i]); } return joined; } diff --git a/tools/skpbench/skpbench.py b/tools/skpbench/skpbench.py index 932d8d0461..9598162693 100755 --- a/tools/skpbench/skpbench.py +++ b/tools/skpbench/skpbench.py @@ -67,6 +67,11 @@ if FLAGS.adb: else: import _os_path as _path +def dump_commandline_if_verbose(commandline): + if FLAGS.verbosity >= 4: + quoted = ['\'%s\'' % re.sub(r'([\\\'])', r'\\\1', x) for x in commandline] + print(' '.join(quoted), file=sys.stderr) + class StddevException(Exception): pass @@ -111,7 +116,26 @@ class SKPBench: @classmethod def print_header(cls): - subprocess.call(cls.ARGV + ['--duration', '0']) + commandline = cls.ARGV + ['--duration', '0'] + dump_commandline_if_verbose(commandline) + subprocess.call(commandline) + + @classmethod + def run_warmup(cls, warmup_time): + if not warmup_time: + return + print('running %i second warmup...' % warmup_time) + commandline = cls.ARGV + ['--duration', str(warmup_time * 1000), + '--config', 'gpu', + '--skp', 'warmup'] + dump_commandline_if_verbose(commandline) + output = subprocess.check_output(commandline).decode('utf-8') + # validate the warmup run output. + for line in output.split('\n'): + match = BenchResult.match(line.rstrip()) + if match and match.bench == 'warmup': + return + raise Exception('Invalid warmup output:\n%s' % output) def __init__(self, skp, config, max_stddev, best_result=None): self.skp = skp @@ -143,9 +167,7 @@ class SKPBench: pngfile = _path.join(FLAGS.write_path, self.config, _path.basename(self.skp) + '.png') commandline.extend(['--png', pngfile]) - if (FLAGS.verbosity >= 4): - quoted = ['\'%s\'' % re.sub(r'([\\\'])', r'\\\1', x) for x in commandline] - print(' '.join(quoted), file=sys.stderr) + dump_commandline_if_verbose(commandline) self._proc = subprocess.Popen(commandline, stdout=subprocess.PIPE) self._monitor = SubprocessMonitor(self._queue, self._proc) self._monitor.start() @@ -233,13 +255,12 @@ def run_benchmarks(configs, skps, hardware): if FLAGS.verbosity >= 5: hardware.print_debug_diagnostics() skpbench.terminate() - naptime = max(hardware.kick_in_time, exception.sleeptime) if FLAGS.verbosity >= 1: print("%s; taking a %i second nap..." % - (exception.message, naptime), file=sys.stderr) + (exception.message, exception.sleeptime), file=sys.stderr) benches.appendleft(benchargs) # retry the same bench next time. - hardware.sleep(naptime - hardware.kick_in_time) - time.sleep(hardware.kick_in_time) + hardware.sleep(exception.sleeptime) + SKPBench.run_warmup(hardware.warmup_time) def main(): @@ -263,10 +284,7 @@ def main(): hardware = Hardware() with hardware: - if hardware.kick_in_time: - print("sleeping %i seconds to allow hardware settings to kick in..." % - hardware.kick_in_time, file=sys.stderr) - time.sleep(hardware.kick_in_time) + SKPBench.run_warmup(hardware.warmup_time) run_benchmarks(configs, skps, hardware) -- cgit v1.2.3