Adding new benchmark to test image decoding performance.

BUG=skia:

Review URL: https://codereview.chromium.org/918673002
This commit is contained in:
msarett 2015-02-13 09:05:41 -08:00 committed by Commit bot
parent a8fcea0cd0
commit 95f192d199
13 changed files with 318 additions and 147 deletions

View File

@ -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); )

62
bench/DecodingBench.cpp Normal file
View File

@ -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);
}
}

35
bench/DecodingBench.h Normal file
View File

@ -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;
};

View File

@ -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);
}
}
}
}

View File

@ -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;
};

View File

@ -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")); )

View 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();

View File

@ -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 "

View 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',

View 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',

View File

@ -18,6 +18,8 @@
'xml.gyp:xml',
],
'sources': [
'../bench/DecodingBench.cpp',
'../bench/DecodingSubsetBench.cpp',
'../bench/GMBench.cpp',
'../bench/RecordingBench.cpp',
'../bench/SKPBench.cpp',

View 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,

View 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);