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

Unified Diff: tools/bbh_shootout.cpp

Issue 194903003: Revert of New version of the bbh shootout (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/PictureRenderer.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/bbh_shootout.cpp
diff --git a/tools/bbh_shootout.cpp b/tools/bbh_shootout.cpp
index 6475ab18b45e5f08eaeed534a5dd06beb6581767..fa1739c3b573a34bc904af925678391afc86bdb9 100644
--- a/tools/bbh_shootout.cpp
+++ b/tools/bbh_shootout.cpp
@@ -15,30 +15,155 @@
#include "SkStream.h"
#include "SkString.h"
#include "SkTArray.h"
-#include "SkCommandLineFlags.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(bbh, "", "The set of bbox types to test. If empty, all are tested. "
- "Should be one or more of none, quadtree, 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 {
+#include "TimerData.h"
+
+static const int kNumNormalRecordings = 10;
+static const int kNumRTreeRecordings = 10;
+static const int kNumPlaybacks = 1;
+static const size_t kNumBaseBenchmarks = 3;
+static const size_t kNumTileSizes = 3;
+static const size_t kNumBbhPlaybackBenchmarks = 3;
+static const size_t kNumBenchmarks = kNumBaseBenchmarks + kNumBbhPlaybackBenchmarks;
+
+enum BenchmarkType {
+ kNormal_BenchmarkType = 0,
+ kRTree_BenchmarkType,
+};
+
+struct Histogram {
+ Histogram() {
+ // Make fCpuTime negative so that we don't mess with stats:
+ fCpuTime = SkIntToScalar(-1);
+ }
+ SkScalar fCpuTime;
+ SkString fPath;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Defined below.
+struct BenchmarkControl;
+
+typedef void (*BenchmarkFunction)
+ (const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*);
+
+static void benchmark_playback(
+ const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*);
+static void benchmark_recording(
+ const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*);
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Acts as a POD containing information needed to run a benchmark.
+ * Provides static methods to poll benchmark info from an index.
+ */
+struct BenchmarkControl {
+ SkISize fTileSize;
+ BenchmarkType fType;
+ BenchmarkFunction fFunction;
SkString fName;
- SkScalar fRecordAverage[kBBoxTypeCount];
- SkScalar fPlaybackAverage[kBBoxTypeCount];
+
+ /**
+ * Will construct a BenchmarkControl instance from an index between 0 an kNumBenchmarks.
+ */
+ static BenchmarkControl Make(size_t i) {
+ SkASSERT(kNumBenchmarks > i);
+ BenchmarkControl benchControl;
+ benchControl.fTileSize = GetTileSize(i);
+ benchControl.fType = GetBenchmarkType(i);
+ benchControl.fFunction = GetBenchmarkFunc(i);
+ benchControl.fName = GetBenchmarkName(i);
+ return benchControl;
+ }
+
+ enum BaseBenchmarks {
+ kNormalRecord = 0,
+ kRTreeRecord,
+ kNormalPlayback,
+ };
+
+ static SkISize fTileSizes[kNumTileSizes];
+
+ static SkISize GetTileSize(size_t i) {
+ // Two of the base benchmarks don't need a tile size. But to maintain simplicity
+ // down the pipeline we have to let a couple of values unused.
+ if (i < kNumBaseBenchmarks) {
+ return SkISize::Make(256, 256);
+ }
+ if (i >= kNumBaseBenchmarks && i < kNumBenchmarks) {
+ return fTileSizes[i - kNumBaseBenchmarks];
+ }
+ SkASSERT(0);
+ return SkISize::Make(0, 0);
+ }
+
+ static BenchmarkType GetBenchmarkType(size_t i) {
+ if (i < kNumBaseBenchmarks) {
+ switch (i) {
+ case kNormalRecord:
+ return kNormal_BenchmarkType;
+ case kNormalPlayback:
+ return kNormal_BenchmarkType;
+ case kRTreeRecord:
+ return kRTree_BenchmarkType;
+ }
+ }
+ if (i < kNumBenchmarks) {
+ return kRTree_BenchmarkType;
+ }
+ SkASSERT(0);
+ return kRTree_BenchmarkType;
+ }
+
+ static BenchmarkFunction GetBenchmarkFunc(size_t i) {
+ // Base functions.
+ switch (i) {
+ case kNormalRecord:
+ return benchmark_recording;
+ case kNormalPlayback:
+ return benchmark_playback;
+ case kRTreeRecord:
+ return benchmark_recording;
+ }
+ // RTree playbacks
+ if (i < kNumBenchmarks) {
+ return benchmark_playback;
+ }
+ SkASSERT(0);
+ return NULL;
+ }
+
+ static SkString GetBenchmarkName(size_t i) {
+ // Base benchmark names
+ switch (i) {
+ case kNormalRecord:
+ return SkString("normal_recording");
+ case kNormalPlayback:
+ return SkString("normal_playback");
+ case kRTreeRecord:
+ return SkString("rtree_recording");
+ }
+ // RTree benchmark names.
+ if (i < kNumBenchmarks) {
+ SkASSERT(i >= kNumBaseBenchmarks);
+ SkString name;
+ name.printf("rtree_playback_%dx%d",
+ fTileSizes[i - kNumBaseBenchmarks].fWidth,
+ fTileSizes[i - kNumBaseBenchmarks].fHeight);
+ return name;
+
+ } else {
+ SkASSERT(0);
+ }
+ return SkString("");
+ }
+
};
-const char* kBBoxHierarchyTypeNames[kBBoxTypeCount] = {
- "none", // kNone_BBoxHierarchyType
- "quadtree", // kQuadTree_BBoxHierarchyType
- "rtree", // kRTree_BBoxHierarchyType
- "tilegrid", // kTileGrid_BBoxHierarchyType
+SkISize BenchmarkControl::fTileSizes[kNumTileSizes] = {
+ SkISize::Make(256, 256),
+ SkISize::Make(512, 512),
+ SkISize::Make(1024, 1024),
};
static SkPicture* pic_from_path(const char path[]) {
@@ -51,90 +176,162 @@
}
/**
+ * Returns true when a tiled renderer with no bounding box hierarchy produces the given bitmap.
+ */
+static bool compare_picture(const SkString& path, const SkBitmap& inBitmap, SkPicture* pic) {
+ SkBitmap* bitmap;
+ sk_tools::TiledPictureRenderer renderer;
+ renderer.setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBoxHierarchyType);
+ renderer.init(pic);
+ renderer.setup();
+ renderer.render(&path, &bitmap);
+ SkAutoTDelete<SkBitmap> bmDeleter(bitmap);
+ renderer.end();
+
+ if (bitmap->getSize() != inBitmap.getSize()) {
+ return false;
+ }
+ return !memcmp(bitmap->getPixels(), inBitmap.getPixels(), bitmap->getSize());
+}
+
+/**
* 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.
+ * 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 will use a
+ * TiledPictureRenderer.
*/
static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
- BBoxType bBoxType,
- SkPicture* pic,
- const int numRepeats,
- BenchTimer* timer) {
- renderer->setBBoxHierarchyType(bBoxType);
- renderer->setGridSize(FLAGS_tilesize, FLAGS_tilesize);
+ int benchmarkType, const SkString& path, SkPicture* pic,
+ const int numRepeats, const char *msg, BenchTimer* timer) {
+ SkString msgPrefix;
+
+ switch (benchmarkType){
+ case kNormal_BenchmarkType:
+ msgPrefix.set("Normal");
+ renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBoxHierarchyType);
+ break;
+ case kRTree_BenchmarkType:
+ msgPrefix.set("RTree");
+ renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kRTree_BBoxHierarchyType);
+ break;
+ default:
+ SkASSERT(0);
+ break;
+ }
+
renderer->init(pic);
- SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats);
+ /**
+ * If the renderer is not tiled, assume we are measuring recording.
+ */
+ bool isPlayback = (NULL != renderer->getTiledRenderer());
+ // Will be non-null during RTree picture playback. For correctness test.
+ SkBitmap* bitmap = NULL;
+
+ SkDebugf("%s %s %s %d times...\n", msgPrefix.c_str(), msg, path.c_str(), numRepeats);
for (int i = 0; i < numRepeats; ++i) {
+ // Set up the bitmap.
+ SkBitmap** out = NULL;
+ if (i == 0 && kRTree_BenchmarkType == benchmarkType && isPlayback) {
+ out = &bitmap;
+ }
+
renderer->setup();
- // Render once to fill caches
- renderer->render(NULL, NULL);
+ // Render once to fill caches. Fill bitmap during the first iteration.
+ renderer->render(NULL, out);
// Render again to measure
timer->start();
- renderer->render(NULL);
+ bool result = renderer->render(NULL);
timer->end();
+
+ // We only care about a false result on playback. RecordPictureRenderer::render will always
+ // return false because we are passing a NULL file name on purpose; which is fine.
+ if (isPlayback && !result) {
+ SkDebugf("Error rendering during playback.\n");
+ }
+ }
+ if (bitmap) {
+ SkAutoTDelete<SkBitmap> bmDeleter(bitmap);
+ if (!compare_picture(path, *bitmap, pic)) {
+ SkDebugf("Error: RTree produced different bitmap\n");
+ }
+ }
+}
+
+/**
+ * Call do_benchmark_work with a tiled renderer using the default tile dimensions.
+ */
+static void benchmark_playback(
+ const BenchmarkControl& benchControl,
+ const SkString& path, SkPicture* pic, BenchTimer* timer) {
+ sk_tools::TiledPictureRenderer renderer;
+
+ SkString message("tiled_playback");
+ message.appendf("_%dx%d", benchControl.fTileSize.fWidth, benchControl.fTileSize.fHeight);
+ do_benchmark_work(&renderer, benchControl.fType,
+ path, pic, kNumPlaybacks, message.c_str(), timer);
+}
+
+/**
+ * Call do_benchmark_work with a RecordPictureRenderer.
+ */
+static void benchmark_recording(
+ const BenchmarkControl& benchControl,
+ const SkString& path, SkPicture* pic, BenchTimer* timer) {
+ sk_tools::RecordPictureRenderer renderer;
+ int numRecordings = 0;
+ switch(benchControl.fType) {
+ case kRTree_BenchmarkType:
+ numRecordings = kNumRTreeRecordings;
+ break;
+ case kNormal_BenchmarkType:
+ numRecordings = kNumNormalRecordings;
+ break;
+ }
+ do_benchmark_work(&renderer, benchControl.fType,
+ path, pic, numRecordings, "recording", timer);
+}
+
+/**
+ * Takes argc,argv along with one of the benchmark functions defined above.
+ * Will loop along all skp files and perform measurments.
+ */
+static void benchmark_loop(
+ int argc,
+ char **argv,
+ const BenchmarkControl& benchControl,
+ SkTArray<Histogram>& histogram) {
+ for (int index = 1; index < argc; ++index) {
+ BenchTimer timer;
+ SkString path(argv[index]);
+ SkAutoTUnref<SkPicture> pic(pic_from_path(path.c_str()));
+ if (NULL == pic) {
+ SkDebugf("Couldn't create picture. Ignoring path: %s\n", path.c_str());
+ continue;
+ }
+ benchControl.fFunction(benchControl, path, pic, &timer);
+ histogram[index - 1].fPath = path;
+ histogram[index - 1].fCpuTime = SkDoubleToScalar(timer.fCpu);
}
}
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_bbh.count() == 0) ||
- FLAGS_bbh.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) {
- sk_tools::TiledPictureRenderer playbackRenderer;
- BenchTimer playbackTimer;
- do_benchmark_work(&playbackRenderer, (BBoxType)bBoxType,
- picture, FLAGS_playback, &playbackTimer);
- measurement.fPlaybackAverage[bBoxType] = playbackTimer.fCpu;
- }
- if (FLAGS_record > 0) {
- sk_tools::RecordPictureRenderer recordRenderer;
- BenchTimer 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();
+ SkString usage;
+ usage.printf("Usage: filename [filename]*\n");
+
+ if (argc < 2) {
+ SkDebugf("%s\n", usage.c_str());
+ return -1;
+ }
+
+ SkTArray<Histogram> histograms[kNumBenchmarks];
+
+ for (size_t i = 0; i < kNumBenchmarks; ++i) {
+ histograms[i].reset(argc - 1);
+ benchmark_loop(argc, argv, BenchmarkControl::Make(i), histograms[i]);
}
// Output gnuplot readable histogram data..
@@ -144,46 +341,62 @@
SkFILEWStream recordOut(recTitle);
recordOut.writeText("# ");
playbackOut.writeText("# ");
- SkDebugf("---\n");
- for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
- if (!includeBBoxType[bBoxType]) { continue; }
+ for (size_t i = 0; i < kNumBenchmarks; ++i) {
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]);
+ out.printf("%s ", BenchmarkControl::GetBenchmarkName(i).c_str());
+ if (BenchmarkControl::GetBenchmarkFunc(i) == &benchmark_recording) {
+ recordOut.writeText(out.c_str());
+ }
+ if (BenchmarkControl::GetBenchmarkFunc(i) == &benchmark_playback) {
+ playbackOut.writeText(out.c_str());
}
}
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];
+ SkScalar avgRecord = SkIntToScalar(0);
+ SkScalar avgPlayback = SkIntToScalar(0);
+ SkScalar avgRecordRTree = SkIntToScalar(0);
+ SkScalar avgPlaybackRTree = SkIntToScalar(0);
+ for (int i = 0; i < argc - 1; ++i) {
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]);
- }
+ // ==== Write record info
+ recLine.printf("%d ", i);
+ SkScalar cpuTime = histograms[BenchmarkControl::kNormalRecord][i].fCpuTime;
+ recLine.appendf("%f ", cpuTime);
+ avgRecord += cpuTime;
+ cpuTime = histograms[BenchmarkControl::kRTreeRecord][i].fCpuTime;
+ recLine.appendf("%f", cpuTime);
+ avgRecordRTree += cpuTime;
+ avgPlaybackRTree += cpuTime;
+
+ // ==== Write playback info
+ pbLine.printf("%d ", i);
+ pbLine.appendf("%f ", histograms[2][i].fCpuTime); // Start with normal playback time.
+ avgPlayback += histograms[kNumBbhPlaybackBenchmarks - 1][i].fCpuTime;
+ avgPlaybackRTree += histograms[kNumBbhPlaybackBenchmarks][i].fCpuTime;
+ // Append all playback benchmark times.
+ for (size_t j = kNumBbhPlaybackBenchmarks; j < kNumBenchmarks; ++j) {
+ pbLine.appendf("%f ", histograms[j][i].fCpuTime);
+ }
+ pbLine.remove(pbLine.size() - 1, 1); // Remove trailing space from line.
pbLine.appendf("\n");
recLine.appendf("\n");
playbackOut.writeText(pbLine.c_str());
recordOut.writeText(recLine.c_str());
}
+ avgRecord /= argc - 1;
+ avgRecordRTree /= argc - 1;
+ avgPlayback /= argc - 1;
+ avgPlaybackRTree /= argc - 1;
+ SkDebugf("Average base recording time: %.3fms\n", avgRecord);
+ SkDebugf("Average recording time with rtree: %.3fms\n", avgRecordRTree);
+ SkDebugf("Average base playback time: %.3fms\n", avgPlayback);
+ SkDebugf("Average playback time with rtree: %.3fms\n", avgPlaybackRTree);
+
SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle);
+
return 0;
}
« no previous file with comments | « tools/PictureRenderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698