diff options
author | msarett <msarett@google.com> | 2015-02-13 09:05:41 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-13 09:05:42 -0800 |
commit | 95f192d19938b98a45dd1fa4112d965f60d10516 (patch) | |
tree | a0c6f343f0d97f7022c117139d1d1ac9597ab4ec | |
parent | a8fcea0cd09080de45143f2726059398cd8b8049 (diff) |
Adding new benchmark to test image decoding performance.
BUG=skia:
Review URL: https://codereview.chromium.org/918673002
-rw-r--r-- | bench/DecodeBench.cpp | 50 | ||||
-rw-r--r-- | bench/DecodingBench.cpp | 62 | ||||
-rw-r--r-- | bench/DecodingBench.h | 35 | ||||
-rw-r--r-- | bench/DecodingSubsetBench.cpp | 73 | ||||
-rw-r--r-- | bench/DecodingSubsetBench.h | 37 | ||||
-rw-r--r-- | bench/ImageDecodeBench.cpp | 93 | ||||
-rw-r--r-- | bench/nanobench.cpp | 105 | ||||
-rw-r--r-- | dm/DM.cpp | 1 | ||||
-rw-r--r-- | gyp/bench.gyp | 2 | ||||
-rw-r--r-- | gyp/bench.gypi | 2 | ||||
-rw-r--r-- | gyp/iOSShell.gyp | 2 | ||||
-rw-r--r-- | tools/flags/SkCommonFlags.cpp | 2 | ||||
-rw-r--r-- | tools/flags/SkCommonFlags.h | 1 |
13 files changed, 318 insertions, 147 deletions
diff --git a/bench/DecodeBench.cpp b/bench/DecodeBench.cpp deleted file mode 100644 index 507a7d8e92..0000000000 --- a/bench/DecodeBench.cpp +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "Benchmark.h" -#include "SkBitmap.h" -#include "SkCommandLineFlags.h" -#include "SkImageDecoder.h" -#include "SkOSFile.h" -#include "SkString.h" -#include "sk_tool_utils.h" - -DEFINE_string(decodeBenchFilename, "resources/CMYK.jpeg", "Path to image for DecodeBench."); - -class DecodeBench : public Benchmark { - const SkColorType fPrefColorType; - SkString fName; -public: - DecodeBench(SkColorType ct) : fPrefColorType(ct) { - SkString fname = SkOSPath::Basename(FLAGS_decodeBenchFilename[0]); - fName.printf("decode_%s_%s", sk_tool_utils::colortype_name(ct), fname.c_str()); - } - - bool isSuitableFor(Backend backend) SK_OVERRIDE { - return backend == kNonRendering_Backend; - } - -protected: - virtual const char* onGetName() { - return fName.c_str(); - } - - virtual void onDraw(const int loops, SkCanvas*) { - for (int i = 0; i < loops; i++) { - SkBitmap bm; - SkImageDecoder::DecodeFile(FLAGS_decodeBenchFilename[0], &bm, fPrefColorType, - SkImageDecoder::kDecodePixels_Mode); - } - } - -private: - typedef Benchmark INHERITED; -}; - -DEF_BENCH( return new DecodeBench(kN32_SkColorType); ) -DEF_BENCH( return new DecodeBench(kRGB_565_SkColorType); ) -DEF_BENCH( return new DecodeBench(kARGB_4444_SkColorType); ) diff --git a/bench/DecodingBench.cpp b/bench/DecodingBench.cpp new file mode 100644 index 0000000000..c8490ca7a8 --- /dev/null +++ b/bench/DecodingBench.cpp @@ -0,0 +1,62 @@ +/* + * 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 "DecodingBench.h" +#include "SkData.h" +#include "SkImageDecoder.h" +#include "SkOSFile.h" +#include "SkStream.h" + +/* + * + * This benchmark is designed to test the performance of image decoding. + * It is invoked from the nanobench.cpp file. + * + */ +DecodingBench::DecodingBench(SkString path, SkColorType colorType) + : fColorType(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); + + // Perform setup for the decode + SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str())); + fStream.reset(new SkMemoryStream(encoded)); + fDecoder.reset(SkImageDecoder::Factory(fStream.get())); +} + +const char* DecodingBench::onGetName() { + return fName.c_str(); +} + +bool DecodingBench::isSuitableFor(Backend backend) { + return kNonRendering_Backend == backend; +} + +void DecodingBench::onDraw(const int n, SkCanvas* canvas) { + SkBitmap bitmap; + for (int i = 0; i < n; i++) { + fStream->rewind(); + fDecoder->decode(fStream, &bitmap, fColorType, + SkImageDecoder::kDecodePixels_Mode); + } +} diff --git a/bench/DecodingBench.h b/bench/DecodingBench.h new file mode 100644 index 0000000000..b41941b84f --- /dev/null +++ b/bench/DecodingBench.h @@ -0,0 +1,35 @@ +/* + * 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 "Benchmark.h" +#include "SkImageDecoder.h" +#include "SkImageInfo.h" +#include "SkStream.h" +#include "SkString.h" + +/* + * + * This benchmark is designed to test the performance of image decoding. + * It is invoked from the nanobench.cpp file. + * + */ +class DecodingBench : public Benchmark { +public: + DecodingBench(SkString path, SkColorType colorType); + +protected: + const char* onGetName() SK_OVERRIDE; + bool isSuitableFor(Backend backend) SK_OVERRIDE; + void onDraw(const int n, SkCanvas* canvas) SK_OVERRIDE; + +private: + SkString fName; + SkColorType fColorType; + SkAutoTDelete<SkMemoryStream> fStream; + SkAutoTDelete<SkImageDecoder> fDecoder; + typedef Benchmark INHERITED; +}; diff --git a/bench/DecodingSubsetBench.cpp b/bench/DecodingSubsetBench.cpp new file mode 100644 index 0000000000..dc3c9f39cc --- /dev/null +++ b/bench/DecodingSubsetBench.cpp @@ -0,0 +1,73 @@ +/* + * 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 "DecodingSubsetBench.h" +#include "SkData.h" +#include "SkImageDecoder.h" +#include "SkOSFile.h" +#include "SkStream.h" + +/* + * + * This benchmark is designed to test the performance of image subset decoding. + * It is invoked from the nanobench.cpp file. + * + */ +DecodingSubsetBench::DecodingSubsetBench(SkString path, SkColorType colorType, + const int divisor) + : fColorType(colorType) + , fDivisor(divisor) +{ + // 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("DecodeSubset_%dx%d_%s_%s", fDivisor, fDivisor, + baseName.c_str(), colorName); + + // Perform the decode setup + SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str())); + fStream.reset(new SkMemoryStream(encoded)); + fDecoder.reset(SkImageDecoder::Factory(fStream)); +} + +const char* DecodingSubsetBench::onGetName() { + return fName.c_str(); +} + +bool DecodingSubsetBench::isSuitableFor(Backend backend) { + return kNonRendering_Backend == backend; +} + +void DecodingSubsetBench::onDraw(const int n, SkCanvas* canvas) { + for (int i = 0; i < n; i++) { + int w, h; + fDecoder->buildTileIndex(fStream->duplicate(), &w, &h); + // Divide the image into subsets and decode each subset + const int sW = w / fDivisor; + const int sH = h / fDivisor; + for (int y = 0; y < h; y += sH) { + for (int x = 0; x < w; x += sW) { + SkBitmap bitmap; + SkIRect rect = SkIRect::MakeXYWH(x, y, sW, sH); + fDecoder->decodeSubset(&bitmap, rect, fColorType); + } + } + } +} diff --git a/bench/DecodingSubsetBench.h b/bench/DecodingSubsetBench.h new file mode 100644 index 0000000000..8034c8fb74 --- /dev/null +++ b/bench/DecodingSubsetBench.h @@ -0,0 +1,37 @@ +/* + * 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 "Benchmark.h" +#include "SkImageDecoder.h" +#include "SkImageInfo.h" +#include "SkStream.h" +#include "SkString.h" + +/* + * + * This benchmark is designed to test the performance of image subset decoding. + * It is invoked from the nanobench.cpp file. + * + */ +class DecodingSubsetBench : public Benchmark { +public: + DecodingSubsetBench(SkString path, SkColorType colorType, + const int divisor); + +protected: + const char* onGetName() SK_OVERRIDE; + bool isSuitableFor(Backend backend) SK_OVERRIDE; + void onDraw(const int n, SkCanvas* canvas) SK_OVERRIDE; + +private: + SkString fName; + SkColorType fColorType; + const int fDivisor; + SkAutoTDelete<SkMemoryStream> fStream; + SkAutoTDelete<SkImageDecoder> fDecoder; + typedef Benchmark INHERITED; +}; diff --git a/bench/ImageDecodeBench.cpp b/bench/ImageDecodeBench.cpp deleted file mode 100644 index 55dffe9b2e..0000000000 --- a/bench/ImageDecodeBench.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 "Benchmark.h" -#include "SkBitmap.h" -#include "SkData.h" -#include "SkForceLinking.h" -#include "SkImageDecoder.h" -#include "SkOSFile.h" -#include "SkStream.h" -#include "SkString.h" - -__SK_FORCE_IMAGE_DECODER_LINKING; - -class SkCanvas; - -class ImageDecodeBench : public Benchmark { -public: - ImageDecodeBench(void* p, const char* filename) - : fName("image_decode_") - , fFilename(filename) - , fStream() - , fValid(false) { - fName.append(SkOSPath::Basename(filename)); - } - - bool isSuitableFor(Backend backend) SK_OVERRIDE { - return backend == kNonRendering_Backend; - } - -protected: - const char* onGetName() SK_OVERRIDE { - return fName.c_str(); - } - - void onPreDraw() SK_OVERRIDE { - SkFILEStream fileStream(fFilename.c_str()); - fValid = fileStream.isValid() && fileStream.getLength() > 0; - if (fValid) { - const size_t size = fileStream.getLength(); - void* data = sk_malloc_throw(size); - if (fileStream.read(data, size) < size) { - fValid = false; - } else { - SkAutoTUnref<SkData> skdata(SkData::NewFromMalloc(data, size)); - fStream.setData(skdata.get()); - } - } - } - - void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { -#ifdef SK_DEBUG - if (!fValid) { - SkDebugf("stream was invalid: %s\n", fName.c_str()); - return; - } -#endif - // Decode a bunch of times - SkBitmap bm; - for (int i = 0; i < loops; ++i) { - SkDEBUGCODE(bool success =) SkImageDecoder::DecodeStream(&fStream, &bm); -#ifdef SK_DEBUG - if (!success) { - SkDebugf("failed to decode %s\n", fName.c_str()); - return; - } -#endif - SkDEBUGCODE(success =) fStream.rewind(); -#ifdef SK_DEBUG - if (!success) { - SkDebugf("failed to rewind %s\n", fName.c_str()); - return; - } -#endif - } - } - -private: - SkString fName; - const SkString fFilename; - SkMemoryStream fStream; - bool fValid; - - typedef Benchmark INHERITED; -}; - -// These are files which call decodePalette -//DEF_BENCH( return SkNEW_ARGS(ImageDecodeBench, ("/usr/local/google/home/scroggo/Downloads/images/hal_163x90.png")); ) -//DEF_BENCH( return SkNEW_ARGS(ImageDecodeBench, ("/usr/local/google/home/scroggo/Downloads/images/box_19_top-left.png")); ) diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp index eb48ec228d..d66b308b71 100644 --- a/bench/nanobench.cpp +++ b/bench/nanobench.cpp @@ -9,6 +9,8 @@ #include "Benchmark.h" #include "CrashHandler.h" +#include "DecodingBench.h" +#include "DecodingSubsetBench.h" #include "GMBench.h" #include "ProcStats.h" #include "ResultsWriter.h" @@ -20,6 +22,7 @@ #include "SkBBoxHierarchy.h" #include "SkCanvas.h" #include "SkCommonFlags.h" +#include "SkData.h" #include "SkForceLinking.h" #include "SkGraphics.h" #include "SkOSFile.h" @@ -439,7 +442,11 @@ public: , fCurrentRecording(0) , fCurrentScale(0) , fCurrentSKP(0) - , fCurrentUseMPD(0) { + , fCurrentUseMPD(0) + , fCurrentImage(0) + , fCurrentSubsetImage(0) + , fCurrentColorType(0) + , fDivisor(2) { for (int i = 0; i < FLAGS_skps.count(); i++) { if (SkStrEndsWith(FLAGS_skps[i], ".skp")) { fSKPs.push_back() = FLAGS_skps[i]; @@ -469,6 +476,27 @@ public: if (FLAGS_mpd) { fUseMPDs.push_back() = true; } + + // Prepare the images for decoding + for (int i = 0; i < FLAGS_images.count(); i++) { + const char* flag = FLAGS_images[i]; + if (sk_isdir(flag)) { + // If the value passed in is a directory, add all the images + SkOSFile::Iter it(flag); + SkString file; + while (it.next(&file)) { + fImages.push_back() = SkOSPath::Join(flag, file.c_str()); + } + } else if (sk_exists(flag)) { + // Also add the value if it is a single image + fImages.push_back() = flag; + } + } + + // Choose the candidate color types for image decoding + const SkColorType colorTypes[] = + { kN32_SkColorType, kRGB_565_SkColorType, kAlpha_8_SkColorType }; + fColorTypes.push_back_n(SK_ARRAY_COUNT(colorTypes), colorTypes); } static bool ReadPicture(const char* path, SkAutoTUnref<SkPicture>* pic) { @@ -562,6 +590,75 @@ public: fCurrentScale++; } + // Run the DecodingBenches + while (fCurrentImage < fImages.count()) { + while (fCurrentColorType < fColorTypes.count()) { + const SkString& path = fImages[fCurrentImage]; + SkColorType colorType = fColorTypes[fCurrentColorType]; + fCurrentColorType++; + // Check if the image decodes before creating the benchmark + SkBitmap bitmap; + if (SkImageDecoder::DecodeFile(path.c_str(), &bitmap, + colorType, SkImageDecoder::kDecodePixels_Mode)) { + return new DecodingBench(path, colorType); + } + } + fCurrentColorType = 0; + fCurrentImage++; + } + + // Run the DecodingSubsetBenches + while (fCurrentSubsetImage < fImages.count()) { + while (fCurrentColorType < fColorTypes.count()) { + const SkString& path = fImages[fCurrentSubsetImage]; + SkColorType colorType = fColorTypes[fCurrentColorType]; + fCurrentColorType++; + // Check if the image decodes before creating the benchmark + SkAutoTUnref<SkData> encoded( + SkData::NewFromFileName(path.c_str())); + SkAutoTDelete<SkMemoryStream> stream( + new SkMemoryStream(encoded)); + SkAutoTDelete<SkImageDecoder> + decoder(SkImageDecoder::Factory(stream.get())); + if (!decoder) { + SkDebugf("Cannot find decoder for %s\n", path.c_str()); + } else { + stream->rewind(); + int w, h; + bool success; + if (!decoder->buildTileIndex(stream.detach(), &w, &h) + || w*h == 1) { + // This is not an error, but in this case we still + // do not want to run the benchmark. + success = false; + } else if (fDivisor > w || fDivisor > h) { + SkDebugf("Divisor %d is too big for %s %dx%d\n", + fDivisor, path.c_str(), w, h); + success = false; + } else { + const int sW = w / fDivisor; + const int sH = h / fDivisor; + SkBitmap bitmap; + success = true; + for (int y = 0; y < h; y += sH) { + for (int x = 0; x < w; x += sW) { + SkIRect rect = SkIRect::MakeXYWH(x, y, sW, sH); + success &= decoder->decodeSubset(&bitmap, rect, + colorType); + } + } + } + // Create the benchmark if successful + if (success) { + return new DecodingSubsetBench(path, colorType, + fDivisor); + } + } + } + fCurrentColorType = 0; + fCurrentSubsetImage++; + } + return NULL; } @@ -591,6 +688,8 @@ private: SkTArray<SkScalar> fScales; SkTArray<SkString> fSKPs; SkTArray<bool> fUseMPDs; + SkTArray<SkString> fImages; + SkTArray<SkColorType> fColorTypes; double fSKPBytes, fSKPOps; @@ -600,6 +699,10 @@ private: int fCurrentScale; int fCurrentSKP; int fCurrentUseMPD; + int fCurrentImage; + int fCurrentSubsetImage; + int fCurrentColorType; + const int fDivisor; }; int nanobench_main(); @@ -16,7 +16,6 @@ #include "Test.h" #include "Timer.h" -DEFINE_string(images, "resources", "Images to decode."); DEFINE_string(src, "tests gm skp image subset", "Source types to test."); DEFINE_bool(nameByHash, false, "If true, write to FLAGS_writePath[0]/<hash>.png instead of " diff --git a/gyp/bench.gyp b/gyp/bench.gyp index 26849d511a..480f876321 100644 --- a/gyp/bench.gyp +++ b/gyp/bench.gyp @@ -10,6 +10,8 @@ 'type': 'executable', 'sources': [ '../gm/gm.cpp', + '../bench/DecodingBench.cpp', + '../bench/DecodingSubsetBench.cpp', '../bench/GMBench.cpp', '../bench/RecordingBench.cpp', '../bench/SKPBench.cpp', diff --git a/gyp/bench.gypi b/gyp/bench.gypi index e2aacd0d94..87c6622caa 100644 --- a/gyp/bench.gypi +++ b/gyp/bench.gypi @@ -43,7 +43,6 @@ '../bench/ColorPrivBench.cpp', '../bench/CoverageBench.cpp', '../bench/DashBench.cpp', - '../bench/DecodeBench.cpp', '../bench/DeferredSurfaceCopyBench.cpp', '../bench/DisplacementBench.cpp', '../bench/ETCBitmapBench.cpp', @@ -58,7 +57,6 @@ '../bench/GradientBench.cpp', '../bench/HairlinePathBench.cpp', '../bench/ImageCacheBench.cpp', - '../bench/ImageDecodeBench.cpp', '../bench/ImageFilterDAGBench.cpp', '../bench/ImageFilterCollapse.cpp', '../bench/InterpBench.cpp', diff --git a/gyp/iOSShell.gyp b/gyp/iOSShell.gyp index ac2ed30303..77ff8d1594 100644 --- a/gyp/iOSShell.gyp +++ b/gyp/iOSShell.gyp @@ -18,6 +18,8 @@ 'xml.gyp:xml', ], 'sources': [ + '../bench/DecodingBench.cpp', + '../bench/DecodingSubsetBench.cpp', '../bench/GMBench.cpp', '../bench/RecordingBench.cpp', '../bench/SKPBench.cpp', diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp index 2a0490cbb7..15d9123e1e 100644 --- a/tools/flags/SkCommonFlags.cpp +++ b/tools/flags/SkCommonFlags.cpp @@ -23,6 +23,8 @@ DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" " "Defaults to empty string, which selects the API native to the " "system."); +DEFINE_string(images, "resources", "Directory of images to decode."); + DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects."); DEFINE_string2(match, m, NULL, diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h index 661501a4a9..69b835800c 100644 --- a/tools/flags/SkCommonFlags.h +++ b/tools/flags/SkCommonFlags.h @@ -15,6 +15,7 @@ DECLARE_bool(cpu); DECLARE_bool(dryRun); DECLARE_bool(gpu); DECLARE_string(gpuAPI); +DECLARE_string(images); DECLARE_bool(leaks); DECLARE_string(match); DECLARE_bool(quiet); |