Adding new benchmark to test image decoding performance.
authormsarett <msarett@google.com>
Fri, 13 Feb 2015 17:05:41 +0000 (09:05 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 13 Feb 2015 17:05:42 +0000 (09:05 -0800)
BUG=skia:

Review URL: https://codereview.chromium.org/918673002

13 files changed:
bench/DecodeBench.cpp [deleted file]
bench/DecodingBench.cpp [new file with mode: 0644]
bench/DecodingBench.h [new file with mode: 0644]
bench/DecodingSubsetBench.cpp [new file with mode: 0644]
bench/DecodingSubsetBench.h [new file with mode: 0644]
bench/ImageDecodeBench.cpp [deleted file]
bench/nanobench.cpp
dm/DM.cpp
gyp/bench.gyp
gyp/bench.gypi
gyp/iOSShell.gyp
tools/flags/SkCommonFlags.cpp
tools/flags/SkCommonFlags.h

diff --git a/bench/DecodeBench.cpp b/bench/DecodeBench.cpp
deleted file mode 100644 (file)
index 507a7d8..0000000
+++ /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 (file)
index 0000000..c8490ca
--- /dev/null
@@ -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 (file)
index 0000000..b41941b
--- /dev/null
@@ -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 (file)
index 0000000..dc3c9f3
--- /dev/null
@@ -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 (file)
index 0000000..8034c8f
--- /dev/null
@@ -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 (file)
index 55dffe9..0000000
+++ /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")); )
index eb48ec228d6b35886d6c8a87cd5e1c344f9479e3..d66b308b71e0b7364c6e2d04aef57af908ab280f 100644 (file)
@@ -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();
index 3af7dbede5f9108f7b8cb2d9703cf3a74ddd5021..5745113096b4433e473ada6793e56380c58537cf 100644 (file)
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -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 "
index 26849d511a618d4fd2126a74545d13b2b77d2944..480f876321e1cfc344ccaaa00a951cc8ec687834 100644 (file)
@@ -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',
index e2aacd0d9498d5e54fffc14a41f94cd28dcd1a35..87c6622caa4b457648715d3da1f056036387dc2b 100644 (file)
@@ -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',
index ac2ed303030f5b75e3b214359ca11fd63863e422..77ff8d159450bf50aee1b3b59006a041e1332790 100644 (file)
@@ -18,6 +18,8 @@
             'xml.gyp:xml',
           ],
           'sources': [
+            '../bench/DecodingBench.cpp',
+            '../bench/DecodingSubsetBench.cpp',
             '../bench/GMBench.cpp',
             '../bench/RecordingBench.cpp',
             '../bench/SKPBench.cpp',
index 2a0490cbb72b99dd2ab9a358356a7ba44e5cba46..15d9123e1edb068fe86ba6f6ad64764dd2e52c20 100644 (file)
@@ -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,
index 661501a4a9167f9afc56e85a3a1fc0ca846207c3..69b835800c6f80f47d39e2d712886fa85be50be4 100644 (file)
@@ -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);