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); |
+} |
+ |