blob: 545731900bcfc288d17d564d91f0a228547171a9 [file] [log] [blame]
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkCommandLineFlags.h"
9#include "SkForceLinking.h"
10#include "SkGraphics.h"
11#include "SkOSFile.h"
12#include "SkPicture.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000013#include "SkPictureRecorder.h"
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +000014#include "SkStream.h"
15#include "SkString.h"
mtklein90c471e2014-06-16 14:04:32 -070016
commit-bot@chromium.org16182f72014-03-28 16:08:18 +000017#include "LazyDecodeBitmap.h"
mtklein90c471e2014-06-16 14:04:32 -070018#include "Stats.h"
mtklein9ac68ee2014-06-20 11:29:20 -070019#include "Timer.h"
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +000020
21__SK_FORCE_IMAGE_DECODER_LINKING;
22
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +000023DEFINE_string2(skps, r, "skps", "Directory containing SKPs to read and re-record.");
mtklein90c471e2014-06-16 14:04:32 -070024DEFINE_int32(samples, 10, "Number of times to re-record each SKP.");
commit-bot@chromium.org450d9ef2014-03-03 17:51:12 +000025DEFINE_int32(tileGridSize, 512, "Set the tile grid size. Has no effect if bbh is not set to tilegrid.");
26DEFINE_string(bbh, "", "Turn on the bbh and select the type, one of rtree, tilegrid, quadtree");
commit-bot@chromium.orge3ff5582014-04-01 16:24:06 +000027DEFINE_bool(skr, false, "Record SKR instead of SKP.");
commit-bot@chromium.org5da5b592014-04-21 14:59:59 +000028DEFINE_string(match, "", "The usual filters on file names of SKPs to bench.");
commit-bot@chromium.org172eb1b2014-04-28 19:41:17 +000029DEFINE_string(timescale, "us", "Print times in ms, us, or ns");
mtklein90c471e2014-06-16 14:04:32 -070030DEFINE_double(overheadGoal, 0.0001,
31 "Try to make timer overhead at most this fraction of our sample measurements.");
32DEFINE_int32(verbose, 0, "0: print min sample; "
33 "1: print min, mean, max and noise indication "
34 "2: print all samples");
commit-bot@chromium.org172eb1b2014-04-28 19:41:17 +000035
mtklein90c471e2014-06-16 14:04:32 -070036static double timescale() {
37 if (FLAGS_timescale.contains("us")) return 1000;
38 if (FLAGS_timescale.contains("ns")) return 1000000;
39 return 1;
commit-bot@chromium.org172eb1b2014-04-28 19:41:17 +000040}
commit-bot@chromium.orga8582232014-01-13 19:09:36 +000041
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +000042static SkBBHFactory* parse_FLAGS_bbh() {
skia.committer@gmail.com51997012014-04-14 03:04:57 +000043 if (FLAGS_bbh.isEmpty()) {
commit-bot@chromium.org450d9ef2014-03-03 17:51:12 +000044 return NULL;
45 }
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +000046
skia.committer@gmail.com51997012014-04-14 03:04:57 +000047 if (FLAGS_bbh.contains("rtree")) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +000048 return SkNEW(SkRTreeFactory);
robertphillips@google.com84b18c72014-04-13 19:09:42 +000049 }
skia.committer@gmail.com51997012014-04-14 03:04:57 +000050 if (FLAGS_bbh.contains("tilegrid")) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +000051 SkTileGridFactory::TileGridInfo info;
52 info.fTileInterval.set(FLAGS_tileGridSize, FLAGS_tileGridSize);
53 info.fMargin.setEmpty();
54 info.fOffset.setZero();
55 return SkNEW_ARGS(SkTileGridFactory, (info));
robertphillips@google.com84b18c72014-04-13 19:09:42 +000056 }
skia.committer@gmail.com51997012014-04-14 03:04:57 +000057 if (FLAGS_bbh.contains("quadtree")) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +000058 return SkNEW(SkQuadTreeFactory);
robertphillips@google.com84b18c72014-04-13 19:09:42 +000059 }
commit-bot@chromium.org450d9ef2014-03-03 17:51:12 +000060 SkDebugf("Invalid bbh type %s, must be one of rtree, tilegrid, quadtree.\n", FLAGS_bbh[0]);
61 return NULL;
62}
63
mtklein90c471e2014-06-16 14:04:32 -070064static void rerecord(const SkPicture& src, SkBBHFactory* bbhFactory) {
mtklein887f3972014-06-17 12:08:15 -070065 SkPictureRecorder recorder;
mtklein90c471e2014-06-16 14:04:32 -070066 if (FLAGS_skr) {
mtklein887f3972014-06-17 12:08:15 -070067 src.draw(recorder.EXPERIMENTAL_beginRecording(src.width(), src.height(), bbhFactory));
mtklein90c471e2014-06-16 14:04:32 -070068 } else {
mtklein90c471e2014-06-16 14:04:32 -070069 src.draw(recorder.beginRecording(src.width(), src.height(), bbhFactory));
commit-bot@chromium.orga8582232014-01-13 19:09:36 +000070 }
mtklein887f3972014-06-17 12:08:15 -070071 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
mtklein90c471e2014-06-16 14:04:32 -070072}
commit-bot@chromium.orga8582232014-01-13 19:09:36 +000073
mtklein90c471e2014-06-16 14:04:32 -070074static void bench_record(const SkPicture& src,
75 const double timerOverhead,
76 const char* name,
77 SkBBHFactory* bbhFactory) {
78 // Rerecord once to warm up any caches. Otherwise the first sample can be very noisy.
79 rerecord(src, bbhFactory);
80
81 // Rerecord once to see how many times we should loop to make timer overhead insignificant.
mtklein9ac68ee2014-06-20 11:29:20 -070082 WallTimer timer;
83 const double scale = timescale();
mtklein90c471e2014-06-16 14:04:32 -070084 do {
mtklein9ac68ee2014-06-20 11:29:20 -070085 timer.start();
mtklein90c471e2014-06-16 14:04:32 -070086 rerecord(src, bbhFactory);
87 timer.end();
mtklein9ac68ee2014-06-20 11:29:20 -070088 } while (timer.fWall * scale < timerOverhead); // Loop just in case something bizarre happens.
mtklein90c471e2014-06-16 14:04:32 -070089
90 // We want (timer overhead / measurement) to be less than FLAGS_overheadGoal.
91 // So in each sample, we'll loop enough times to have made that true for our first measurement.
92 const int loops = (int)ceil(timerOverhead / timer.fWall / FLAGS_overheadGoal);
93
94 SkAutoTMalloc<double> samples(FLAGS_samples);
95 for (int i = 0; i < FLAGS_samples; i++) {
mtklein9ac68ee2014-06-20 11:29:20 -070096 timer.start();
mtklein90c471e2014-06-16 14:04:32 -070097 for (int j = 0; j < loops; j++) {
98 rerecord(src, bbhFactory);
99 }
100 timer.end();
mtklein9ac68ee2014-06-20 11:29:20 -0700101 samples[i] = timer.fWall * scale / loops;
mtklein90c471e2014-06-16 14:04:32 -0700102 }
103
104 Stats stats(samples.get(), FLAGS_samples);
105 if (FLAGS_verbose == 0) {
106 printf("%g\t%s\n", stats.min, name);
107 } else if (FLAGS_verbose == 1) {
108 // Get a rough idea of how noisy the measurements were.
109 const double noisePercent = 100 * sqrt(stats.var) / stats.mean;
110 printf("%g\t%g\t%g\t±%.0f%%\t%s\n", stats.min, stats.mean, stats.max, noisePercent, name);
111 } else if (FLAGS_verbose == 2) {
112 printf("%s", name);
113 for (int i = 0; i < FLAGS_samples; i++) {
114 printf("\t%g", samples[i]);
115 }
116 printf("\n");
117 }
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000118}
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000119
120int tool_main(int argc, char** argv);
121int tool_main(int argc, char** argv) {
122 SkCommandLineFlags::Parse(argc, argv);
123 SkAutoGraphics autoGraphics;
124
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000125 if (FLAGS_bbh.count() > 1) {
126 SkDebugf("Multiple bbh arguments supplied.\n");
commit-bot@chromium.org450d9ef2014-03-03 17:51:12 +0000127 return 1;
128 }
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000129
130 SkAutoTDelete<SkBBHFactory> bbhFactory(parse_FLAGS_bbh());
mtklein90c471e2014-06-16 14:04:32 -0700131
132 // Each run will use this timer overhead estimate to guess how many times it should run.
133 static const int kOverheadLoops = 10000000;
mtklein9ac68ee2014-06-20 11:29:20 -0700134 WallTimer timer;
mtklein90c471e2014-06-16 14:04:32 -0700135 double overheadEstimate = 0.0;
mtklein9ac68ee2014-06-20 11:29:20 -0700136 const double scale = timescale();
mtklein90c471e2014-06-16 14:04:32 -0700137 for (int i = 0; i < kOverheadLoops; i++) {
mtklein9ac68ee2014-06-20 11:29:20 -0700138 timer.start();
mtklein90c471e2014-06-16 14:04:32 -0700139 timer.end();
mtklein9ac68ee2014-06-20 11:29:20 -0700140 overheadEstimate += timer.fWall * scale;
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000141 }
mtklein90c471e2014-06-16 14:04:32 -0700142 overheadEstimate /= kOverheadLoops;
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000143
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000144 SkOSFile::Iter it(FLAGS_skps[0], ".skp");
145 SkString filename;
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000146 bool failed = false;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000147 while (it.next(&filename)) {
commit-bot@chromium.org5da5b592014-04-21 14:59:59 +0000148 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) {
149 continue;
150 }
151
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000152 const SkString path = SkOSPath::SkPathJoin(FLAGS_skps[0], filename.c_str());
153
154 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path.c_str()));
155 if (!stream) {
156 SkDebugf("Could not read %s.\n", path.c_str());
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000157 failed = true;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000158 continue;
159 }
commit-bot@chromium.org16182f72014-03-28 16:08:18 +0000160 SkAutoTUnref<SkPicture> src(
161 SkPicture::CreateFromStream(stream, sk_tools::LazyDecodeBitmap));
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000162 if (!src) {
163 SkDebugf("Could not read %s as an SkPicture.\n", path.c_str());
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000164 failed = true;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000165 continue;
166 }
mtklein90c471e2014-06-16 14:04:32 -0700167 bench_record(*src, overheadEstimate, filename.c_str(), bbhFactory.get());
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000168 }
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000169 return failed ? 1 : 0;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000170}
171
172#if !defined SK_BUILD_FOR_IOS
173int main(int argc, char * const argv[]) {
174 return tool_main(argc, (char**) argv);
175}
176#endif