Chromium Code Reviews| Index: tools/bbh_shootout.cpp |
| diff --git a/tools/bbh_shootout.cpp b/tools/bbh_shootout.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..96d2014b993752bcb76ba8620dd88e3a4093ea3e |
| --- /dev/null |
| +++ b/tools/bbh_shootout.cpp |
| @@ -0,0 +1,197 @@ |
| +/* |
| + * Copyright 2013 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
| +#include "BenchTimer.h" |
| +#include "PictureBenchmark.h" |
| +#include "PictureRenderer.h" |
| +#include "PictureRenderingFlags.h" |
| +#include "SkCommandLineFlags.h" |
| +#include "SkForceLinking.h" |
| +#include "SkStream.h" |
| +#include "SkString.h" |
| +#include "SkGraphics.h" |
| +#include "TimerData.h" |
| + |
| + |
| +__SK_FORCE_IMAGE_DECODER_LINKING; |
| + |
| +static const int kNumRecordings = 10; |
| +static const int kNumPlaybacks = 1; |
| + |
| +static const int gTileDimensions[2] = {128, 128}; |
| + |
| +enum BenchmarkType { |
| + kNormal_BenchmarkType = 0, |
| + kRTree_BenchmarkType, |
| +}; |
| + |
| +// Defined in PictureRenderingFlags.cpp |
| +extern bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap); |
| + |
| +static SkPicture* pic_from_path(const char path[]) { |
| + SkFILEStream stream(path); |
| + if (!stream.isValid()) { |
| + SkDebugf("-- Can't open '%s'\n", path); |
| + return NULL; |
| + } |
| + bool success = false; |
| + SkPicture* pic = SkNEW_ARGS(SkPicture, (&stream, &success, &lazy_decode_bitmap)); |
| + if (!success) { |
| + SkDebugf("Could not create SkPicture: %s\n", path); |
| + return pic; |
|
caryclark
2013/06/28 18:09:43
just let it fall through
|
| + } |
| + return pic; |
| +} |
| + |
| +/** |
| + * This function is the sink to which all work ends up going. |
| + * Renders the picture into the renderer. It may or may not use an RTree. |
| + * The renderer is chosen upstream. If we want to measure recording, we will |
| + * use a RecordPictureRenderer. If we want to measure rendering, we eill use a |
| + * TiledPictureRenderer. |
| + */ |
| +static void do_benchmark_work(sk_tools::PictureRenderer* renderer, |
| + int benchmarkType, const SkString *path, SkPicture* pic, |
| + const int numRepeats, const char *msg) { |
| + SkASSERT(NULL != pic); |
| + |
| + SkString msgPrefix; |
| + |
| + switch (benchmarkType){ |
| + case kNormal_BenchmarkType: |
| + msgPrefix.printf("Normal"); |
| + renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBoxHierarchyType); |
| + break; |
| + case kRTree_BenchmarkType: |
| + msgPrefix.printf("RTree"); |
| + renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kRTree_BBoxHierarchyType); |
| + break; |
| + } |
| + |
| + renderer->init(pic); |
| + |
| + SkDebugf("%s %s %s %d times...\n", msgPrefix.c_str(), msg, path->c_str(), numRepeats); |
| + for(int i = 0; i < numRepeats; ++i) { |
|
caryclark
2013/06/28 18:09:43
space after for
|
| + renderer->setup(); |
| + bool result = renderer->render(path); |
| + if(!result) { |
|
caryclark
2013/06/28 18:09:43
space after if
|
| + SkDebugf("Error recording.\n"); |
| + } |
| + } |
| + renderer->end(); |
| +} |
| + |
| +/** |
| + * Call do_benchmark_work with a tiled renderer using the default tile dimensions. |
| + */ |
| +static void benchmark_playback(int benchmarkType, const SkString* path, SkPicture* pic) { |
| + SkAutoTUnref<sk_tools::TiledPictureRenderer> renderer(SkNEW(sk_tools::TiledPictureRenderer)); |
|
caryclark
2013/06/28 18:09:43
Since this just lives on the stack, do you need to
sglez
2013/07/01 15:34:38
Changed it to live on the stack.
|
| + SkASSERT(NULL != renderer); |
| + |
| + renderer->setTileWidth(gTileDimensions[0]); |
| + renderer->setTileHeight(gTileDimensions[1]); |
| + |
| + do_benchmark_work(renderer, benchmarkType, path, pic, kNumPlaybacks, "tiled playback"); |
| +} |
| + |
| +/** |
| + * Call do_benchmark_work with a RecordPictureRenderer. |
| + */ |
| +static void benchmark_recording(int benchmarkType, const SkString* path, SkPicture* pic) { |
| + SkAutoTUnref<sk_tools::PictureRenderer> renderer(SkNEW(sk_tools::RecordPictureRenderer)); |
| + SkASSERT(NULL != renderer); |
| + |
| + do_benchmark_work(renderer, benchmarkType, path, pic, kNumRecordings, "recording"); |
| +} |
| + |
| +/** |
| + * Returns a SkScalar representing CPU time for a TimerData. |
| + * As a side effect, it spits the timer result to stdout. |
| + */ |
| +static SkScalar get_data_result(TimerData &timerData, const char *configName) { |
| + const SkString timerResult = timerData.getResult( |
| + /*logPerIter=*/false, /*printMin=*/false, /*repeatDraw*/1, |
| + /*configName*/configName, |
| + /*showWallTime=*/false, /*showTruncatedWallTime=*/false, /*showCpuTime=*/true, |
| + /*showTruncatedCpuTime=*/false, /*showGpuTime=*/false |
|
caryclark
2013/06/28 18:09:43
Good documentation, if a little hard to read. Use
|
| + ); |
| + const char findStr[] = "= "; |
| + int pos = timerResult.find(findStr); |
|
caryclark
2013/06/28 18:09:43
error check if find fails?
|
| + SkDebugf("%s\n", timerResult.c_str()); |
|
caryclark
2013/06/28 18:09:43
probably should put debug before find in case find
|
| + const SkScalar cpuTime = atof(timerResult.c_str() + pos + sizeof(findStr) - 1); |
|
caryclark
2013/06/28 18:09:43
const doesn't add any information here
|
| + return cpuTime; |
|
caryclark
2013/06/28 18:09:43
error check atof ?
|
| +} |
| + |
| +static const SkString perIterTimeFormat = SkString("%f"); |
|
caryclark
2013/06/28 18:09:43
... perIterTimeFormat("%f");
etc.
|
| +static const SkString normalTimeFormat = SkString("%f"); |
| + |
| +/** |
| + * Takes argc,argv along with one of the benchmark functions defined above. |
| + * Will loop along all skp files and perform a measurment; then it will return |
| + * that measurement. |
| + */ |
| +TimerData benchmark_loop( |
| + int argc, |
| + char **argv, |
| + void (*func)(int, const SkString*, SkPicture*), |
| + int benchmarkType) { |
| + TimerData timerData(perIterTimeFormat, normalTimeFormat); |
| + for(int index = 1; index < argc; ++index) { |
|
caryclark
2013/06/28 18:09:43
space after for
|
| + BenchTimer timer; |
| + const SkString path = SkString(argv[index]); |
|
caryclark
2013/06/28 18:09:43
path(argv[index])
|
| + timer.start(); |
| + SkAutoTUnref<SkPicture> pic(pic_from_path(argv[index])); |
|
caryclark
2013/06/28 18:09:43
no auto unref required, I don't think, e.g.
SkPic
sglez
2013/07/01 15:34:38
pic_from_path was returning a pointer. I modified
|
| + func(benchmarkType, &path, pic); |
| + timer.end(); |
| + timerData.appendTimes(&timer, index == argc - 1); |
| + } |
| + return timerData; |
| +} |
| + |
| +int tool_main(int argc, char** argv); |
|
caryclark
2013/06/28 18:09:43
is this seen by someone external to this file, i.e
sglez
2013/07/01 15:34:38
I was following the crowd. Everyone defines tool_m
|
| +int tool_main(int argc, char** argv) { |
| + SkAutoGraphics ag; |
| + SkString usage; |
| + usage.printf("Usage: filename [filename]*\n"); |
| + |
| + if (argc < 2) { |
| + SkDebugf("%s\n", usage.c_str()); |
| + } |
| + |
| + TimerData normalRecordData = |
| + benchmark_loop(argc, argv, benchmark_recording, kNormal_BenchmarkType); |
| + TimerData rtreeRecordData = |
| + benchmark_loop(argc, argv, benchmark_recording, kRTree_BenchmarkType); |
| + TimerData normalPlaybackData = |
| + benchmark_loop(argc, argv, benchmark_playback, kNormal_BenchmarkType); |
| + TimerData rtreePlaybackData = |
| + benchmark_loop(argc, argv, benchmark_playback, kRTree_BenchmarkType); |
| + |
| + const SkScalar normalRecordResult = get_data_result(normalRecordData, "normal_record"); |
| + const SkScalar rtreeRecordResult = get_data_result(rtreeRecordData, "rtree_record"); |
| + const SkScalar normalPlaybackResult = get_data_result(normalPlaybackData, "normal_playback"); |
| + const SkScalar rtreePlaybackResult = get_data_result(rtreePlaybackData, "rtree_playback"); |
|
caryclark
2013/06/28 18:09:43
not sure const adds any value here
|
| + |
| + SkASSERT(normalRecordResult != 0 && normalPlaybackResult != 0); |
| + SkDebugf("Recording: Relative difference: %.4f\n", rtreeRecordResult / normalRecordResult); |
| + SkDebugf("Playback: Relative difference: %.4f\n", rtreePlaybackResult / normalPlaybackResult); |
| + |
| + SkScalar times = |
| + (kNumPlaybacks * (normalRecordResult - rtreeRecordResult)) / |
| + (kNumRecordings * (rtreePlaybackResult - normalPlaybackResult)); |
| + |
| + SkDebugf("Number of playback repetitions for RTree to be worth it: %d (ratio: %.4f)\n", |
| + SkScalarCeilToInt(times), times); |
| + |
| + return 0; |
| +} |
| +#undef BENCHMARK_LOOP |
| + |
| +int main(int argc, char** argv) { |
| + return tool_main(argc, argv); |
| +} |
| + |