Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: tools/bbh_shootout.cpp

Issue 16948011: Measure tiled rendering. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Code review fixes Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright 2013 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 "BenchTimer.h"
9 #include "PictureBenchmark.h"
10 #include "PictureRenderer.h"
11 #include "PictureRenderingFlags.h"
12 #include "SkBenchmark.h"
13 #include "SkCommandLineFlags.h"
14 #include "SkForceLinking.h"
15 #include "SkGraphics.h"
16 #include "SkStream.h"
17 #include "SkString.h"
18 #include "TimerData.h"
19
20 __SK_FORCE_IMAGE_DECODER_LINKING;
21
22 static const int kNumRecordings = SkBENCHLOOP(10);
23 static const int kNumPlaybacks = SkBENCHLOOP(5);
24
25 enum BenchmarkType {
26 kNormal_BenchmarkType = 0,
27 kRTree_BenchmarkType,
28 };
29
30 struct Histogram {
caryclark 2013/07/12 13:13:28 Add Histogram() : fCpuTime(SkIntToScalar(-1))
31 SkScalar fCpuTime;
32 SkString fPath;
33 };
34
35 // Defined in PictureRenderingFlags.cpp
36 extern bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap );
caryclark 2013/07/12 13:13:28 since it's also used by bench_pictures_main.cpp, l
sglez 2013/07/13 03:57:15 CL sent
37
38 static SkPicture* pic_from_path(const char path[]) {
39 SkFILEStream stream(path);
40 if (!stream.isValid()) {
41 SkDebugf("-- Can't open '%s'\n", path);
42 return NULL;
43 }
44 return SkPicture::CreateFromStream(&stream, &lazy_decode_bitmap);
45 }
46
47 /**
48 * This function is the sink to which all work ends up going.
49 * Renders the picture into the renderer. It may or may not use an RTree.
50 * The renderer is chosen upstream. If we want to measure recording, we will
51 * use a RecordPictureRenderer. If we want to measure rendering, we eill use a
52 * TiledPictureRenderer.
53 */
54 static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
55 int benchmarkType, const SkString& path, SkPicture* pic,
56 const int numRepeats, const char *msg, BenchTimer* timer) {
57 SkString msgPrefix;
58
59 switch (benchmarkType){
60 case kNormal_BenchmarkType:
61 msgPrefix.set("Normal");
62 renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBox HierarchyType);
63 break;
64 case kRTree_BenchmarkType:
65 msgPrefix.set("RTree");
66 renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kRTree_BBo xHierarchyType);
67 break;
68 default:
69 SkASSERT(0);
70 break;
71 }
72
73 renderer->init(pic);
74
75 /**
76 * If the renderer is not tiled, assume we are measuring recording.
77 */
78 bool recording = (NULL == renderer->getTiledRenderer());
79
80 SkDebugf("%s %s %s %d times...\n", msgPrefix.c_str(), msg, path.c_str(), num Repeats);
81 for (int i = 0; i < numRepeats; ++i) {
82 renderer->setup();
83 // Render once to fill caches.
84 renderer->render(NULL);
85 // Render again to measure
86 timer->start();
87 bool result = renderer->render(NULL);
88 timer->end();
89 // We only care about a false result on playback. RecordPictureRenderer: :render will always
90 // return false because we are passing a NULL ptr.
91 if(!recording && !result) {
92 SkDebugf("Error rendering (playback).\n");
caryclark 2013/07/12 13:13:28 If recording == false, this will print the debug m
sglez 2013/07/13 03:57:15 RecordPictureRenderer::render(..), returns false w
caryclark 2013/07/15 12:00:15 My mistake. I misread the && for an ||. On 2013/0
93 }
94 }
95 renderer->end();
96 }
97
98 /**
99 * Call do_benchmark_work with a tiled renderer using the default tile dimension s.
100 */
101 static void benchmark_playback(
102 BenchmarkType benchmarkType, const int tileSize[2],
103 const SkString& path, SkPicture* pic, BenchTimer* timer) {
104 sk_tools::TiledPictureRenderer renderer;
105
106 SkString message("tiled_playback");
107 message.appendf("_%dx%d", tileSize[0], tileSize[1]);
108 do_benchmark_work(&renderer, benchmarkType,
109 path, pic, kNumPlaybacks, message.c_str(), timer);
110 }
111
112 /**
113 * Call do_benchmark_work with a RecordPictureRenderer.
114 */
115 static void benchmark_recording(
116 BenchmarkType benchmarkType, const int tileSize[2],
117 const SkString& path, SkPicture* pic, BenchTimer* timer) {
118 sk_tools::RecordPictureRenderer renderer;
119 do_benchmark_work(&renderer, benchmarkType, path, pic, kNumRecordings, "reco rding", timer);
120 }
121
122 static const SkString perIterTimeFormat("%f");
123 static const SkString normalTimeFormat("%f");
124
125 /**
126 * Takes argc,argv along with one of the benchmark functions defined above.
127 * Will loop along all skp files and perform measurments.
128 *
129 * Returns a SkScalar representing CPU time taken during benchmark.
130 * As a side effect, it spits the timer result to stdout.
131 * Will return -1.0 on error.
132 */
133 static SkScalar benchmark_loop(
134 int argc,
135 char **argv,
136 void (*func)(BenchmarkType, const int[], const SkString&, SkPicture*, Be nchTimer*),
caryclark 2013/07/12 13:13:28 below, you use const int[kNumBenchMarks]. Make the
sglez 2013/07/13 03:57:15 Yes, I should have typedef'd that some time ago.
137 const int tileSize[2],
caryclark 2013/07/12 13:13:28 I assume the '2' is the number of tile dimensions,
sglez 2013/07/13 03:57:15 In this instance, I think having a struct would be
138 SkTArray<Histogram>& histogram,
139 BenchmarkType benchmarkType,
140 const char* configName) {
141 TimerData timerData(perIterTimeFormat, normalTimeFormat);
142 for (int index = 1; index < argc; ++index) {
caryclark 2013/07/12 13:13:28 this seems inconsistent. If argc == 1, this loop e
sglez 2013/07/13 03:57:15 If argc == 1 this loop doesn't excecute :)
caryclark 2013/07/15 12:00:15 Understood -- my mistake again. See, aren't code r
143 BenchTimer timer;
144 SkString path(argv[index]);
145 SkAutoTUnref<SkPicture> pic(pic_from_path(argv[index]));
146 if (NULL == pic) {
147 SkDebugf("Couldn't create picture. Ignoring path: %s\n", path.c_str( ));
caryclark 2013/07/12 13:13:28 Here you use path.c_str() for char* . A couple lin
148 // Make fCpuTime negative so that we don't mess with stats:
149 histogram[index - 1].fCpuTime = SkIntToScalar(-1);
caryclark 2013/07/12 13:13:28 move this to the struct constructor (see above)
150 continue;
151 }
152 func(benchmarkType, tileSize, path, pic, &timer);
caryclark 2013/07/12 13:13:28 (*func)(benchmarkType ...
153 timerData.appendTimes(&timer, index == argc - 1);
caryclark 2013/07/12 13:13:28 this is a good place to reverse this to argc - 1
154
155 histogram[index - 1].fPath = path;
156 histogram[index - 1].fCpuTime = timer.fCpu;
157 }
158
159 const SkString timerResult = timerData.getResult(
160 /*logPerIter = */ false,
161 /*printMin = */ false,
162 /*repeatDraw = */ 1,
163 /*configName = */ configName,
164 /*showWallTime = */ false,
165 /*showTruncatedWallTime = */ false,
166 /*showCpuTime = */ true,
167 /*showTruncatedCpuTime = */ false,
168 /*showGpuTime = */ false);
169
170 const char findStr[] = "= ";
171 int pos = timerResult.find(findStr);
172 if (-1 == pos) {
173 SkDebugf("Unexpected output from TimerData::getResult(...). Unable to pa rse.");
174 return SkIntToScalar(-1);
175 }
176 SkDebugf("%s\n", timerResult.c_str());
177
178 SkScalar cpuTime = atof(timerResult.c_str() + pos + sizeof(findStr) - 1);
179 if (cpuTime == SkIntToScalar(0)) { // atof returns 0.0 on error.
caryclark 2013/07/12 13:13:28 0 is always 0, so you can say if (cpuTime == 0) {
180 SkDebugf("Unable to read value from timer result.\n");
181 return SkIntToScalar(-1);
182 }
183 return cpuTime;
184 }
185
186 static int tool_main(int argc, char** argv) {
187 SkAutoGraphics ag;
188 SkString usage;
189 usage.printf("Usage: filename [filename]*\n");
190
191 if (argc < 2) {
192 SkDebugf("%s\n", usage.c_str());
caryclark 2013/07/12 13:13:28 return something other than zero in the error case
193 return 0;
194 }
195
196 static const int tileSizes[][2] = {
197 {256, 256},
198 {512, 512},
199 {1024, 1024},
200 };
201 static const size_t kNumTileSizes = SK_ARRAY_COUNT(tileSizes);
202 static const size_t kNumBenchmarks = 3 + kNumTileSizes;
caryclark 2013/07/12 13:13:28 you want kNumBaseBenches (or another name of your
203 static SkString benchNames[kNumBenchmarks];
204
205 benchNames[0] = "normal_recording";
206 benchNames[1] = "normal_playback";
207 benchNames[2] = "rtree_recording";
208 for (size_t i = 0; i < kNumTileSizes; ++i) {
209 SkString benchName;
210 benchName.printf("rtree_playback_%dx%d", tileSizes[i][0], tileSizes[i][1 ]);
caryclark 2013/07/12 13:13:28 earlier, you set the name in the string and did ap
211 benchNames[i + kNumTileSizes] = benchName.c_str();
caryclark 2013/07/12 13:13:28 kNumTileSizes isn't what you want here. You need a
212 }
213 static SkScalar results[kNumBenchmarks];
214 static SkTArray<Histogram> histograms[kNumBenchmarks];
215
216 static void (*baseBenchmarkFunctions[3])
217 (BenchmarkType, const int [kNumBenchmarks], const SkString&, SkPicture*, BenchTimer*) = {
218 benchmark_recording, // normal_recording
219 benchmark_playback, // normal_playback
220 benchmark_recording, // rtree_recording
221 };
caryclark 2013/07/12 13:13:28 this is one possibility for const int kNumBaseBen
222
223 for (size_t i = 0; i < kNumBenchmarks; ++i) {
224 BenchmarkType type;
225 if (i < 2) {
226 type = kNormal_BenchmarkType;
227 } else {
228 type = kRTree_BenchmarkType;
caryclark 2013/07/12 13:13:28 I'm not crazy about benchNames being initialized i
sglez 2013/07/13 03:57:15 This comment made me do a big change. I hope I was
229 }
230 int tileSize[2] = {256, 256};
231 static void (*benchmarkFunction)
232 (BenchmarkType, const int [kNumBenchmarks], const SkString&, SkPictu re*, BenchTimer*);
233 if (i < 3) {
234 benchmarkFunction = baseBenchmarkFunctions[i];
235 } else {
236 // If our bencmark is of the type rtree_playback_[SIZE]:
237 // Set tileSize and set benchmark to playback.
238 tileSize[0] = tileSizes[i - 3][0];
239 tileSize[1] = tileSizes[i - 3][1];
caryclark 2013/07/12 13:13:28 lots of '3's here :)
240 benchmarkFunction = benchmark_playback;
241 }
242 histograms[i] = SkTArray<Histogram>(argc - 1);
243 histograms[i].reset(argc - 1);
244 results[i] = benchmark_loop(
245 argc, argv, benchmarkFunction, tileSize, histograms[i],
246 type, benchNames[i].c_str());
247 }
248
249 // Print results
250 SkDebugf("\n");
251 for (size_t i = 0; i < kNumBenchmarks; ++i) {
252 SkDebugf("%s total: %f\n", benchNames[i].c_str(), results[i]);
253 }
254
255 // Print a rough analysis to stdout:
256 {
257 SkScalar normalRecordResult = results[0];
258 SkScalar normalPlaybackResult = results[1];
259 SkScalar rtreeRecordResult = results[2];
260 SkScalar rtreePlaybackResult = results[3];
261 SkASSERT(normalRecordResult != 0 && normalPlaybackResult != 0);
262 SkDebugf("\n");
263 SkDebugf("Recording: Relative difference: %.4f\n",
264 rtreeRecordResult / normalRecordResult);
265 SkDebugf("Playback (256x256): Relative difference: %.4f\n",
266 rtreePlaybackResult / normalPlaybackResult);
267 SkScalar times =
268 (kNumPlaybacks * (normalRecordResult - rtreeRecordResult)) /
269 (kNumRecordings * (rtreePlaybackResult - normalPlaybackResult));
caryclark 2013/07/12 13:13:28 what about if rtreePlaybackResult == normalPlaybac
sglez 2013/07/13 03:57:15 I missed this comment and didn't address it. I wil
270 SkDebugf("Number of playback repetitions for RTree to be worth it: %d (r atio: %.4f)\n",
271 SkScalarCeilToInt(times), times);
272 }
273
274 // Print min/max times for each benchmark.
275 SkDebugf("\n");
276 SkScalar minMax[kNumBenchmarks][2];
caryclark 2013/07/12 13:13:28 2 being one for min, one for max. Good place for a
277 for (size_t i = 0; i < kNumBenchmarks; ++i) {
278 SkString minPath;
279 SkString maxPath;
280 minMax[i][0] = SK_ScalarMax;
281 minMax[i][1] = 0;
282 for (int j = 0; j < argc - 1; ++j) {
283 SkScalar value = histograms[i][j].fCpuTime;
284 if (value < 0) continue; // skp wasn't found or couldn't be read.
285 if (value < minMax[i][0]) {
286 minMax[i][0] = value;
caryclark 2013/07/12 13:13:28 I prefer the pattern of if (a op b) { a = b; bu
sglez 2013/07/13 03:57:15 Normally I would agree, but when doing min/max I p
287 minPath = histograms[i][j].fPath;
288 }
289 if (value > minMax[i][1]) {
290 minMax[i][1] = value;
291 maxPath = histograms[i][j].fPath;
292 }
293 }
294 SkDebugf("%s min is %.3f:\t\t%s\n"
295 "%s max is %.3f:\t\t%s\n",
296 benchNames[i].c_str(), minMax[i][0], minPath.c_str(),
297 benchNames[i].c_str(), minMax[i][1], maxPath.c_str());
298 }
299
300 // Output gnuplot readable histogram data..
301 const char* pbTitle = "bbh_shootout_playback.dat";
302 const char* recTitle = "bbh_shootout_record.dat";
303 SkFILEWStream playbackOut(pbTitle);
304 SkFILEWStream recordOut(recTitle);
305 recordOut.writeText("# Index Normal RTree\n");
306 playbackOut.writeText("# Index Normal RTree\n");
307 for (int i = 0; i < argc - 1; ++i) {
308 SkString pbLine;
309 SkString recLine;
310 // ==== Write record info
311 recLine.printf("%d ", i);
312 recLine.appendf("%f ", histograms[0][i].fCpuTime); // Append normal_rec ord time
313 recLine.appendf("%f ", histograms[2][i].fCpuTime); // Append rtree_reco rd time
314
315 // ==== Write playback info
316 pbLine.printf("%d ", i);
317 pbLine.appendf("%f ", histograms[1][i].fCpuTime); // Start with normal playback time.
318 // Append all playback benchmark times.
319 for (size_t j = kNumTileSizes; j < kNumBenchmarks; ++j) {
320 pbLine.appendf("%f ", histograms[j][i].fCpuTime);
caryclark 2013/07/12 13:13:28 this puts a final ' ' followed by a '\n'
sglez 2013/07/13 03:57:15 Added a line that trims the trailing space.
321 }
322 pbLine.appendf("\n");
323 recLine.appendf("\n");
324 playbackOut.writeText(pbLine.c_str());
325 recordOut.writeText(recLine.c_str());
326 }
327 SkDebugf("Wrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle) ;
328
329 return 0;
330 }
331
332 int main(int argc, char** argv) {
333 return tool_main(argc, argv);
334 }
335
OLDNEW
« no previous file with comments | « gyp/tools.gyp ('k') | tools/lua/bbh_filter.lua » ('j') | tools/lua/bbh_filter.lua » ('J')

Powered by Google App Engine
This is Rietveld 408576698