blob: a9cca9658f96e0a36a565cfc8ff5b62e1bb34d37 [file] [log] [blame]
reed@google.com006db0f2012-06-27 19:33:29 +00001/*
2 * Copyright 2012 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"
keyar@chromium.orgcf6c44c2012-07-09 19:37:40 +00009#include "SamplePipeControllers.h"
reed@google.com006db0f2012-06-27 19:33:29 +000010#include "SkBitmap.h"
11#include "SkCanvas.h"
keyar@chromium.orgcf6c44c2012-07-09 19:37:40 +000012#include "SkGPipe.h"
reed@google.com006db0f2012-06-27 19:33:29 +000013#include "SkOSFile.h"
14#include "SkPicture.h"
15#include "SkStream.h"
16#include "SkTArray.h"
17#include "picture_utils.h"
18
19const int DEFAULT_REPEATS = 100;
20const int DEFAULT_TILE_WIDTH = 256;
21const int DEFAULT_TILE_HEIGHT = 256;
22
23struct Options;
keyar@chromium.orga4091ba2012-07-10 19:53:59 +000024static void run_simple_benchmark(SkPicture* picture, const Options&);
reed@google.com006db0f2012-06-27 19:33:29 +000025
26struct Options {
27 int fRepeats;
keyar@chromium.orga4091ba2012-07-10 19:53:59 +000028 void (*fBenchmark) (SkPicture*, const Options& options);
reed@google.com006db0f2012-06-27 19:33:29 +000029 int fTileWidth;
30 int fTileHeight;
keyar@chromium.org0665f252012-07-10 18:30:18 +000031 double fTileWidthPercentage;
32 double fTileHeightPercentage;
reed@google.com006db0f2012-06-27 19:33:29 +000033
34 Options() : fRepeats(DEFAULT_REPEATS), fBenchmark(run_simple_benchmark),
keyar@chromium.org0665f252012-07-10 18:30:18 +000035 fTileWidth(DEFAULT_TILE_WIDTH), fTileHeight(DEFAULT_TILE_HEIGHT),
36 fTileWidthPercentage(0), fTileHeightPercentage(0){}
reed@google.com006db0f2012-06-27 19:33:29 +000037};
38
39static void usage(const char* argv0) {
40 SkDebugf("SkPicture benchmarking tool\n");
41 SkDebugf("\n"
42"Usage: \n"
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000043" %s <inputDir>...\n"
reed@google.com006db0f2012-06-27 19:33:29 +000044" [--repeat] [--tile width height]"
45, argv0);
46 SkDebugf("\n\n");
47 SkDebugf(
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000048" inputDir: A list of directories and files to use as input.\n"
49" Files are expected to have the .skp extension.\n\n");
reed@google.com006db0f2012-06-27 19:33:29 +000050 SkDebugf(
keyar@chromium.orgcf6c44c2012-07-09 19:37:40 +000051" --pipe : "
52"Set to use piping."
53" Default is to not use piping.\n");
54 SkDebugf(
keyar@chromium.org21e3ed22012-07-16 19:20:14 +000055" --record : "
56"Set to do a picture recording benchmark. Default is not to do this.\n");
57 SkDebugf(
reed@google.com006db0f2012-06-27 19:33:29 +000058" --repeat : "
59"Set the number of times to repeat each test."
60" Default is %i.\n", DEFAULT_REPEATS);
61 SkDebugf(
keyar@chromium.org0665f252012-07-10 18:30:18 +000062" --tile width[%] height[%]: "
63"Set to use the tiling size and specify the dimensions of each tile.\n"
64" Default is to not use tiling\n");
keyar@chromium.org49169712012-07-12 19:19:55 +000065 SkDebugf(
66" --unflatten: "
67"Set to do a picture unflattening benchmark. Default is not to do this.\n");
reed@google.com006db0f2012-06-27 19:33:29 +000068}
69
keyar@chromium.orga4091ba2012-07-10 19:53:59 +000070static void run_simple_benchmark(SkPicture* picture, const Options& options) {
71 SkBitmap bitmap;
72 sk_tools::setup_bitmap(&bitmap, picture->width(), picture->height());
73
reed@google.com006db0f2012-06-27 19:33:29 +000074 SkCanvas canvas(bitmap);
75
76 // We throw this away to remove first time effects (such as paging in this
77 // program)
78 canvas.drawPicture(*picture);
79
80 BenchTimer timer = BenchTimer(NULL);
81 timer.start();
82 for (int i = 0; i < options.fRepeats; ++i) {
83 canvas.drawPicture(*picture);
84 }
85 timer.end();
86
keyar@chromium.orgb5e30ab2012-07-12 21:16:49 +000087 printf("simple: msecs = %6.2f\n", timer.fWall / options.fRepeats);
reed@google.com006db0f2012-06-27 19:33:29 +000088}
89
90struct TileInfo {
91 SkBitmap* fBitmap;
92 SkCanvas* fCanvas;
93};
94
keyar@chromium.org70b42222012-07-09 19:51:05 +000095static void clip_tile(SkPicture* picture, const TileInfo& tile) {
keyar@chromium.org3e8483e2012-07-13 18:15:04 +000096 SkRect clip = SkRect::MakeWH(SkIntToScalar(picture->width()),
robertphillips@google.com59f46b82012-07-10 17:30:58 +000097 SkIntToScalar(picture->height()));
keyar@chromium.org70b42222012-07-09 19:51:05 +000098 tile.fCanvas->clipRect(clip);
99}
100
keyar@chromium.org3e8483e2012-07-13 18:15:04 +0000101static void setup_single_tile(SkPicture* picture, const Options& options,
102 SkTArray<TileInfo>* tiles, int tile_x_start, int tile_y_start) {
reed@google.com006db0f2012-06-27 19:33:29 +0000103 TileInfo& tile = tiles->push_back();
keyar@chromium.org70b42222012-07-09 19:51:05 +0000104
keyar@chromium.org3e8483e2012-07-13 18:15:04 +0000105 tile.fBitmap = new SkBitmap();
106 sk_tools::setup_bitmap(tile.fBitmap, options.fTileWidth, options.fTileHeight);
107
108 tile.fCanvas = new SkCanvas(*(tile.fBitmap));
109 tile.fCanvas->translate(SkIntToScalar(-tile_x_start), SkIntToScalar(-tile_y_start));
keyar@chromium.org70b42222012-07-09 19:51:05 +0000110 clip_tile(picture, tile);
reed@google.com006db0f2012-06-27 19:33:29 +0000111}
112
keyar@chromium.org3e8483e2012-07-13 18:15:04 +0000113static void setup_tiles(SkPicture* picture, const Options& options, SkTArray<TileInfo>* tiles) {
reed@google.com006db0f2012-06-27 19:33:29 +0000114 for (int tile_y_start = 0; tile_y_start < picture->height();
115 tile_y_start += options.fTileHeight) {
116 for (int tile_x_start = 0; tile_x_start < picture->width();
117 tile_x_start += options.fTileWidth) {
keyar@chromium.org3e8483e2012-07-13 18:15:04 +0000118 setup_single_tile(picture, options, tiles, tile_x_start, tile_y_start);
reed@google.com006db0f2012-06-27 19:33:29 +0000119 }
120 }
121
122}
123
keyar@chromium.orga4091ba2012-07-10 19:53:59 +0000124static void run_tile_benchmark(SkPicture* picture, const Options& options) {
reed@google.com006db0f2012-06-27 19:33:29 +0000125 SkTArray<TileInfo> tiles;
keyar@chromium.org3e8483e2012-07-13 18:15:04 +0000126 setup_tiles(picture, options, &tiles);
reed@google.com006db0f2012-06-27 19:33:29 +0000127
128 // We throw this away to remove first time effects (such as paging in this
129 // program)
130 for (int j = 0; j < tiles.count(); ++j) {
131 tiles[j].fCanvas->drawPicture(*picture);
132 }
133
134 BenchTimer timer = BenchTimer(NULL);
135 timer.start();
136 for (int i = 0; i < options.fRepeats; ++i) {
137 for (int j = 0; j < tiles.count(); ++j) {
138 tiles[j].fCanvas->drawPicture(*picture);
139 }
140 }
141 timer.end();
142
143 for (int i = 0; i < tiles.count(); ++i) {
144 delete tiles[i].fCanvas;
145 delete tiles[i].fBitmap;
146 }
147
keyar@chromium.orgb5e30ab2012-07-12 21:16:49 +0000148 printf("%i_tiles_%ix%i: msecs = %6.2f\n", tiles.count(), options.fTileWidth,
reed@google.com006db0f2012-06-27 19:33:29 +0000149 options.fTileHeight, timer.fWall / options.fRepeats);
150}
151
keyar@chromium.orgcf6c44c2012-07-09 19:37:40 +0000152static void pipe_run(SkPicture* picture, SkCanvas* canvas) {
153 PipeController pipeController(canvas);
154 SkGPipeWriter writer;
155 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
156 pipeCanvas->drawPicture(*picture);
157 writer.endRecording();
158}
159
keyar@chromium.orga4091ba2012-07-10 19:53:59 +0000160static void run_pipe_benchmark(SkPicture* picture, const Options& options) {
161 SkBitmap bitmap;
162 sk_tools::setup_bitmap(&bitmap, picture->width(), picture->height());
163
keyar@chromium.orgcf6c44c2012-07-09 19:37:40 +0000164 SkCanvas canvas(bitmap);
165
166 // We throw this away to remove first time effects (such as paging in this
167 // program)
168 pipe_run(picture, &canvas);
169
170 BenchTimer timer = BenchTimer(NULL);
171 timer.start();
172 for (int i = 0; i < options.fRepeats; ++i) {
173 pipe_run(picture, &canvas);
174 }
175 timer.end();
176
keyar@chromium.orgb5e30ab2012-07-12 21:16:49 +0000177 printf("pipe: msecs = %6.2f\n", timer.fWall / options.fRepeats);
keyar@chromium.orgcf6c44c2012-07-09 19:37:40 +0000178}
179
keyar@chromium.org49169712012-07-12 19:19:55 +0000180static void run_unflatten_benchmark(SkPicture* commands, const Options& options) {
181 BenchTimer timer = BenchTimer(NULL);
182 double wall_time = 0;
183
184 for (int i = 0; i < options.fRepeats + 1; ++i) {
185 SkPicture replayer;
186 SkCanvas* recorder = replayer.beginRecording(commands->width(), commands->height());
187
188 recorder->drawPicture(*commands);
189
190 timer.start();
191 replayer.endRecording();
192 timer.end();
193
194 // We want to ignore first time effects
195 if (i > 0) {
196 wall_time += timer.fWall;
197 }
198 }
199
keyar@chromium.orgb5e30ab2012-07-12 21:16:49 +0000200 printf("unflatten: msecs = %6.4f\n", wall_time / options.fRepeats);
keyar@chromium.org49169712012-07-12 19:19:55 +0000201}
202
keyar@chromium.org21e3ed22012-07-16 19:20:14 +0000203static void run_record_benchmark(SkPicture* commands, const Options& options) {
204 BenchTimer timer = BenchTimer(NULL);
205 double wall_time = 0;
206
207 for (int i = 0; i < options.fRepeats + 1; ++i) {
208 SkPicture replayer;
209 SkCanvas* recorder = replayer.beginRecording(commands->width(), commands->height());
210
211 timer.start();
212 recorder->drawPicture(*commands);
213 timer.end();
214
215 // We want to ignore first time effects
216 if (i > 0) {
217 wall_time += timer.fWall;
218 }
219 }
220
221 printf("record: msecs = %6.5f\n", wall_time / options.fRepeats);
222}
223
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000224static void run_single_benchmark(const SkString& inputPath,
keyar@chromium.org0665f252012-07-10 18:30:18 +0000225 Options* options) {
reed@google.com006db0f2012-06-27 19:33:29 +0000226 SkFILEStream inputStream;
227
reed@google.com006db0f2012-06-27 19:33:29 +0000228 inputStream.setPath(inputPath.c_str());
229 if (!inputStream.isValid()) {
230 SkDebugf("Could not open file %s\n", inputPath.c_str());
231 return;
232 }
233
234 SkPicture picture(&inputStream);
reed@google.com006db0f2012-06-27 19:33:29 +0000235
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000236 SkString filename;
237 sk_tools::get_basename(&filename, inputPath);
reed@google.com006db0f2012-06-27 19:33:29 +0000238 printf("running bench [%i %i] %s ", picture.width(), picture.height(),
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000239 filename.c_str());
240
keyar@chromium.org0665f252012-07-10 18:30:18 +0000241 if (options->fTileWidthPercentage > 0) {
242 options->fTileWidth = sk_float_ceil2int(options->fTileWidthPercentage * picture.width()
243 / 100);
244 }
245 if (options->fTileHeightPercentage > 0) {
246 options->fTileHeight = sk_float_ceil2int(options->fTileHeightPercentage * picture.height()
247 / 100);
248 }
249
keyar@chromium.orga4091ba2012-07-10 19:53:59 +0000250 options->fBenchmark(&picture, *options);
keyar@chromium.org0665f252012-07-10 18:30:18 +0000251}
252
253static bool is_percentage(char* const string) {
254 SkString skString(string);
255 return skString.endsWith("%");
reed@google.com006db0f2012-06-27 19:33:29 +0000256}
257
258static void parse_commandline(int argc, char* const argv[],
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000259 SkTArray<SkString>* inputs, Options* options) {
reed@google.com006db0f2012-06-27 19:33:29 +0000260 const char* argv0 = argv[0];
261 char* const* stop = argv + argc;
262
263 for (++argv; argv < stop; ++argv) {
264 if (0 == strcmp(*argv, "--repeat")) {
265 ++argv;
266 if (argv < stop) {
267 options->fRepeats = atoi(*argv);
268 if (options->fRepeats < 1) {
269 SkDebugf("--repeat must be given a value > 0\n");
270 exit(-1);
271 }
272 } else {
273 SkDebugf("Missing arg for --repeat\n");
274 usage(argv0);
275 exit(-1);
276 }
277 } else if (0 == strcmp(*argv, "--tile")) {
278 options->fBenchmark = run_tile_benchmark;
279 ++argv;
280 if (argv < stop) {
keyar@chromium.org0665f252012-07-10 18:30:18 +0000281 if (is_percentage(*argv)) {
282 options->fTileWidthPercentage = atof(*argv);
283 if (!(options->fTileWidthPercentage > 0)) {
284 SkDebugf("--tile must be given a width percentage > 0\n");
285 exit(-1);
286 }
287 } else {
288 options->fTileWidth = atoi(*argv);
289 if (!(options->fTileWidth > 0)) {
290 SkDebugf("--tile must be given a width > 0\n");
291 exit(-1);
292 }
reed@google.com006db0f2012-06-27 19:33:29 +0000293 }
294 } else {
295 SkDebugf("Missing width for --tile\n");
296 usage(argv0);
297 exit(-1);
298 }
299 ++argv;
300 if (argv < stop) {
keyar@chromium.org0665f252012-07-10 18:30:18 +0000301 if (is_percentage(*argv)) {
302 options->fTileHeightPercentage = atof(*argv);
303 if (!(options->fTileHeightPercentage > 0)) {
304 SkDebugf(
305 "--tile must be given a height percentage > 0\n");
306 exit(-1);
307 }
308 } else {
309 options->fTileHeight = atoi(*argv);
310 if (!(options->fTileHeight > 0)) {
311 SkDebugf("--tile must be given a height > 0\n");
312 exit(-1);
313 }
reed@google.com006db0f2012-06-27 19:33:29 +0000314 }
315 } else {
316 SkDebugf("Missing height for --tile\n");
keyar@chromium.org0665f252012-07-10 18:30:18 +0000317 usage(argv0);
reed@google.com006db0f2012-06-27 19:33:29 +0000318 exit(-1);
319 }
keyar@chromium.orgcf6c44c2012-07-09 19:37:40 +0000320 } else if (0 == strcmp(*argv, "--pipe")) {
321 options->fBenchmark = run_pipe_benchmark;
keyar@chromium.org21e3ed22012-07-16 19:20:14 +0000322 } else if (0 == strcmp(*argv, "--record")) {
323 options->fBenchmark = run_record_benchmark;
keyar@chromium.org49169712012-07-12 19:19:55 +0000324 } else if (0 == strcmp(*argv, "--unflatten")) {
325 options->fBenchmark = run_unflatten_benchmark;
reed@google.com006db0f2012-06-27 19:33:29 +0000326 } else if (0 == strcmp(*argv, "--help") || 0 == strcmp(*argv, "-h")) {
327 usage(argv0);
328 exit(0);
329 } else {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000330 inputs->push_back(SkString(*argv));
reed@google.com006db0f2012-06-27 19:33:29 +0000331 }
332 }
333
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000334 if (inputs->count() < 1) {
reed@google.com006db0f2012-06-27 19:33:29 +0000335 usage(argv0);
336 exit(-1);
337 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000338}
reed@google.com006db0f2012-06-27 19:33:29 +0000339
keyar@chromium.org0665f252012-07-10 18:30:18 +0000340static void process_input(const SkString& input, Options* options) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000341 SkOSFile::Iter iter(input.c_str(), "skp");
342 SkString inputFilename;
343
344 if (iter.next(&inputFilename)) {
345 do {
346 SkString inputPath;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000347 sk_tools::make_filepath(&inputPath, input,
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000348 inputFilename);
349 run_single_benchmark(inputPath, options);
350 } while(iter.next(&inputFilename));
351 } else {
352 run_single_benchmark(input, options);
353 }
reed@google.com006db0f2012-06-27 19:33:29 +0000354}
355
356int main(int argc, char* const argv[]) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000357 SkTArray<SkString> inputs;
reed@google.com006db0f2012-06-27 19:33:29 +0000358 Options options;
359
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000360 parse_commandline(argc, argv, &inputs, &options);
reed@google.com006db0f2012-06-27 19:33:29 +0000361
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000362 for (int i = 0; i < inputs.count(); ++i) {
keyar@chromium.org0665f252012-07-10 18:30:18 +0000363 process_input(inputs[i], &options);
reed@google.com006db0f2012-06-27 19:33:29 +0000364 }
365}