OLD | NEW |
| (Empty) |
1 /* | |
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" | |
13 #include "SkPictureRecorder.h" | |
14 #include "SkStream.h" | |
15 #include "SkString.h" | |
16 | |
17 #include "LazyDecodeBitmap.h" | |
18 #include "Stats.h" | |
19 #include "Timer.h" | |
20 | |
21 __SK_FORCE_IMAGE_DECODER_LINKING; | |
22 | |
23 DEFINE_string2(skps, r, "skps", "Directory containing SKPs to read and re-record
."); | |
24 DEFINE_int32(samples, 10, "Number of times to re-record each SKP."); | |
25 DEFINE_int32(tileGridSize, 512, "Set the tile grid size. Has no effect if bbh is
not set to tilegrid."); | |
26 DEFINE_string(bbh, "", "Turn on the bbh and select the type, one of rtree, tileg
rid"); | |
27 DEFINE_bool(skr, false, "Record SKR instead of SKP."); | |
28 DEFINE_string(match, "", "The usual filters on file names of SKPs to bench."); | |
29 DEFINE_string(timescale, "us", "Print times in ms, us, or ns"); | |
30 DEFINE_double(overheadGoal, 0.0001, | |
31 "Try to make timer overhead at most this fraction of our sample me
asurements."); | |
32 DEFINE_int32(verbose, 0, "0: print min sample; " | |
33 "1: print min, mean, max and noise indication " | |
34 "2: print all samples"); | |
35 | |
36 static double timescale() { | |
37 if (FLAGS_timescale.contains("us")) return 1000; | |
38 if (FLAGS_timescale.contains("ns")) return 1000000; | |
39 return 1; | |
40 } | |
41 | |
42 static SkBBHFactory* parse_FLAGS_bbh() { | |
43 if (FLAGS_bbh.isEmpty()) { | |
44 return NULL; | |
45 } | |
46 | |
47 if (FLAGS_bbh.contains("rtree")) { | |
48 return SkNEW(SkRTreeFactory); | |
49 } | |
50 if (FLAGS_bbh.contains("tilegrid")) { | |
51 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)); | |
56 } | |
57 SkDebugf("Invalid bbh type %s, must be one of rtree, tilegrid.\n", FLAGS_bbh
[0]); | |
58 return NULL; | |
59 } | |
60 | |
61 static void rerecord(const SkPicture& src, SkBBHFactory* bbhFactory) { | |
62 SkPictureRecorder recorder; | |
63 if (FLAGS_skr) { | |
64 src.playback(recorder.EXPERIMENTAL_beginRecording(src.cullRect().width()
, | |
65 src.cullRect().height(), | |
66 bbhFactory)); | |
67 } else { | |
68 src.playback(recorder. DEPRECATED_beginRecording(src.cullRect().width()
, | |
69 src.cullRect().height(), | |
70 bbhFactory)); | |
71 } | |
72 SkAutoTUnref<SkPicture> pic(recorder.endRecording()); | |
73 } | |
74 | |
75 static 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 v
ery noisy. | |
80 rerecord(src, bbhFactory); | |
81 | |
82 // Rerecord once to see how many times we should loop to make timer overhead
insignificant. | |
83 WallTimer timer; | |
84 const double scale = timescale(); | |
85 do { | |
86 timer.start(); | |
87 rerecord(src, bbhFactory); | |
88 timer.end(); | |
89 } while (timer.fWall * scale < timerOverhead); // Loop just in case somethi
ng bizarre happens. | |
90 | |
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++) { | |
97 timer.start(); | |
98 for (int j = 0; j < loops; j++) { | |
99 rerecord(src, bbhFactory); | |
100 } | |
101 timer.end(); | |
102 samples[i] = timer.fWall * scale / loops; | |
103 } | |
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, no
isePercent, 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 } | |
119 } | |
120 | |
121 int tool_main(int argc, char** argv); | |
122 int tool_main(int argc, char** argv) { | |
123 SkCommandLineFlags::Parse(argc, argv); | |
124 SkAutoGraphics autoGraphics; | |
125 | |
126 if (FLAGS_bbh.count() > 1) { | |
127 SkDebugf("Multiple bbh arguments supplied.\n"); | |
128 return 1; | |
129 } | |
130 | |
131 SkAutoTDelete<SkBBHFactory> bbhFactory(parse_FLAGS_bbh()); | |
132 | |
133 // Each run will use this timer overhead estimate to guess how many times it
should run. | |
134 static const int kOverheadLoops = 10000000; | |
135 WallTimer timer; | |
136 double overheadEstimate = 0.0; | |
137 const double scale = timescale(); | |
138 for (int i = 0; i < kOverheadLoops; i++) { | |
139 timer.start(); | |
140 timer.end(); | |
141 overheadEstimate += timer.fWall * scale; | |
142 } | |
143 overheadEstimate /= kOverheadLoops; | |
144 | |
145 SkOSFile::Iter it(FLAGS_skps[0], ".skp"); | |
146 SkString filename; | |
147 bool failed = false; | |
148 while (it.next(&filename)) { | |
149 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) { | |
150 continue; | |
151 } | |
152 | |
153 const SkString path = SkOSPath::Join(FLAGS_skps[0], filename.c_str()); | |
154 | |
155 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path.c_str())); | |
156 if (!stream) { | |
157 SkDebugf("Could not read %s.\n", path.c_str()); | |
158 failed = true; | |
159 continue; | |
160 } | |
161 SkAutoTUnref<SkPicture> src( | |
162 SkPicture::CreateFromStream(stream, sk_tools::LazyDecodeBitmap)); | |
163 if (!src) { | |
164 SkDebugf("Could not read %s as an SkPicture.\n", path.c_str()); | |
165 failed = true; | |
166 continue; | |
167 } | |
168 bench_record(*src, overheadEstimate, filename.c_str(), bbhFactory.get())
; | |
169 } | |
170 return failed ? 1 : 0; | |
171 } | |
172 | |
173 #if !defined SK_BUILD_FOR_IOS | |
174 int main(int argc, char * const argv[]) { | |
175 return tool_main(argc, (char**) argv); | |
176 } | |
177 #endif | |
OLD | NEW |