diff options
Diffstat (limited to 'bench')
-rw-r--r-- | bench/Android.mk | 6 | ||||
-rw-r--r-- | bench/MatrixBench.cpp | 229 | ||||
-rw-r--r-- | bench/bench_compare.py | 140 | ||||
-rw-r--r-- | bench/benchmain.cpp | 146 |
4 files changed, 456 insertions, 65 deletions
diff --git a/bench/Android.mk b/bench/Android.mk index b20aef9..71523af 100644 --- a/bench/Android.mk +++ b/bench/Android.mk @@ -6,6 +6,9 @@ LOCAL_SRC_FILES := \ BitmapBench.cpp \ DecodeBench.cpp \ FPSBench.cpp \ + GradientBench.cpp \ + MatrixBench.cpp \ + PathBench.cpp \ RectBench.cpp \ RepeatTileBench.cpp \ TextBench.cpp \ @@ -17,7 +20,8 @@ LOCAL_SRC_FILES += \ ../src/utils/SkNWayCanvas.cpp \ ../src/utils/SkParse.cpp -LOCAL_SHARED_LIBRARIES := libcutils libskia +LOCAL_SHARED_LIBRARIES := libcutils libskia libGLESv2 +LOCAL_STATIC_LIBRARIES := libskiagpu LOCAL_C_INCLUDES := \ external/skia/include/config \ external/skia/include/core \ diff --git a/bench/MatrixBench.cpp b/bench/MatrixBench.cpp new file mode 100644 index 0000000..d963bc7 --- /dev/null +++ b/bench/MatrixBench.cpp @@ -0,0 +1,229 @@ +#include "SkBenchmark.h" +#include "SkMatrix.h" +#include "SkRandom.h" +#include "SkString.h" + +class MatrixBench : public SkBenchmark { + SkString fName; + enum { N = 100000 }; +public: + MatrixBench(void* param, const char name[]) : INHERITED(param) { + fName.printf("matrix_%s", name); + } + + virtual void performTest() = 0; + +protected: + virtual int mulLoopCount() const { return 1; } + + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(SkCanvas* canvas) { + int n = N * this->mulLoopCount(); + for (int i = 0; i < n; i++) { + this->performTest(); + } + } + +private: + typedef SkBenchmark INHERITED; +}; + +// we want to stop the compiler from eliminating code that it thinks is a no-op +// so we have a non-static global we increment, hoping that will convince the +// compiler to execute everything +int gMatrixBench_NonStaticGlobal; + +#define always_do(pred) \ + do { \ + if (pred) { \ + ++gMatrixBench_NonStaticGlobal; \ + } \ + } while (0) + +class EqualsMatrixBench : public MatrixBench { +public: + EqualsMatrixBench(void* param) : INHERITED(param, "equals") {} +protected: + virtual void performTest() { + SkMatrix m0, m1, m2; + + m0.reset(); + m1.reset(); + m2.reset(); + always_do(m0 == m1); + always_do(m1 == m2); + always_do(m2 == m0); + always_do(m0.getType()); + always_do(m1.getType()); + always_do(m2.getType()); + } +private: + typedef MatrixBench INHERITED; +}; + +class ScaleMatrixBench : public MatrixBench { +public: + ScaleMatrixBench(void* param) : INHERITED(param, "scale") { + + fM0.reset(); + fM1.setScale(fSX, fSY); + fM2.setTranslate(fSX, fSY); + fSX = fSY = SkFloatToScalar(1.5f); + } +protected: + virtual void performTest() { + SkMatrix m; + m = fM0; m.preScale(fSX, fSY); + m = fM1; m.preScale(fSX, fSY); + m = fM2; m.preScale(fSX, fSY); + } +private: + SkMatrix fM0, fM1, fM2; + SkScalar fSX, fSY; + typedef MatrixBench INHERITED; +}; + +// having unknown values in our arrays can throw off the timing a lot, perhaps +// handling NaN values is a lot slower. Anyway, this guy is just meant to put +// reasonable values in our arrays. +template <typename T> void init9(T array[9]) { + SkRandom rand; + for (int i = 0; i < 9; i++) { + array[i] = rand.nextSScalar1(); + } +} + +// Test the performance of setConcat() non-perspective case: +// using floating point precision only. +class FloatConcatMatrixBench : public MatrixBench { +public: + FloatConcatMatrixBench(void* p) : INHERITED(p, "concat_floatfloat") { + init9(mya); + init9(myb); + init9(myr); + } +protected: + virtual int mulLoopCount() const { return 4; } + + static inline void muladdmul(float a, float b, float c, float d, + float* result) { + *result = a * b + c * d; + } + virtual void performTest() { + const float* a = mya; + const float* b = myb; + float* r = myr; + muladdmul(a[0], b[0], a[1], b[3], &r[0]); + muladdmul(a[0], b[1], a[1], b[4], &r[1]); + muladdmul(a[0], b[2], a[1], b[5], &r[2]); + r[2] += a[2]; + muladdmul(a[3], b[0], a[4], b[3], &r[3]); + muladdmul(a[3], b[1], a[4], b[4], &r[4]); + muladdmul(a[3], b[2], a[4], b[5], &r[5]); + r[5] += a[5]; + r[6] = r[7] = 0.0f; + r[8] = 1.0f; + } +private: + float mya [9]; + float myb [9]; + float myr [9]; + typedef MatrixBench INHERITED; +}; + +static inline float SkDoubleToFloat(double x) { + return static_cast<float>(x); +} + +// Test the performance of setConcat() non-perspective case: +// using floating point precision but casting up to float for +// intermediate results during computations. +class FloatDoubleConcatMatrixBench : public MatrixBench { +public: + FloatDoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_floatdouble") { + init9(mya); + init9(myb); + init9(myr); + } +protected: + virtual int mulLoopCount() const { return 4; } + + static inline void muladdmul(float a, float b, float c, float d, + float* result) { + *result = SkDoubleToFloat((double)a * b + (double)c * d); + } + virtual void performTest() { + const float* a = mya; + const float* b = myb; + float* r = myr; + muladdmul(a[0], b[0], a[1], b[3], &r[0]); + muladdmul(a[0], b[1], a[1], b[4], &r[1]); + muladdmul(a[0], b[2], a[1], b[5], &r[2]); + r[2] += a[2]; + muladdmul(a[3], b[0], a[4], b[3], &r[3]); + muladdmul(a[3], b[1], a[4], b[4], &r[4]); + muladdmul(a[3], b[2], a[4], b[5], &r[5]); + r[5] += a[5]; + r[6] = r[7] = 0.0f; + r[8] = 1.0f; + } +private: + float mya [9]; + float myb [9]; + float myr [9]; + typedef MatrixBench INHERITED; +}; + +// Test the performance of setConcat() non-perspective case: +// using double precision only. +class DoubleConcatMatrixBench : public MatrixBench { +public: + DoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_double") { + init9(mya); + init9(myb); + init9(myr); + } +protected: + virtual int mulLoopCount() const { return 4; } + + static inline void muladdmul(double a, double b, double c, double d, + double* result) { + *result = a * b + c * d; + } + virtual void performTest() { + const double* a = mya; + const double* b = myb; + double* r = myr; + muladdmul(a[0], b[0], a[1], b[3], &r[0]); + muladdmul(a[0], b[1], a[1], b[4], &r[1]); + muladdmul(a[0], b[2], a[1], b[5], &r[2]); + r[2] += a[2]; + muladdmul(a[3], b[0], a[4], b[3], &r[3]); + muladdmul(a[3], b[1], a[4], b[4], &r[4]); + muladdmul(a[3], b[2], a[4], b[5], &r[5]); + r[5] += a[5]; + r[6] = r[7] = 0.0; + r[8] = 1.0; + } +private: + double mya [9]; + double myb [9]; + double myr [9]; + typedef MatrixBench INHERITED; +}; + + +static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); } +static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); } +static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); } +static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); } +static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); } + +static BenchRegistry gReg0(M0); +static BenchRegistry gReg1(M1); +static BenchRegistry gReg2(M2); +static BenchRegistry gReg3(M3); +static BenchRegistry gReg4(M4); diff --git a/bench/bench_compare.py b/bench/bench_compare.py new file mode 100644 index 0000000..f6909b1 --- /dev/null +++ b/bench/bench_compare.py @@ -0,0 +1,140 @@ +''' +Created on May 16, 2011 + +@author: bungeman +''' +import sys +import getopt +import re + +def parse(lines): + """Takes iterable lines of bench output, returns {bench:{config:time}}.""" + + benches = {} + current_bench = None + + for line in lines: + #see if this line starts a new bench + new_bench = re.search('running bench \[\d+ \d+\] (.{28})', line) + if new_bench: + current_bench = new_bench.group(1) + + #add configs on this line to the current bench + if current_bench: + for new_config in re.finditer(' (.{4}): msecs = (\d+\.\d+)', line): + current_config = new_config.group(1) + current_time = float(new_config.group(2)) + if current_bench in benches: + benches[current_bench][current_config] = current_time + else: + benches[current_bench] = {current_config : current_time} + + return benches + +def usage(): + """Prints simple usage information.""" + + print '-o <file> the old bench output file.' + print '-n <file> the new bench output file.' + print '-h causes headers to be output.' + print '-f <fieldSpec> which fields to output and in what order.' + print ' Not specifying is the same as -f "bcondp".' + print ' b: bench' + print ' c: config' + print ' o: old time' + print ' n: new time' + print ' d: diff' + print ' p: percent diff' + + +def main(): + """Parses command line and writes output.""" + + try: + opts, args = getopt.getopt(sys.argv[1:], "f:o:n:h") + except getopt.GetoptError, err: + print str(err) + usage() + sys.exit(2) + + column_formats = { + 'b' : '{bench: >28} ', + 'c' : '{config: <4} ', + 'o' : '{old_time: >10.2f} ', + 'n' : '{new_time: >10.2f} ', + 'd' : '{diff: >+10.2f} ', + 'p' : '{diffp: >+7.1%} ', + } + header_formats = { + 'b' : '{bench: >28} ', + 'c' : '{config: <4} ', + 'o' : '{old_time: >10} ', + 'n' : '{new_time: >10} ', + 'd' : '{diff: >10} ', + 'p' : '{diffp: >7} ', + } + + old = None + new = None + column_format = "" + header_format = "" + columns = 'bcondp' + header = False + + for option, value in opts: + if option == "-o": + old = value + elif option == "-n": + new = value + elif option == "-h": + header = True + elif option == "-f": + columns = value + else: + usage() + assert False, "unhandled option" + + if old is None or new is None: + usage() + sys.exit(2) + + for column_char in columns: + if column_formats[column_char]: + column_format += column_formats[column_char] + header_format += header_formats[column_char] + else: + usage() + sys.exit(2) + + if header: + print header_format.format( + bench='bench' + , config='conf' + , old_time='old' + , new_time='new' + , diff='diff' + , diffp='diffP' + ) + + old_benches = parse(open(old, 'r')) + new_benches = parse(open(new, 'r')) + + for old_bench, old_configs in old_benches.items(): + if old_bench in new_benches: + new_configs = new_benches[old_bench] + for old_config, old_time in old_configs.items(): + if old_config in new_configs: + new_time = new_configs[old_config] + old_time = old_configs[old_config] + print column_format.format( + bench=old_bench.strip() + , config=old_config.strip() + , old_time=old_time + , new_time=new_time + , diff=(old_time - new_time) + , diffp=((old_time-new_time)/old_time) + ) + + +if __name__ == "__main__": + main() diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index 4f6d81c..066573a 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -6,6 +6,9 @@ #include "SkPicture.h" #include "SkString.h" #include "SkTime.h" +#include "GrContext.h" +#include "SkGpuDevice.h" +#include "SkEGLContext.h" #include "SkBenchmark.h" @@ -30,6 +33,7 @@ static void erase(SkBitmap& bm) { } } +#if 0 static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { if (bm1.width() != bm2.width() || bm1.height() != bm2.height() || @@ -43,9 +47,9 @@ static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { return false; } } - return true; } +#endif class Iter { public: @@ -62,7 +66,7 @@ public: } return NULL; } - + private: const BenchRegistry* fBench; void* fParam; @@ -102,7 +106,7 @@ static void saveFile(const char name[], const char config[], const char dir[], *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); } } - + SkString str; make_filename(name, &str); str.appendf("_%s.png", config); @@ -118,7 +122,7 @@ static void performClip(SkCanvas* canvas, int w, int h) { r.set(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); canvas->clipRect(r, SkRegion::kIntersect_Op); - + r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), SkIntToScalar(w-10), SkIntToScalar(h-10)); canvas->clipRect(r, SkRegion::kXOR_Op); @@ -143,21 +147,6 @@ static void performScale(SkCanvas* canvas, int w, int h) { canvas->translate(-x, -y); } -static void compare_pict_to_bitmap(SkPicture* pict, const SkBitmap& bm) { - SkBitmap bm2; - - bm2.setConfig(bm.config(), bm.width(), bm.height()); - bm2.allocPixels(); - erase(bm2); - - SkCanvas canvas(bm2); - canvas.drawPicture(*pict); - - if (!equal(bm, bm2)) { - SkDebugf("----- compare_pict_to_bitmap failed\n"); - } -} - static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { if (argv < stop) { *var = atoi(*argv) != 0; @@ -166,16 +155,43 @@ static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { return false; } +enum Backend { + kRaster_Backend, + kGPU_Backend, + kPDF_Backend, +}; + +static SkDevice* make_device(SkBitmap::Config config, const SkIPoint& size, + Backend backend, GrContext* context) { + SkDevice* device = NULL; + SkBitmap bitmap; + bitmap.setConfig(config, size.fX, size.fY); + + switch (backend) { + case kRaster_Backend: + bitmap.allocPixels(); + erase(bitmap); + device = new SkDevice(NULL, bitmap, true); + break; + case kGPU_Backend: + device = new SkGpuDevice(context, bitmap, SkGpuDevice::Current3DApiRenderTarget()); +// device->clear(0xFFFFFFFF); + break; + case kPDF_Backend: + default: + SkASSERT(!"unsupported"); + } + return device; +} + static const struct { SkBitmap::Config fConfig; const char* fName; + Backend fBackend; } gConfigs[] = { - { SkBitmap::kARGB_8888_Config, "8888" }, - { SkBitmap::kRGB_565_Config, "565", }, -#if 0 - { SkBitmap::kARGB_4444_Config, "4444", }, - { SkBitmap::kA8_Config, "A8", } -#endif + { SkBitmap::kARGB_8888_Config, "8888", kRaster_Backend }, + { SkBitmap::kRGB_565_Config, "565", kRaster_Backend }, + { SkBitmap::kARGB_8888_Config, "GPU", kGPU_Backend }, }; static int findConfig(const char config[]) { @@ -189,7 +205,7 @@ static int findConfig(const char config[]) { int main (int argc, char * const argv[]) { SkAutoGraphics ag; - + SkTDict<const char*> defineDict(1024); int repeatDraw = 1; int forceAlpha = 0xFF; @@ -199,16 +215,16 @@ int main (int argc, char * const argv[]) { bool doScale = false; bool doRotate = false; bool doClip = false; - bool doPict = false; const char* matchStr = NULL; bool hasStrokeWidth = false; float strokeWidth; - + SkString outDir; SkBitmap::Config outConfig = SkBitmap::kNo_Config; const char* configName = ""; + Backend backend = kRaster_Backend; // for warning int configCount = SK_ARRAY_COUNT(gConfigs); - + char* const* stop = argv + argc; for (++argv; argv < stop; ++argv) { if (strcmp(*argv, "-o") == 0) { @@ -219,8 +235,6 @@ int main (int argc, char * const argv[]) { outDir.append("/"); } } - } else if (strcmp(*argv, "-pict") == 0) { - doPict = true; } else if (strcmp(*argv, "-repeat") == 0) { argv++; if (argv < stop) { @@ -290,6 +304,7 @@ int main (int argc, char * const argv[]) { if (index >= 0) { outConfig = gConfigs[index].fConfig; configName = gConfigs[index].fName; + backend = gConfigs[index].fBackend; configCount = 1; } else { SkString str; @@ -316,7 +331,7 @@ int main (int argc, char * const argv[]) { return -1; } } - + // report our current settings { SkString str; @@ -324,7 +339,13 @@ int main (int argc, char * const argv[]) { forceAlpha, forceAA, forceFilter); log_progress(str); } - + + GrContext* context = NULL; + SkEGLContext eglContext; + if (eglContext.init(1024, 1024)) { + context = GrContext::CreateGLShaderContext(); + } + Iter iter(&defineDict); SkBenchmark* bench; while ((bench = iter.next()) != NULL) { @@ -340,32 +361,34 @@ int main (int argc, char * const argv[]) { if (hasStrokeWidth) { bench->setStrokeWidth(strokeWidth); } - + // only run benchmarks if their name contains matchStr if (matchStr && strstr(bench->getName(), matchStr) == NULL) { continue; } - + { SkString str; str.printf("running bench [%d %d] %28s", dim.fX, dim.fY, bench->getName()); log_progress(str); } - + for (int configIndex = 0; configIndex < configCount; configIndex++) { if (configCount > 1) { outConfig = gConfigs[configIndex].fConfig; configName = gConfigs[configIndex].fName; + backend = gConfigs[configIndex].fBackend; } - SkBitmap bm; - bm.setConfig(outConfig, dim.fX, dim.fY); - bm.allocPixels(); - erase(bm); - - SkCanvas canvas(bm); - + if (kGPU_Backend == backend && NULL == context) { + continue; + } + + SkDevice* device = make_device(outConfig, dim, backend, context); + SkCanvas canvas(device); + device->unref(); + if (doClip) { performClip(&canvas, dim.fX, dim.fY); } @@ -375,33 +398,27 @@ int main (int argc, char * const argv[]) { if (doRotate) { performRotate(&canvas, dim.fX, dim.fY); } - + + //warm up caches if needed if (repeatDraw > 1) { SkAutoCanvasRestore acr(&canvas, true); bench->draw(&canvas); + if (kGPU_Backend == backend && context) { + context->flush(); + glFinish(); + } } - + SkMSec now = SkTime::GetMSecs(); for (int i = 0; i < repeatDraw; i++) { - SkCanvas* c = &canvas; - - SkNWayCanvas nway; - SkPicture* pict = NULL; - if (doPict) { - pict = new SkPicture; - nway.addCanvas(pict->beginRecording(bm.width(), bm.height())); - nway.addCanvas(&canvas); - c = &nway; - } - - SkAutoCanvasRestore acr(c, true); - bench->draw(c); - - if (pict) { - compare_pict_to_bitmap(pict, bm); - pict->unref(); - } + SkAutoCanvasRestore acr(&canvas, true); + bench->draw(&canvas); + } + if (kGPU_Backend == backend && context) { + context->flush(); + glFinish(); } + if (repeatDraw > 1) { double duration = SkTime::GetMSecs() - now; SkString str; @@ -409,7 +426,8 @@ int main (int argc, char * const argv[]) { log_progress(str); } if (outDir.size() > 0) { - saveFile(bench->getName(), configName, outDir.c_str(), bm); + saveFile(bench->getName(), configName, outDir.c_str(), + device->accessBitmap(false)); } } log_progress("\n"); |