/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "Benchmark.h" #include "SkData.h" #include "SkOSFile.h" #include "SkPicture.h" #include "Timer.h" #include "gm.h" #include "ok.h" #include #include #include #include #include struct GMStream : Stream { const skiagm::GMRegistry* registry = skiagm::GMRegistry::Head(); static std::unique_ptr Create(Options) { GMStream stream; return move_unique(stream); } struct GMSrc : Src { skiagm::GM* (*factory)(void*); std::unique_ptr gm; void init() { if (gm) { return; } gm.reset(factory(nullptr)); } std::string name() override { this->init(); return gm->getName(); } SkISize size() override { this->init(); return gm->getISize(); } Status draw(SkCanvas* canvas) override { this->init(); canvas->clear(0xffffffff); gm->draw(canvas); return Status::OK; } }; std::unique_ptr next() override { if (!registry) { return nullptr; } GMSrc src; src.factory = registry->factory(); registry = registry->next(); return move_unique(src); } }; static Register gm{"gm", "draw GMs linked into this binary", GMStream::Create}; struct SKPStream : Stream { std::string dir; std::vector skps; static std::unique_ptr Create(Options options) { SKPStream stream; stream.dir = options("dir", "skps"); SkOSFile::Iter it{stream.dir.c_str(), ".skp"}; for (SkString path; it.next(&path); ) { stream.skps.push_back(path.c_str()); } return move_unique(stream); } struct SKPSrc : Src { std::string dir, path; sk_sp pic; void init() { if (pic) { return; } auto skp = SkData::MakeFromFileName((dir+"/"+path).c_str()); pic = SkPicture::MakeFromData(skp.get()); } std::string name() override { return path; } SkISize size() override { this->init(); return pic->cullRect().roundOut().size(); } Status draw(SkCanvas* canvas) override { this->init(); canvas->clear(0xffffffff); pic->playback(canvas); return Status::OK; } }; std::unique_ptr next() override { if (skps.empty()) { return nullptr; } SKPSrc src; src.dir = dir; src.path = skps.back(); skps.pop_back(); return move_unique(src); } }; static Register skp{"skp", "draw SKPs from dir=skps", SKPStream::Create}; struct BenchStream : Stream { const BenchRegistry* registry = BenchRegistry::Head(); int samples; static std::unique_ptr Create(Options options) { BenchStream stream; stream.samples = std::max(1, atoi(options("samples", "20").c_str())); return move_unique(stream); } struct BenchSrc : Src { Benchmark* (*factory)(void*); std::unique_ptr bench; int samples; void init() { if (bench) { return; } bench.reset(factory(nullptr)); } std::string name() override { this->init(); return bench->getName(); } SkISize size() override { this->init(); return { bench->getSize().x(), bench->getSize().y() }; } Status draw(SkCanvas* canvas) override { this->init(); using ms = std::chrono::duration; std::vector sample(samples); bench->delayedSetup(); if (canvas) { bench->perCanvasPreDraw(canvas); } for (int i = 0; i < samples; i++) { using clock = std::chrono::high_resolution_clock; for (int loops = 1; loops < 1000000000; loops *= 2) { bench->preDraw(canvas); auto start = clock::now(); bench->draw(loops, canvas); ms elapsed = clock::now() - start; bench->postDraw(canvas); if (elapsed.count() < 10) { continue; } sample[i] = elapsed / loops; break; } } if (canvas) { bench->perCanvasPostDraw(canvas); } std::sort(sample.begin(), sample.end()); SkString msg = SkStringPrintf("%s\t@0", HumanizeMs(sample[0].count()).c_str()); if (samples > 2) { msg.appendf("\t%s\t@%g", HumanizeMs(sample[samples-2].count()).c_str() , 100.0*(samples-1) / samples); } if (samples > 1) { msg.appendf("\t%s\t@100", HumanizeMs(sample[samples-1].count()).c_str()); } ok_log(msg.c_str()); return Status::OK; } }; std::unique_ptr next() override { if (!registry) { return nullptr; } BenchSrc src; src.factory = registry->factory(); src.samples = samples; registry = registry->next(); return move_unique(src); } }; static Register bench{ "bench", "time benchmarks linked into this binary samples=20 times each", BenchStream::Create, };