blob: fe28e342a4525035925ecb5961e289834aeaa5db [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.");
mtklein2a65a232014-08-26 14:07:04 -070026DEFINE_string(bbh, "", "Turn on the bbh and select the type, one of rtree, tilegrid");
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 }
mtklein2a65a232014-08-26 14:07:04 -070057 SkDebugf("Invalid bbh type %s, must be one of rtree, tilegrid.\n", FLAGS_bbh[0]);
commit-bot@chromium.org450d9ef2014-03-03 17:51:12 +000058 return NULL;
59}
60
mtklein90c471e2014-06-16 14:04:32 -070061static void rerecord(const SkPicture& src, SkBBHFactory* bbhFactory) {
mtklein887f3972014-06-17 12:08:15 -070062 SkPictureRecorder recorder;
mtklein90c471e2014-06-16 14:04:32 -070063 if (FLAGS_skr) {
robertphillipsc5ba71d2014-09-04 08:42:50 -070064 src.playback(recorder.EXPERIMENTAL_beginRecording(src.cullRect().width(),
robertphillipsa8d7f0b2014-08-29 08:03:56 -070065 src.cullRect().height(),
66 bbhFactory));
mtklein90c471e2014-06-16 14:04:32 -070067 } else {
robertphillipsc5ba71d2014-09-04 08:42:50 -070068 src.playback(recorder. DEPRECATED_beginRecording(src.cullRect().width(),
robertphillipsa8d7f0b2014-08-29 08:03:56 -070069 src.cullRect().height(),
70 bbhFactory));
commit-bot@chromium.orga8582232014-01-13 19:09:36 +000071 }
mtklein887f3972014-06-17 12:08:15 -070072 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
mtklein90c471e2014-06-16 14:04:32 -070073}
commit-bot@chromium.orga8582232014-01-13 19:09:36 +000074
mtklein90c471e2014-06-16 14:04:32 -070075static void bench_record(const SkPicture& src,
76 const double timerOverhead,
77 const char* name,
78 SkBBHFactory* bbhFactory) {
79 // Rerecord once to warm up any caches. Otherwise the first sample can be very noisy.
80 rerecord(src, bbhFactory);
81
82 // Rerecord once to see how many times we should loop to make timer overhead insignificant.
mtklein9ac68ee2014-06-20 11:29:20 -070083 WallTimer timer;
84 const double scale = timescale();
mtklein90c471e2014-06-16 14:04:32 -070085 do {
mtklein9ac68ee2014-06-20 11:29:20 -070086 timer.start();
mtklein90c471e2014-06-16 14:04:32 -070087 rerecord(src, bbhFactory);
88 timer.end();
mtklein9ac68ee2014-06-20 11:29:20 -070089 } while (timer.fWall * scale < timerOverhead); // Loop just in case something bizarre happens.
mtklein90c471e2014-06-16 14:04:32 -070090
91 // We want (timer overhead / measurement) to be less than FLAGS_overheadGoal.
92 // So in each sample, we'll loop enough times to have made that true for our first measurement.
93 const int loops = (int)ceil(timerOverhead / timer.fWall / FLAGS_overheadGoal);
94
95 SkAutoTMalloc<double> samples(FLAGS_samples);
96 for (int i = 0; i < FLAGS_samples; i++) {
mtklein9ac68ee2014-06-20 11:29:20 -070097 timer.start();
mtklein90c471e2014-06-16 14:04:32 -070098 for (int j = 0; j < loops; j++) {
99 rerecord(src, bbhFactory);
100 }
101 timer.end();
mtklein9ac68ee2014-06-20 11:29:20 -0700102 samples[i] = timer.fWall * scale / loops;
mtklein90c471e2014-06-16 14:04:32 -0700103 }
104
105 Stats stats(samples.get(), FLAGS_samples);
106 if (FLAGS_verbose == 0) {
107 printf("%g\t%s\n", stats.min, name);
108 } else if (FLAGS_verbose == 1) {
109 // Get a rough idea of how noisy the measurements were.
110 const double noisePercent = 100 * sqrt(stats.var) / stats.mean;
111 printf("%g\t%g\t%g\t±%.0f%%\t%s\n", stats.min, stats.mean, stats.max, noisePercent, name);
112 } else if (FLAGS_verbose == 2) {
113 printf("%s", name);
114 for (int i = 0; i < FLAGS_samples; i++) {
115 printf("\t%g", samples[i]);
116 }
117 printf("\n");
118 }
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000119}
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000120
121int tool_main(int argc, char** argv);
122int tool_main(int argc, char** argv) {
123 SkCommandLineFlags::Parse(argc, argv);
124 SkAutoGraphics autoGraphics;
125
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000126 if (FLAGS_bbh.count() > 1) {
127 SkDebugf("Multiple bbh arguments supplied.\n");
commit-bot@chromium.org450d9ef2014-03-03 17:51:12 +0000128 return 1;
129 }
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000130
131 SkAutoTDelete<SkBBHFactory> bbhFactory(parse_FLAGS_bbh());
mtklein90c471e2014-06-16 14:04:32 -0700132
133 // Each run will use this timer overhead estimate to guess how many times it should run.
134 static const int kOverheadLoops = 10000000;
mtklein9ac68ee2014-06-20 11:29:20 -0700135 WallTimer timer;
mtklein90c471e2014-06-16 14:04:32 -0700136 double overheadEstimate = 0.0;
mtklein9ac68ee2014-06-20 11:29:20 -0700137 const double scale = timescale();
mtklein90c471e2014-06-16 14:04:32 -0700138 for (int i = 0; i < kOverheadLoops; i++) {
mtklein9ac68ee2014-06-20 11:29:20 -0700139 timer.start();
mtklein90c471e2014-06-16 14:04:32 -0700140 timer.end();
mtklein9ac68ee2014-06-20 11:29:20 -0700141 overheadEstimate += timer.fWall * scale;
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000142 }
mtklein90c471e2014-06-16 14:04:32 -0700143 overheadEstimate /= kOverheadLoops;
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000144
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000145 SkOSFile::Iter it(FLAGS_skps[0], ".skp");
146 SkString filename;
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000147 bool failed = false;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000148 while (it.next(&filename)) {
commit-bot@chromium.org5da5b592014-04-21 14:59:59 +0000149 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) {
150 continue;
151 }
152
tfarinaa8e2e152014-07-28 19:26:58 -0700153 const SkString path = SkOSPath::Join(FLAGS_skps[0], filename.c_str());
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000154
155 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path.c_str()));
156 if (!stream) {
157 SkDebugf("Could not read %s.\n", path.c_str());
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000158 failed = true;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000159 continue;
160 }
commit-bot@chromium.org16182f72014-03-28 16:08:18 +0000161 SkAutoTUnref<SkPicture> src(
162 SkPicture::CreateFromStream(stream, sk_tools::LazyDecodeBitmap));
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000163 if (!src) {
164 SkDebugf("Could not read %s as an SkPicture.\n", path.c_str());
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000165 failed = true;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000166 continue;
167 }
mtklein90c471e2014-06-16 14:04:32 -0700168 bench_record(*src, overheadEstimate, filename.c_str(), bbhFactory.get());
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000169 }
commit-bot@chromium.orga8582232014-01-13 19:09:36 +0000170 return failed ? 1 : 0;
commit-bot@chromium.org15ac3222014-01-13 12:03:47 +0000171}
172
173#if !defined SK_BUILD_FOR_IOS
174int main(int argc, char * const argv[]) {
175 return tool_main(argc, (char**) argv);
176}
177#endif