Index: tools/bbh_shootout.cpp |
diff --git a/tools/bbh_shootout.cpp b/tools/bbh_shootout.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0c2e2e3a37933963f0fdfadaffc250ca88a25433 |
--- /dev/null |
+++ b/tools/bbh_shootout.cpp |
@@ -0,0 +1,201 @@ |
+/* |
+ * 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 "Timer.h" |
+#include "Benchmark.h" |
+#include "LazyDecodeBitmap.h" |
+#include "PictureBenchmark.h" |
+#include "PictureRenderer.h" |
+#include "SkCommandLineFlags.h" |
+#include "SkForceLinking.h" |
+#include "SkGraphics.h" |
+#include "SkStream.h" |
+#include "SkString.h" |
+#include "SkTArray.h" |
+ |
+typedef sk_tools::PictureRenderer::BBoxHierarchyType BBoxType; |
+static const int kBBoxTypeCount = sk_tools::PictureRenderer::kLast_BBoxHierarchyType + 1; |
+ |
+ |
+DEFINE_string2(skps, r, "", "The list of SKPs to benchmark."); |
+DEFINE_string(bb_types, "", "The set of bbox types to test. If empty, all are tested. " |
+ "Should be one or more of none, rtree, tilegrid."); |
+DEFINE_int32(record, 100, "Number of times to record each SKP."); |
+DEFINE_int32(playback, 1, "Number of times to playback each SKP."); |
+DEFINE_int32(tilesize, 256, "The size of a tile."); |
+ |
+struct Measurement { |
+ SkString fName; |
+ double fRecordAverage[kBBoxTypeCount]; |
+ double fPlaybackAverage[kBBoxTypeCount]; |
+}; |
+ |
+const char* kBBoxHierarchyTypeNames[kBBoxTypeCount] = { |
+ "none", // kNone_BBoxHierarchyType |
+ "rtree", // kRTree_BBoxHierarchyType |
+}; |
+ |
+static SkPicture* pic_from_path(const char path[]) { |
+ SkFILEStream stream(path); |
+ if (!stream.isValid()) { |
+ SkDebugf("-- Can't open '%s'\n", path); |
+ return NULL; |
+ } |
+ return SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap); |
+} |
+ |
+/** |
+ * This function is the sink to which all work ends up going. |
+ * @param renderer The renderer to use to perform the work. |
+ * To measure rendering, use a TiledPictureRenderer. |
+ * To measure recording, use a RecordPictureRenderer. |
+ * @param bBoxType The bounding box hierarchy type to use. |
+ * @param pic The picture to draw to the renderer. |
+ * @param numRepeats The number of times to repeat the draw. |
+ * @param timer The timer used to benchmark the work. |
+ */ |
+static void do_benchmark_work(sk_tools::PictureRenderer* renderer, |
+ BBoxType bBoxType, |
+ SkPicture* pic, |
+ const int numRepeats, |
+ Timer* timer) { |
+ renderer->setBBoxHierarchyType(bBoxType); |
+ renderer->init(pic, NULL, NULL, NULL, false, false); |
+ |
+ SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats); |
+ for (int i = 0; i < numRepeats; ++i) { |
+ renderer->setup(); |
+ // Render once to fill caches |
+ renderer->render(); |
+ // Render again to measure |
+ timer->start(); |
+ renderer->render(); |
+ timer->end(); |
+ } |
+} |
+ |
+int tool_main(int argc, char** argv); |
+int tool_main(int argc, char** argv) { |
+ SkCommandLineFlags::Parse(argc, argv); |
+ SkAutoGraphics ag; |
+ bool includeBBoxType[kBBoxTypeCount]; |
+ for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
+ includeBBoxType[bBoxType] = (FLAGS_bb_types.count() == 0) || |
+ FLAGS_bb_types.contains(kBBoxHierarchyTypeNames[bBoxType]); |
+ } |
+ // go through all the pictures |
+ SkTArray<Measurement> measurements; |
+ for (int index = 0; index < FLAGS_skps.count(); ++index) { |
+ const char* path = FLAGS_skps[index]; |
+ SkPicture* picture = pic_from_path(path); |
+ if (NULL == picture) { |
+ SkDebugf("Couldn't create picture. Ignoring path: %s\n", path); |
+ continue; |
+ } |
+ SkDebugf("Benchmarking path: %s\n", path); |
+ Measurement& measurement = measurements.push_back(); |
+ measurement.fName = path; |
+ for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
+ if (!includeBBoxType[bBoxType]) { continue; } |
+ if (FLAGS_playback > 0) { |
+#if SK_SUPPORT_GPU |
+ GrContext::Options grContextOpts; |
+ sk_tools::TiledPictureRenderer playbackRenderer(grContextOpts); |
+#else |
+ sk_tools::TiledPictureRenderer playbackRenderer; |
+#endif |
+ Timer playbackTimer; |
+ do_benchmark_work(&playbackRenderer, (BBoxType)bBoxType, |
+ picture, FLAGS_playback, &playbackTimer); |
+ measurement.fPlaybackAverage[bBoxType] = playbackTimer.fCpu; |
+ } |
+ if (FLAGS_record > 0) { |
+#if SK_SUPPORT_GPU |
+ GrContext::Options grContextOpts; |
+ sk_tools::RecordPictureRenderer recordRenderer(grContextOpts); |
+#else |
+ sk_tools::RecordPictureRenderer recordRenderer; |
+#endif |
+ Timer recordTimer; |
+ do_benchmark_work(&recordRenderer, (BBoxType)bBoxType, |
+ picture, FLAGS_record, &recordTimer); |
+ measurement.fRecordAverage[bBoxType] = recordTimer.fCpu; |
+ } |
+ } |
+ } |
+ |
+ Measurement globalMeasurement; |
+ for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
+ if (!includeBBoxType[bBoxType]) { continue; } |
+ globalMeasurement.fPlaybackAverage[bBoxType] = 0; |
+ globalMeasurement.fRecordAverage[bBoxType] = 0; |
+ for (int index = 0; index < measurements.count(); ++index) { |
+ const Measurement& measurement = measurements[index]; |
+ globalMeasurement.fPlaybackAverage[bBoxType] += |
+ measurement.fPlaybackAverage[bBoxType]; |
+ globalMeasurement.fRecordAverage[bBoxType] += |
+ measurement.fRecordAverage[bBoxType]; |
+ } |
+ globalMeasurement.fPlaybackAverage[bBoxType] /= measurements.count(); |
+ globalMeasurement.fRecordAverage[bBoxType] /= measurements.count(); |
+ } |
+ |
+ // Output gnuplot readable histogram data.. |
+ const char* pbTitle = "bbh_shootout_playback.dat"; |
+ const char* recTitle = "bbh_shootout_record.dat"; |
+ SkFILEWStream playbackOut(pbTitle); |
+ SkFILEWStream recordOut(recTitle); |
+ recordOut.writeText("# "); |
+ playbackOut.writeText("# "); |
+ SkDebugf("---\n"); |
+ for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
+ if (!includeBBoxType[bBoxType]) { continue; } |
+ SkString out; |
+ out.printf("%s ", kBBoxHierarchyTypeNames[bBoxType]); |
+ recordOut.writeText(out.c_str()); |
+ playbackOut.writeText(out.c_str()); |
+ |
+ if (FLAGS_record > 0) { |
+ SkDebugf("Average %s recording time: %.3fms\n", |
+ kBBoxHierarchyTypeNames[bBoxType], |
+ globalMeasurement.fRecordAverage[bBoxType]); |
+ } |
+ if (FLAGS_playback > 0) { |
+ SkDebugf("Average %s playback time: %.3fms\n", |
+ kBBoxHierarchyTypeNames[bBoxType], |
+ globalMeasurement.fPlaybackAverage[bBoxType]); |
+ } |
+ } |
+ recordOut.writeText("\n"); |
+ playbackOut.writeText("\n"); |
+ // Write to file, and save recording averages. |
+ for (int index = 0; index < measurements.count(); ++index) { |
+ const Measurement& measurement = measurements[index]; |
+ SkString pbLine; |
+ SkString recLine; |
+ |
+ pbLine.printf("%d", index); |
+ recLine.printf("%d", index); |
+ for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
+ if (!includeBBoxType[bBoxType]) { continue; } |
+ pbLine.appendf(" %f", measurement.fPlaybackAverage[bBoxType]); |
+ recLine.appendf(" %f", measurement.fRecordAverage[bBoxType]); |
+ } |
+ pbLine.appendf("\n"); |
+ recLine.appendf("\n"); |
+ playbackOut.writeText(pbLine.c_str()); |
+ recordOut.writeText(recLine.c_str()); |
+ } |
+ SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle); |
+ return 0; |
+} |
+ |
+#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
+int main(int argc, char** argv) { |
+ return tool_main(argc, argv); |
+} |
+#endif |