Index: tools/bbh_shootout.cpp |
diff --git a/tools/bbh_shootout.cpp b/tools/bbh_shootout.cpp |
index 9de0bfcf828ab91a493307d2173beb9bfbdeb085..76e8d074c3f78a37c82a67dd70325c913aa714ed 100644 |
--- a/tools/bbh_shootout.cpp |
+++ b/tools/bbh_shootout.cpp |
@@ -19,7 +19,7 @@ |
static const int kNumNormalRecordings = SkBENCHLOOP(10); |
static const int kNumRTreeRecordings = SkBENCHLOOP(10); |
-static const int kNumPlaybacks = SkBENCHLOOP(4); |
+static const int kNumPlaybacks = SkBENCHLOOP(1); |
static const size_t kNumBaseBenchmarks = 3; |
static const size_t kNumTileSizes = 3; |
static const size_t kNumBbhPlaybackBenchmarks = 3; |
@@ -39,14 +39,19 @@ struct Histogram { |
SkString fPath; |
}; |
-typedef void (*BenchmarkFunction) |
- (BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*); |
+//////////////////////////////////////////////////////////////////////////////// |
// Defined below. |
+struct BenchmarkControl; |
+ |
+typedef void (*BenchmarkFunction) |
+ (const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*); |
+ |
static void benchmark_playback( |
- BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*); |
+ const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*); |
static void benchmark_recording( |
- BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*); |
+ const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*); |
+//////////////////////////////////////////////////////////////////////////////// |
/** |
* Acts as a POD containing information needed to run a benchmark. |
@@ -64,10 +69,10 @@ struct BenchmarkControl { |
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); |
+ benchControl.fTileSize = GetTileSize(i); |
+ benchControl.fType = GetBenchmarkType(i); |
+ benchControl.fFunction = GetBenchmarkFunc(i); |
+ benchControl.fName = GetBenchmarkName(i); |
return benchControl; |
} |
@@ -79,7 +84,7 @@ struct BenchmarkControl { |
static SkISize fTileSizes[kNumTileSizes]; |
- static SkISize getTileSize(size_t i) { |
+ 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) { |
@@ -92,15 +97,15 @@ struct BenchmarkControl { |
return SkISize::Make(0, 0); |
} |
- static BenchmarkType getBenchmarkType(size_t i) { |
+ 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; |
+ case kNormalRecord: |
+ return kNormal_BenchmarkType; |
+ case kNormalPlayback: |
+ return kNormal_BenchmarkType; |
+ case kRTreeRecord: |
+ return kRTree_BenchmarkType; |
} |
} |
if (i < kNumBenchmarks) { |
@@ -110,7 +115,7 @@ struct BenchmarkControl { |
return kRTree_BenchmarkType; |
} |
- static BenchmarkFunction getBenchmarkFunc(size_t i) { |
+ static BenchmarkFunction GetBenchmarkFunc(size_t i) { |
// Base functions. |
switch (i) { |
case kNormalRecord: |
@@ -128,7 +133,7 @@ struct BenchmarkControl { |
return NULL; |
} |
- static SkString getBenchmarkName(size_t i) { |
+ static SkString GetBenchmarkName(size_t i) { |
// Base benchmark names |
switch (i) { |
case kNormalRecord: |
@@ -171,10 +176,29 @@ static SkPicture* pic_from_path(const char path[]) { |
} |
/** |
+ * 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. |
* 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 |
+ * use a RecordPictureRenderer. If we want to measure rendering, we will use a |
* TiledPictureRenderer. |
*/ |
static void do_benchmark_work(sk_tools::PictureRenderer* renderer, |
@@ -202,36 +226,50 @@ static void do_benchmark_work(sk_tools::PictureRenderer* renderer, |
* 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); |
// Render again to measure |
timer->start(); |
- bool result = renderer->render(NULL); |
+ bool result = renderer->render(NULL, out); |
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) { |
+ if (isPlayback && !result) { |
SkDebugf("Error rendering during playback.\n"); |
} |
} |
- renderer->end(); |
+ 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( |
- BenchmarkType benchmarkType, const SkISize& tileSize, |
+ const BenchmarkControl& benchControl, |
const SkString& path, SkPicture* pic, BenchTimer* timer) { |
sk_tools::TiledPictureRenderer renderer; |
SkString message("tiled_playback"); |
- message.appendf("_%dx%d", tileSize.fWidth, tileSize.fHeight); |
- do_benchmark_work(&renderer, benchmarkType, |
+ message.appendf("_%dx%d", benchControl.fTileSize.fWidth, benchControl.fTileSize.fHeight); |
+ do_benchmark_work(&renderer, benchControl.fType, |
path, pic, kNumPlaybacks, message.c_str(), timer); |
} |
@@ -239,11 +277,11 @@ static void benchmark_playback( |
* Call do_benchmark_work with a RecordPictureRenderer. |
*/ |
static void benchmark_recording( |
- BenchmarkType benchmarkType, const SkISize& tileSize, |
+ const BenchmarkControl& benchControl, |
const SkString& path, SkPicture* pic, BenchTimer* timer) { |
sk_tools::RecordPictureRenderer renderer; |
int numRecordings = 0; |
- switch(benchmarkType) { |
+ switch(benchControl.fType) { |
case kRTree_BenchmarkType: |
numRecordings = kNumRTreeRecordings; |
break; |
@@ -251,7 +289,8 @@ static void benchmark_recording( |
numRecordings = kNumNormalRecordings; |
break; |
} |
- do_benchmark_work(&renderer, benchmarkType, path, pic, numRecordings, "recording", timer); |
+ do_benchmark_work(&renderer, benchControl.fType, |
+ path, pic, numRecordings, "recording", timer); |
} |
/** |
@@ -277,8 +316,7 @@ static bool benchmark_loop( |
SkDebugf("Couldn't create picture. Ignoring path: %s\n", path.c_str()); |
continue; |
} |
- benchControl.fFunction(benchControl.fType, benchControl.fTileSize, path, pic, &timer); |
- SkAssertResult(timerData.appendTimes(&timer)); |
+ benchControl.fFunction(benchControl, path, pic, &timer); |
histogram[index - 1].fPath = path; |
histogram[index - 1].fCpuTime = SkDoubleToScalar(timer.fCpu); |
@@ -293,7 +331,7 @@ static bool benchmark_loop( |
const char findStr[] = "= "; |
int pos = timerResult.find(findStr); |
if (-1 == pos) { |
- SkDebugf("Unexpected output from TimerData::getResult(...). Unable to parse."); |
+ SkDebugf("Unexpected output from TimerData::getResult(...). Unable to parse.\n"); |
return false; |
} |
@@ -325,7 +363,7 @@ int tool_main(int argc, char** argv) { |
BenchmarkControl::Make(i), |
histograms[i]); |
if (!success) { |
- SkDebugf("benchmark_loop failed at index %d", i); |
+ SkDebugf("benchmark_loop failed at index %d\n", i); |
} |
} |
@@ -338,24 +376,30 @@ int tool_main(int argc, char** argv) { |
playbackOut.writeText("# "); |
for (size_t i = 0; i < kNumBenchmarks; ++i) { |
SkString out; |
- out.printf("%s ", BenchmarkControl::getBenchmarkName(i).c_str()); |
- if (BenchmarkControl::getBenchmarkFunc(i) == &benchmark_recording) { |
+ 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) { |
+ if (BenchmarkControl::GetBenchmarkFunc(i) == &benchmark_playback) { |
playbackOut.writeText(out.c_str()); |
} |
} |
recordOut.writeText("\n"); |
playbackOut.writeText("\n"); |
- |
+ // Write to file, and save recording averages. |
+ SkScalar avgRecord = SkIntToScalar(0); |
+ SkScalar avgRecordRTree = SkIntToScalar(0); |
for (int i = 0; i < argc - 1; ++i) { |
SkString pbLine; |
SkString recLine; |
// ==== Write record info |
recLine.printf("%d ", i); |
- recLine.appendf("%f ", histograms[0][i].fCpuTime); // Append normal_record time |
- recLine.appendf("%f", histograms[1][i].fCpuTime); // Append rtree_record time |
+ 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; |
// ==== Write playback info |
pbLine.printf("%d ", i); |
@@ -370,6 +414,10 @@ int tool_main(int argc, char** argv) { |
playbackOut.writeText(pbLine.c_str()); |
recordOut.writeText(recLine.c_str()); |
} |
+ avgRecord /= argc - 1; |
+ avgRecordRTree /= argc - 1; |
+ SkDebugf("Average base recording time: %.3fms\n", avgRecord); |
+ SkDebugf("Average recording time with rtree: %.3fms\n", avgRecordRTree); |
SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle); |
return 0; |