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

Side by Side Diff: tools/bbh_shootout.cpp

Issue 16948011: Measure tiled rendering. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Struct to handle benchmark info. Other code review tweaks. 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
« no previous file with comments | « gyp/tools.gyp ('k') | tools/lua/bbh_filter.lua » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 static const size_t kNumBaseBenchmarks = 3;
25 static const size_t kNumTileSizes = 3;
26 // This is separate from kNumTileSizes because we may add random tile size bench marks later.
27 static const size_t kNumBbhPlaybackBenchmarks = 3;
28 static const size_t kNumBenchmarks = kNumBaseBenchmarks + kNumBbhPlaybackBenchma rks;
29
30 enum BenchmarkType {
31 kNormal_BenchmarkType = 0,
32 kRTree_BenchmarkType,
33 };
34
35 struct Histogram {
36 Histogram() {
37 // Make fCpuTime negative so that we don't mess with stats:
38 fCpuTime = SkIntToScalar(-1);
39 }
40 SkScalar fCpuTime;
41 SkString fPath;
42 };
43
44 typedef void (*BenchmarkFunction)
45 (BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*);
46
47 // Defined below.
48 static void benchmark_playback(
49 BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*) ;
50 static void benchmark_recording(
51 BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*) ;
52
53 /**
54 * Acts as a POD containing information needed to run a benchmark.
55 * Provides static methods to poll benchmark info from an index.
56 */
57 struct BenchmarkControl {
58 SkISize fTileSize;
59 BenchmarkType fType;
60 BenchmarkFunction fFunction;
61 SkString fName;
62
63 static BenchmarkControl Make(size_t i) {
64 BenchmarkControl benchControl;
65 benchControl.fTileSize = getTileSize(i);
66 benchControl.fType = getBenchmarkType(i);
67 benchControl.fFunction = getBenchmarkFunc(i);
68 benchControl.fName = getBenchmarkName(i);
69 return benchControl;
70 }
71
72 enum BaseBenchmarks {
73 kNormalRecord = 0,
74 kNormalPlayback,
75 kRTreeRecord,
76 };
77
78 static SkISize fTileSizes[kNumTileSizes];
79 static SkTArray<Histogram> fHistograms[kNumBenchmarks];
80
81 static SkISize getTileSize(size_t i) {
82 // Two of the base benchmarks don't need a tile size. But to maintain si mplicity
83 // down the pipeline we have to let a couple of values unused.
84 if (i < kNumBaseBenchmarks) {
85 return SkISize::Make(256, 256);
86 }
87 if (i >= kNumBaseBenchmarks && i < kNumBenchmarks) {
88 return fTileSizes[i - kNumBaseBenchmarks];
89 }
90 SkASSERT(0);
91 return SkISize::Make(0, 0);
92 }
93
94 static BenchmarkType getBenchmarkType(size_t i) {
95 if (i < kNumBaseBenchmarks) {
96 switch (i) {
97 case kNormalRecord:
98 return kNormal_BenchmarkType;
99 case kNormalPlayback:
100 return kNormal_BenchmarkType;
101 case kRTreeRecord:
102 return kRTree_BenchmarkType;
103 }
104 }
105 if (i < kNumBenchmarks) {
106 return kRTree_BenchmarkType;
107 } else {
108 SkASSERT(0);
109 }
110 return kRTree_BenchmarkType;
111 }
112
113 static BenchmarkFunction getBenchmarkFunc(size_t i) {
114 // Base functions.
115 switch (i) {
116 case kNormalRecord:
117 return benchmark_recording;
118 case kNormalPlayback:
119 return benchmark_playback;
120 case kRTreeRecord:
121 return benchmark_recording;
122 }
123 // RTree playbacks
124 if (i < kNumBenchmarks) {
125 return benchmark_playback;
126 } else {
127 SkASSERT(0);
128 }
129 return NULL;
130 }
131
132 static SkString getBenchmarkName(size_t i) {
133 // Base benchmark names
134 switch (i) {
135 case kNormalRecord:
136 return SkString("normal_recording");
137 case kNormalPlayback:
138 return SkString("normal_playback");
139 case kRTreeRecord:
140 return SkString("rtree_recording");
141 }
142 // RTree benchmark names.
143 if (i < kNumBenchmarks) {
144 if (i < kNumBaseBenchmarks) {
145 SkDebugf("WTF %d", i);
146 }
sglez 2013/07/13 03:57:15 Woops!!! This if block was me doing printf debuggi
147 SkASSERT(i >= kNumBaseBenchmarks);
148 SkString name;
149 name.printf("rtree_playback_%dx%d",
150 fTileSizes[i - kNumBaseBenchmarks].fWidth,
151 fTileSizes[i - kNumBaseBenchmarks].fHeight);
152 return name;
153
154 } else {
155 SkASSERT(0);
156 }
157 return SkString("");
158 }
159
160 };
161
162 SkISize BenchmarkControl::fTileSizes[kNumTileSizes] = {
163 SkISize::Make(256, 256),
164 SkISize::Make(512, 512),
165 SkISize::Make(1024, 1024),
166 };
167
168 // Defined in PictureRenderingFlags.cpp
169 extern bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap );
170
171 static SkPicture* pic_from_path(const char path[]) {
172 SkFILEStream stream(path);
173 if (!stream.isValid()) {
174 SkDebugf("-- Can't open '%s'\n", path);
175 return NULL;
176 }
177 return SkPicture::CreateFromStream(&stream, &lazy_decode_bitmap);
178 }
179
180 /**
181 * This function is the sink to which all work ends up going.
182 * Renders the picture into the renderer. It may or may not use an RTree.
183 * The renderer is chosen upstream. If we want to measure recording, we will
184 * use a RecordPictureRenderer. If we want to measure rendering, we eill use a
185 * TiledPictureRenderer.
186 */
187 static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
188 int benchmarkType, const SkString& path, SkPicture* pic,
189 const int numRepeats, const char *msg, BenchTimer* timer) {
190 SkString msgPrefix;
191
192 switch (benchmarkType){
193 case kNormal_BenchmarkType:
194 msgPrefix.set("Normal");
195 renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBox HierarchyType);
196 break;
197 case kRTree_BenchmarkType:
198 msgPrefix.set("RTree");
199 renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kRTree_BBo xHierarchyType);
200 break;
201 default:
202 SkASSERT(0);
203 break;
204 }
205
206 renderer->init(pic);
207
208 /**
209 * If the renderer is not tiled, assume we are measuring recording.
210 */
211 bool isPlayback = (NULL != renderer->getTiledRenderer());
212
213 SkDebugf("%s %s %s %d times...\n", msgPrefix.c_str(), msg, path.c_str(), num Repeats);
214 for (int i = 0; i < numRepeats; ++i) {
215 renderer->setup();
216 // Render once to fill caches.
217 renderer->render(NULL);
218 // Render again to measure
219 timer->start();
220 bool result = renderer->render(NULL);
221 timer->end();
222 // We only care about a false result on playback. RecordPictureRenderer: :render will always
223 // return false because we are passing a NULL file name on purpose; whic h is fine.
224 if(isPlayback && !result) {
225 SkDebugf("Error rendering during playback.\n");
226 }
227 }
228 renderer->end();
229 }
230
231 /**
232 * Call do_benchmark_work with a tiled renderer using the default tile dimension s.
233 */
234 static void benchmark_playback(
235 BenchmarkType benchmarkType, const SkISize& tileSize,
236 const SkString& path, SkPicture* pic, BenchTimer* timer) {
237 sk_tools::TiledPictureRenderer renderer;
238
239 SkString message("tiled_playback");
240 message.appendf("_%dx%d", tileSize.fWidth, tileSize.fHeight);
241 do_benchmark_work(&renderer, benchmarkType,
242 path, pic, kNumPlaybacks, message.c_str(), timer);
243 }
244
245 /**
246 * Call do_benchmark_work with a RecordPictureRenderer.
247 */
248 static void benchmark_recording(
249 BenchmarkType benchmarkType, const SkISize& tileSize,
250 const SkString& path, SkPicture* pic, BenchTimer* timer) {
251 sk_tools::RecordPictureRenderer renderer;
252 do_benchmark_work(&renderer, benchmarkType, path, pic, kNumRecordings, "reco rding", timer);
253 }
254
255 /**
256 * Takes argc,argv along with one of the benchmark functions defined above.
257 * Will loop along all skp files and perform measurments.
258 *
259 * Returns a SkScalar representing CPU time taken during benchmark.
260 * As a side effect, it spits the timer result to stdout.
261 * Will return -1.0 on error.
262 */
263 static SkScalar benchmark_loop(
264 int argc,
265 char **argv,
266 const BenchmarkControl& benchControl,
267 SkTArray<Histogram>& histogram) {
268
269 static const SkString timeFormat("%f");
270 TimerData timerData(timeFormat, timeFormat);
271 for (int index = 1; index < argc; ++index) {
272 BenchTimer timer;
273 SkString path(argv[index]);
274 SkAutoTUnref<SkPicture> pic(pic_from_path(path.c_str()));
275 if (NULL == pic) {
276 SkDebugf("Couldn't create picture. Ignoring path: %s\n", path.c_str( ));
277 continue;
278 }
279 benchControl.fFunction(benchControl.fType, benchControl.fTileSize, path, pic, &timer);
280 timerData.appendTimes(&timer, argc - 1 == index);
281
282 histogram[index - 1].fPath = path;
283 histogram[index - 1].fCpuTime = timer.fCpu;
284 }
285
286 const SkString timerResult = timerData.getResult(
287 /*logPerIter = */ false,
288 /*printMin = */ false,
289 /*repeatDraw = */ 1,
290 /*configName = */ benchControl.fName.c_str(),
291 /*showWallTime = */ false,
292 /*showTruncatedWallTime = */ false,
293 /*showCpuTime = */ true,
294 /*showTruncatedCpuTime = */ false,
295 /*showGpuTime = */ false);
296
297 const char findStr[] = "= ";
298 int pos = timerResult.find(findStr);
299 if (-1 == pos) {
300 SkDebugf("Unexpected output from TimerData::getResult(...). Unable to pa rse.");
301 return SkIntToScalar(-1);
302 }
303 SkDebugf("%s\n", timerResult.c_str());
304
305 SkScalar cpuTime = atof(timerResult.c_str() + pos + sizeof(findStr) - 1);
306 if (cpuTime == 0) { // atof returns 0.0 on error.
307 SkDebugf("Unable to read value from timer result.\n");
308 return SkIntToScalar(-1);
309 }
310 return cpuTime;
311 }
312
313 static int tool_main(int argc, char** argv) {
314 SkAutoGraphics ag;
315 SkString usage;
316 usage.printf("Usage: filename [filename]*\n");
317
318 if (argc < 2) {
319 SkDebugf("%s\n", usage.c_str());
320 return -1;
321 }
322
323 static SkScalar results[kNumBenchmarks];
324 static SkTArray<Histogram> histograms[kNumBenchmarks];
325
326 for (size_t i = 0; i < kNumBenchmarks; ++i) {
327 histograms[i] = SkTArray<Histogram>(argc - 1);
328 histograms[i].reset(argc - 1);
329 results[i] = benchmark_loop(
330 argc, argv,
331 BenchmarkControl::Make(i),
332 histograms[i]);
333 }
334
335 // Print results
336 SkDebugf("\n");
337 for (size_t i = 0; i < kNumBenchmarks; ++i) {
338 SkDebugf("%s total: %f\n", BenchmarkControl::getBenchmarkName(i).c_str() , results[i]);
339 }
340
341 // Print a rough analysis to stdout:
342 {
343 SkScalar normalRecordResult = results[0];
344 SkScalar normalPlaybackResult = results[1];
345 SkScalar rtreeRecordResult = results[2];
346 SkScalar rtreePlaybackResult = results[3];
347 SkASSERT(normalRecordResult != 0 && normalPlaybackResult != 0);
348 SkDebugf("\n");
349 SkDebugf("Recording: Relative difference: %.4f\n",
350 rtreeRecordResult / normalRecordResult);
351 SkDebugf("Playback (256x256): Relative difference: %.4f\n",
352 rtreePlaybackResult / normalPlaybackResult);
353 SkScalar times =
354 (kNumPlaybacks * (normalRecordResult - rtreeRecordResult)) /
355 (kNumRecordings * (rtreePlaybackResult - normalPlaybackResult));
356 SkDebugf("Number of playback repetitions for RTree to be worth it: %d (r atio: %.4f)\n",
357 SkScalarCeilToInt(times), times);
358 }
359
360 for (size_t i = 0; i < kNumBenchmarks; ++i) {
361 SkDebugf("%s\n", BenchmarkControl::getBenchmarkName(i).c_str());
362 }
363 // Print min/max times for each benchmark.
364 SkDebugf("\n");
365 SkScalar minMax[kNumBenchmarks][2];
366 enum {
367 kMinBenchmarkTime,
368 kMaxBenchmarkTime
369 };
370 for (size_t i = 0; i < kNumBenchmarks; ++i) {
371 SkString minPath;
372 SkString maxPath;
373 minMax[i][kMinBenchmarkTime] = SK_ScalarMax;
374 minMax[i][kMaxBenchmarkTime] = 0;
375 for (int j = 0; j < argc - 1; ++j) {
376 SkScalar value = histograms[i][j].fCpuTime;
377 if (value < 0) continue; // skp wasn't found or couldn't be read.
378 if (value < minMax[i][kMinBenchmarkTime]) {
379 minMax[i][kMinBenchmarkTime] = value;
380 minPath = histograms[i][j].fPath;
381 }
382 if (value > minMax[i][kMaxBenchmarkTime]) {
383 minMax[i][kMaxBenchmarkTime] = value;
384 maxPath = histograms[i][j].fPath;
385 }
386 }
387 SkDebugf("%s min is %.3f:\t\t%s\n"
388 "%s max is %.3f:\t\t%s\n",
389 BenchmarkControl::getBenchmarkName(i).c_str(), minMax[i][kMinBen chmarkTime], minPath.c_str(),
390 BenchmarkControl::getBenchmarkName(i).c_str(), minMax[i][kMaxBen chmarkTime], maxPath.c_str());
391 }
392
393 // Output gnuplot readable histogram data..
394 const char* pbTitle = "bbh_shootout_playback.dat";
395 const char* recTitle = "bbh_shootout_record.dat";
396 SkFILEWStream playbackOut(pbTitle);
397 SkFILEWStream recordOut(recTitle);
398 recordOut.writeText("# Index Normal RTree\n");
399 playbackOut.writeText("# Index Normal RTree\n");
400 for (int i = 0; i < argc - 1; ++i) {
401 SkString pbLine;
402 SkString recLine;
403 // ==== Write record info
404 recLine.printf("%d ", i);
405 recLine.appendf("%f ", histograms[0][i].fCpuTime); // Append normal_rec ord time
406 recLine.appendf("%f", histograms[2][i].fCpuTime); // Append rtree_recor d time
407
408 // ==== Write playback info
409 pbLine.printf("%d ", i);
410 pbLine.appendf("%f ", histograms[1][i].fCpuTime); // Start with normal playback time.
411 // Append all playback benchmark times.
412 for (size_t j = kNumBbhPlaybackBenchmarks; j < kNumBenchmarks; ++j) {
413 pbLine.appendf("%f ", histograms[j][i].fCpuTime);
414 }
415 pbLine.remove(pbLine.size() - 1, 1); // Remove trailing space from line .
416 pbLine.appendf("\n");
417 recLine.appendf("\n");
418 playbackOut.writeText(pbLine.c_str());
419 recordOut.writeText(recLine.c_str());
420 }
421 SkDebugf("Wrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle) ;
422
423 return 0;
424 }
425
426 int main(int argc, char** argv) {
427 return tool_main(argc, argv);
428 }
429
OLDNEW
« no previous file with comments | « gyp/tools.gyp ('k') | tools/lua/bbh_filter.lua » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698