aboutsummaryrefslogtreecommitdiffhomepage
path: root/bench
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2015-09-22 11:56:16 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-09-22 11:56:16 -0700
commit7f69144aaabbedf51ad2a1feddc9e0689f2c5ee9 (patch)
tree9ed42dfc6bd44387571d5d5db61bbf7c23036675 /bench
parentcc334b36de5c4508266c322dfa44039d8156dc70 (diff)
Add nanobench tests for BitmapRegionDecoder
SkBitmapRegionDecoderInterface provides an interface for multiple implementations of Android's BitmapRegionDecoder. We already have correctness tests in DM that will enable us to compare the quality of our various BRD implementations. We also need these performance tests to compare the speed of our various implementations. BUG=skia:4357 Review URL: https://codereview.chromium.org/1344993003
Diffstat (limited to 'bench')
-rw-r--r--bench/BitmapRegionDecoderBench.cpp68
-rw-r--r--bench/BitmapRegionDecoderBench.h49
-rw-r--r--bench/CodecBench.cpp17
-rw-r--r--bench/CodecBenchPriv.h30
-rw-r--r--bench/DecodingBench.cpp17
-rw-r--r--bench/nanobench.cpp140
-rw-r--r--bench/subset/SubsetBenchPriv.h20
-rw-r--r--bench/subset/SubsetSingleBench.cpp3
-rw-r--r--bench/subset/SubsetTranslateBench.cpp3
-rw-r--r--bench/subset/SubsetZoomBench.cpp3
10 files changed, 293 insertions, 57 deletions
diff --git a/bench/BitmapRegionDecoderBench.cpp b/bench/BitmapRegionDecoderBench.cpp
new file mode 100644
index 0000000000..77d342331d
--- /dev/null
+++ b/bench/BitmapRegionDecoderBench.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "BitmapRegionDecoderBench.h"
+#include "CodecBenchPriv.h"
+#include "SkBitmap.h"
+#include "SkCodecTools.h"
+#include "SkOSFile.h"
+
+BitmapRegionDecoderBench::BitmapRegionDecoderBench(const char* baseName, SkData* encoded,
+ SkBitmapRegionDecoderInterface::Strategy strategy, SkColorType colorType,
+ uint32_t sampleSize, const SkIRect& subset)
+ : fBRD(nullptr)
+ , fData(SkRef(encoded))
+ , fStrategy(strategy)
+ , fColorType(colorType)
+ , fSampleSize(sampleSize)
+ , fSubset(subset)
+{
+ // Choose a useful name for the region decoding strategy
+ const char* strategyName;
+ switch (strategy) {
+ case SkBitmapRegionDecoderInterface::kOriginal_Strategy:
+ strategyName = "Original";
+ break;
+ case SkBitmapRegionDecoderInterface::kCanvas_Strategy:
+ strategyName = "Canvas";
+ break;
+ default:
+ SkASSERT(false);
+ strategyName = "";
+ break;
+ }
+
+ // Choose a useful name for the color type
+ const char* colorName = color_type_to_str(colorType);
+
+ fName.printf("BRD_%s_%s_%s", baseName, strategyName, colorName);
+ if (1 != sampleSize) {
+ fName.appendf("_%.3f", get_scale_from_sample_size(sampleSize));
+ }
+}
+
+const char* BitmapRegionDecoderBench::onGetName() {
+ return fName.c_str();
+}
+
+bool BitmapRegionDecoderBench::isSuitableFor(Backend backend) {
+ return kNonRendering_Backend == backend;
+}
+
+void BitmapRegionDecoderBench::onPreDraw() {
+ SkStreamRewindable* stream = new SkMemoryStream(fData);
+ fBRD.reset(SkBitmapRegionDecoderInterface::CreateBitmapRegionDecoder(stream, fStrategy));
+}
+
+void BitmapRegionDecoderBench::onDraw(const int n, SkCanvas* canvas) {
+ SkAutoTDelete<SkBitmap> bitmap;
+ for (int i = 0; i < n; i++) {
+ bitmap.reset(fBRD->decodeRegion(fSubset.left(), fSubset.top(), fSubset.width(),
+ fSubset.height(), fSampleSize, fColorType));
+ SkASSERT(nullptr != bitmap.get());
+ }
+}
diff --git a/bench/BitmapRegionDecoderBench.h b/bench/BitmapRegionDecoderBench.h
new file mode 100644
index 0000000000..7be770f472
--- /dev/null
+++ b/bench/BitmapRegionDecoderBench.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef BitmapRegionDecoderBench_DEFINED
+#define BitmapRegionDecoderBench_DEFINED
+
+#include "Benchmark.h"
+#include "SkBitmapRegionDecoderInterface.h"
+#include "SkData.h"
+#include "SkImageInfo.h"
+#include "SkRefCnt.h"
+#include "SkString.h"
+
+/**
+ * Benchmark Android's BitmapRegionDecoder for a particular colorType, sampleSize, and subset.
+ *
+ * fStrategy determines which of various implementations is to be used.
+ *
+ * nanobench.cpp handles creating benchmarks for interesting scaled subsets. We strive to test
+ * on real use cases.
+ */
+class BitmapRegionDecoderBench : public Benchmark {
+public:
+ // Calls encoded->ref()
+ BitmapRegionDecoderBench(const char* basename, SkData* encoded,
+ SkBitmapRegionDecoderInterface::Strategy strategy, SkColorType colorType,
+ uint32_t sampleSize, const SkIRect& subset);
+
+protected:
+ const char* onGetName() override;
+ bool isSuitableFor(Backend backend) override;
+ void onDraw(const int n, SkCanvas* canvas) override;
+ void onPreDraw() override;
+
+private:
+ SkString fName;
+ SkAutoTDelete<SkBitmapRegionDecoderInterface> fBRD;
+ SkAutoTUnref<SkData> fData;
+ const SkBitmapRegionDecoderInterface::Strategy fStrategy;
+ const SkColorType fColorType;
+ const uint32_t fSampleSize;
+ const SkIRect fSubset;
+ typedef Benchmark INHERITED;
+};
+#endif // BitmapRegionDecoderBench_DEFINED
diff --git a/bench/CodecBench.cpp b/bench/CodecBench.cpp
index 1e6b5207bf..a21aae1f0b 100644
--- a/bench/CodecBench.cpp
+++ b/bench/CodecBench.cpp
@@ -6,6 +6,7 @@
*/
#include "CodecBench.h"
+#include "CodecBenchPriv.h"
#include "SkBitmap.h"
#include "SkCodec.h"
#include "SkOSFile.h"
@@ -15,21 +16,7 @@ CodecBench::CodecBench(SkString baseName, SkData* encoded, SkColorType colorType
, fData(SkRef(encoded))
{
// Parse filename and the color type to give the benchmark a useful name
- const char* colorName;
- switch(colorType) {
- case kN32_SkColorType:
- colorName = "N32";
- break;
- case kRGB_565_SkColorType:
- colorName = "565";
- break;
- case kAlpha_8_SkColorType:
- colorName = "Alpha8";
- break;
- default:
- colorName = "Unknown";
- }
- fName.printf("Codec_%s_%s", baseName.c_str(), colorName);
+ fName.printf("Codec_%s_%s", baseName.c_str(), color_type_to_str(colorType));
#ifdef SK_DEBUG
// Ensure that we can create an SkCodec from this data.
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fData));
diff --git a/bench/CodecBenchPriv.h b/bench/CodecBenchPriv.h
new file mode 100644
index 0000000000..d8585b6006
--- /dev/null
+++ b/bench/CodecBenchPriv.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef CodecBenchPriv_DEFINED
+#define CodecBenchPriv_DEFINED
+
+#include "SkImageInfo.h"
+
+inline const char* color_type_to_str(SkColorType colorType) {
+ switch (colorType) {
+ case kN32_SkColorType:
+ return "N32";
+ case kRGB_565_SkColorType:
+ return "565";
+ case kGray_8_SkColorType:
+ return "Gray8";
+ case kIndex_8_SkColorType:
+ return "Index8";
+ case kAlpha_8_SkColorType:
+ return "Alpha8";
+ default:
+ return "Unknown";
+ }
+}
+
+#endif // CodecBenchPriv_DEFINED
diff --git a/bench/DecodingBench.cpp b/bench/DecodingBench.cpp
index 421cabe34a..7b6ad2bb0a 100644
--- a/bench/DecodingBench.cpp
+++ b/bench/DecodingBench.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "CodecBenchPriv.h"
#include "DecodingBench.h"
#include "SkBitmap.h"
#include "SkData.h"
@@ -25,21 +26,7 @@ DecodingBench::DecodingBench(SkString path, SkColorType colorType)
{
// Parse filename and the color type to give the benchmark a useful name
SkString baseName = SkOSPath::Basename(path.c_str());
- const char* colorName;
- switch(colorType) {
- case kN32_SkColorType:
- colorName = "N32";
- break;
- case kRGB_565_SkColorType:
- colorName = "565";
- break;
- case kAlpha_8_SkColorType:
- colorName = "Alpha8";
- break;
- default:
- colorName = "Unknown";
- }
- fName.printf("Decode_%s_%s", baseName.c_str(), colorName);
+ fName.printf("Decode_%s_%s", baseName.c_str(), color_type_to_str(colorType));
#ifdef SK_DEBUG
// Ensure that we can create a decoder.
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index e7019dcb8c..a1db0acd80 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -10,7 +10,9 @@
#include "nanobench.h"
#include "Benchmark.h"
+#include "BitmapRegionDecoderBench.h"
#include "CodecBench.h"
+#include "CodecBenchPriv.h"
#include "CrashHandler.h"
#include "DecodingBench.h"
#include "GMBench.h"
@@ -19,13 +21,13 @@
#include "RecordingBench.h"
#include "SKPAnimationBench.h"
#include "SKPBench.h"
-#include "SubsetBenchPriv.h"
#include "SubsetSingleBench.h"
#include "SubsetTranslateBench.h"
#include "SubsetZoomBench.h"
#include "Stats.h"
#include "Timer.h"
+#include "SkBitmapRegionDecoderInterface.h"
#include "SkBBoxHierarchy.h"
#include "SkCanvas.h"
#include "SkCodec.h"
@@ -525,7 +527,7 @@ static bool valid_subset_bench(const SkString& path, SkColorType colorType, bool
colors, &colorCount) != SkCodec::kSuccess)
{
SkDebugf("Could not create scanline decoder for %s with color type %s. "
- "Skipping bench.\n", path.c_str(), get_color_name(colorType));
+ "Skipping bench.\n", path.c_str(), color_type_to_str(colorType));
return false;
}
*width = info.width();
@@ -539,7 +541,7 @@ static bool valid_subset_bench(const SkString& path, SkColorType colorType, bool
//FIXME: See skbug.com/3921
if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) {
SkDebugf("Cannot use image subset decoder for %s with color type %s. "
- "Skipping bench.\n", path.c_str(), get_color_name(colorType));
+ "Skipping bench.\n", path.c_str(), color_type_to_str(colorType));
return false;
}
if (!decoder->buildTileIndex(stream.detach(), width, height)) {
@@ -557,6 +559,38 @@ static bool valid_subset_bench(const SkString& path, SkColorType colorType, bool
return true;
}
+static bool valid_brd_bench(SkData* encoded, SkBitmapRegionDecoderInterface::Strategy strategy,
+ SkColorType colorType, uint32_t sampleSize, uint32_t minOutputSize, int* width,
+ int* height) {
+ SkStreamRewindable* stream = new SkMemoryStream(encoded);
+ SkAutoTDelete<SkBitmapRegionDecoderInterface> brd(
+ SkBitmapRegionDecoderInterface::CreateBitmapRegionDecoder(stream, strategy));
+ if (nullptr == brd.get()) {
+ // This is indicates that subset decoding is not supported for a particular image format.
+ return false;
+ }
+
+ SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(0, 0, brd->width(), brd->height(), 1,
+ colorType));
+ if (nullptr == bitmap.get() || colorType != bitmap->colorType()) {
+ // This indicates that conversion to the requested color type is not supported for the
+ // particular image.
+ return false;
+ }
+
+ if (sampleSize * minOutputSize > (uint32_t) brd->width() || sampleSize * minOutputSize >
+ (uint32_t) brd->height()) {
+ // This indicates that the image is not large enough to decode a
+ // minOutputSize x minOutputSize subset at the given sampleSize.
+ return false;
+ }
+
+ // Set the image width and height. The calling code will use this to choose subsets to decode.
+ *width = brd->width();
+ *height = brd->height();
+ return true;
+}
+
static void cleanup_run(Target* target) {
delete target;
#if SK_SUPPORT_GPU
@@ -580,9 +614,12 @@ public:
, fCurrentCodec(0)
, fCurrentImage(0)
, fCurrentSubsetImage(0)
+ , fCurrentBRDImage(0)
, fCurrentColorType(0)
, fCurrentSubsetType(0)
, fUseCodec(0)
+ , fCurrentBRDStrategy(0)
+ , fCurrentBRDSampleSize(0)
, fCurrentAnimSKP(0) {
for (int i = 0; i < FLAGS_skps.count(); i++) {
if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
@@ -876,6 +913,97 @@ public:
fUseCodec++;
}
+ // Run the BRDBenches
+ // We will benchmark multiple BRD strategies.
+ const SkBitmapRegionDecoderInterface::Strategy strategies[] = {
+ SkBitmapRegionDecoderInterface::kOriginal_Strategy,
+ SkBitmapRegionDecoderInterface::kCanvas_Strategy,
+ };
+
+ // We intend to create benchmarks that model the use cases in
+ // android/libraries/social/tiledimage. In this library, an image is decoded in 512x512
+ // tiles. The image can be translated freely, so the location of a tile may be anywhere in
+ // the image. For that reason, we will benchmark decodes in five representative locations
+ // in the image. Additionally, this use case utilizes power of two scaling, so we will
+ // test on power of two sample sizes. The output tile is always 512x512, so, when a
+ // sampleSize is used, the size of the subset that is decoded is always
+ // (sampleSize*512)x(sampleSize*512).
+ // There are a few good reasons to only test on power of two sample sizes at this time:
+ // JPEG decodes using kOriginal_Strategy are broken for non-powers of two.
+ // skbug.com/4319
+ // All use cases we are aware of only scale by powers of two.
+ // PNG decodes use the indicated sampling strategy regardless of the sample size, so
+ // these tests are sufficient to provide good coverage of our scaling options.
+ const uint32_t sampleSizes[] = { 1, 2, 4, 8, 16 };
+ const uint32_t minOutputSize = 512;
+ while (fCurrentBRDImage < fImages.count()) {
+ while (fCurrentBRDStrategy < (int) SK_ARRAY_COUNT(strategies)) {
+ while (fCurrentColorType < fColorTypes.count()) {
+ while (fCurrentBRDSampleSize < (int) SK_ARRAY_COUNT(sampleSizes)) {
+ while (fCurrentSubsetType <= kLastSingle_SubsetType) {
+ const SkString& path = fImages[fCurrentBRDImage];
+ const SkBitmapRegionDecoderInterface::Strategy strategy =
+ strategies[fCurrentBRDStrategy];
+ SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
+ const SkColorType colorType = fColorTypes[fCurrentColorType];
+ uint32_t sampleSize = sampleSizes[fCurrentBRDSampleSize];
+ int currentSubsetType = fCurrentSubsetType++;
+
+ int width = 0;
+ int height = 0;
+ if (!valid_brd_bench(encoded.get(), strategy, colorType, sampleSize,
+ minOutputSize, &width, &height)) {
+ break;
+ }
+
+ SkString basename = SkOSPath::Basename(path.c_str());
+ SkIRect subset;
+ const uint32_t subsetSize = sampleSize * minOutputSize;
+ switch (currentSubsetType) {
+ case kTopLeft_SubsetType:
+ basename.append("_TopLeft");
+ subset = SkIRect::MakeXYWH(0, 0, subsetSize, subsetSize);
+ break;
+ case kTopRight_SubsetType:
+ basename.append("_TopRight");
+ subset = SkIRect::MakeXYWH(width - subsetSize, 0, subsetSize,
+ subsetSize);
+ break;
+ case kMiddle_SubsetType:
+ basename.append("_Middle");
+ subset = SkIRect::MakeXYWH((width - subsetSize) / 2,
+ (height - subsetSize) / 2, subsetSize, subsetSize);
+ break;
+ case kBottomLeft_SubsetType:
+ basename.append("_BottomLeft");
+ subset = SkIRect::MakeXYWH(0, height - subsetSize, subsetSize,
+ subsetSize);
+ break;
+ case kBottomRight_SubsetType:
+ basename.append("_BottomRight");
+ subset = SkIRect::MakeXYWH(width - subsetSize,
+ height - subsetSize, subsetSize, subsetSize);
+ break;
+ default:
+ SkASSERT(false);
+ }
+
+ return new BitmapRegionDecoderBench(basename.c_str(), encoded.get(),
+ strategy, colorType, sampleSize, subset);
+ }
+ fCurrentSubsetType = 0;
+ fCurrentBRDSampleSize++;
+ }
+ fCurrentBRDSampleSize = 0;
+ fCurrentColorType++;
+ }
+ fCurrentColorType = 0;
+ fCurrentBRDStrategy++;
+ }
+ fCurrentBRDStrategy = 0;
+ fCurrentBRDImage++;
+ }
+
return nullptr;
}
@@ -907,7 +1035,8 @@ private:
kBottomRight_SubsetType = 4,
kTranslate_SubsetType = 5,
kZoom_SubsetType = 6,
- kLast_SubsetType = kZoom_SubsetType
+ kLast_SubsetType = kZoom_SubsetType,
+ kLastSingle_SubsetType = kBottomRight_SubsetType,
};
const BenchRegistry* fBenches;
@@ -932,9 +1061,12 @@ private:
int fCurrentCodec;
int fCurrentImage;
int fCurrentSubsetImage;
+ int fCurrentBRDImage;
int fCurrentColorType;
int fCurrentSubsetType;
int fUseCodec;
+ int fCurrentBRDStrategy;
+ int fCurrentBRDSampleSize;
int fCurrentAnimSKP;
};
diff --git a/bench/subset/SubsetBenchPriv.h b/bench/subset/SubsetBenchPriv.h
index 02f7040a22..7e1dfb9530 100644
--- a/bench/subset/SubsetBenchPriv.h
+++ b/bench/subset/SubsetBenchPriv.h
@@ -13,26 +13,6 @@
#include "SkImageGenerator.h"
/*
- * Convert the color type to a string
- */
-static const char* get_color_name(SkColorType colorType) {
- switch(colorType) {
- case kN32_SkColorType:
- return "N32";
- case kRGB_565_SkColorType:
- return "565";
- case kGray_8_SkColorType:
- return "Gray8";
- case kIndex_8_SkColorType:
- return "Index8";
- case kAlpha_8_SkColorType:
- return "Alpha8";
- default:
- return "Unknown";
- }
-}
-
-/*
* If we plan to decode to kIndex8, we must create a color table and pass it to the
* bitmap when we allocate pixels. Otherwise, we simply allocate pixels using the
* decode info.
diff --git a/bench/subset/SubsetSingleBench.cpp b/bench/subset/SubsetSingleBench.cpp
index ce00f20947..2e5703f508 100644
--- a/bench/subset/SubsetSingleBench.cpp
+++ b/bench/subset/SubsetSingleBench.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "CodecBenchPriv.h"
#include "SubsetSingleBench.h"
#include "SubsetBenchPriv.h"
#include "SkData.h"
@@ -39,7 +40,7 @@ SubsetSingleBench::SubsetSingleBench(const SkString& path,
SkString baseName = SkOSPath::Basename(path.c_str());
// Choose an informative color name
- const char* colorName = get_color_name(fColorType);
+ const char* colorName = color_type_to_str(fColorType);
fName.printf("%sSubsetSingle_%dx%d +%d_+%d_%s_%s", fUseCodec ? "Codec" : "Image", fSubsetWidth,
fSubsetHeight, fOffsetLeft, fOffsetTop, baseName.c_str(), colorName);
diff --git a/bench/subset/SubsetTranslateBench.cpp b/bench/subset/SubsetTranslateBench.cpp
index 8f6f2ea21b..bed3580853 100644
--- a/bench/subset/SubsetTranslateBench.cpp
+++ b/bench/subset/SubsetTranslateBench.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "CodecBenchPriv.h"
#include "SubsetTranslateBench.h"
#include "SubsetBenchPriv.h"
#include "SkData.h"
@@ -35,7 +36,7 @@ SubsetTranslateBench::SubsetTranslateBench(const SkString& path,
SkString baseName = SkOSPath::Basename(path.c_str());
// Choose an informative color name
- const char* colorName = get_color_name(fColorType);
+ const char* colorName = color_type_to_str(fColorType);
fName.printf("%sSubsetTranslate_%dx%d_%s_%s", fUseCodec ? "Codec" : "Image", fSubsetWidth,
fSubsetHeight, baseName.c_str(), colorName);
diff --git a/bench/subset/SubsetZoomBench.cpp b/bench/subset/SubsetZoomBench.cpp
index bbdca75a54..655285fdf8 100644
--- a/bench/subset/SubsetZoomBench.cpp
+++ b/bench/subset/SubsetZoomBench.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "CodecBenchPriv.h"
#include "SubsetZoomBench.h"
#include "SubsetBenchPriv.h"
#include "SkData.h"
@@ -35,7 +36,7 @@ SubsetZoomBench::SubsetZoomBench(const SkString& path,
SkString baseName = SkOSPath::Basename(path.c_str());
// Choose an informative color name
- const char* colorName = get_color_name(fColorType);
+ const char* colorName = color_type_to_str(fColorType);
fName.printf("%sSubsetZoom_%dx%d_%s_%s", fUseCodec ? "Codec" : "Image", fSubsetWidth,
fSubsetHeight, baseName.c_str(), colorName);