Home | History | Annotate | Download | only in bench
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "Benchmark.h"
      9 #include "SkMatrix.h"
     10 #include "SkMatrixUtils.h"
     11 #include "SkRandom.h"
     12 #include "SkString.h"
     13 
     14 class MatrixBench : public Benchmark {
     15     SkString    fName;
     16 public:
     17     MatrixBench(const char name[])  {
     18         fName.printf("matrix_%s", name);
     19     }
     20 
     21     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
     22         return backend == kNonRendering_Backend;
     23     }
     24 
     25     virtual void performTest() = 0;
     26 
     27 protected:
     28     virtual int mulLoopCount() const { return 1; }
     29 
     30     virtual const char* onGetName() {
     31         return fName.c_str();
     32     }
     33 
     34     virtual void onDraw(const int loops, SkCanvas*) {
     35         for (int i = 0; i < loops; i++) {
     36             this->performTest();
     37         }
     38     }
     39 
     40 private:
     41     typedef Benchmark INHERITED;
     42 };
     43 
     44 
     45 class EqualsMatrixBench : public MatrixBench {
     46 public:
     47     EqualsMatrixBench() : INHERITED("equals") {}
     48 protected:
     49     virtual void performTest() {
     50         SkMatrix m0, m1, m2;
     51 
     52         m0.reset();
     53         m1.reset();
     54         m2.reset();
     55 
     56         // xor into a volatile prevents these comparisons from being optimized away.
     57         volatile bool junk = false;
     58         junk ^= (m0 == m1);
     59         junk ^= (m1 == m2);
     60         junk ^= (m2 == m0);
     61     }
     62 private:
     63     typedef MatrixBench INHERITED;
     64 };
     65 
     66 class ScaleMatrixBench : public MatrixBench {
     67 public:
     68     ScaleMatrixBench() : INHERITED("scale") {
     69         fSX = fSY = 1.5f;
     70         fM0.reset();
     71         fM1.setScale(fSX, fSY);
     72         fM2.setTranslate(fSX, fSY);
     73     }
     74 protected:
     75     virtual void performTest() {
     76         SkMatrix m;
     77         m = fM0; m.preScale(fSX, fSY);
     78         m = fM1; m.preScale(fSX, fSY);
     79         m = fM2; m.preScale(fSX, fSY);
     80     }
     81 private:
     82     SkMatrix fM0, fM1, fM2;
     83     SkScalar fSX, fSY;
     84     typedef MatrixBench INHERITED;
     85 };
     86 
     87 // having unknown values in our arrays can throw off the timing a lot, perhaps
     88 // handling NaN values is a lot slower. Anyway, this guy is just meant to put
     89 // reasonable values in our arrays.
     90 template <typename T> void init9(T array[9]) {
     91     SkRandom rand;
     92     for (int i = 0; i < 9; i++) {
     93         array[i] = rand.nextSScalar1();
     94     }
     95 }
     96 
     97 // Test the performance of setConcat() non-perspective case:
     98 // using floating point precision only.
     99 class FloatConcatMatrixBench : public MatrixBench {
    100 public:
    101     FloatConcatMatrixBench() : INHERITED("concat_floatfloat") {
    102         init9(mya);
    103         init9(myb);
    104         init9(myr);
    105     }
    106 protected:
    107     virtual int mulLoopCount() const { return 4; }
    108 
    109     static inline void muladdmul(float a, float b, float c, float d,
    110                                    float* result) {
    111       *result = a * b + c * d;
    112     }
    113     virtual void performTest() {
    114         const float* a = mya;
    115         const float* b = myb;
    116         float* r = myr;
    117         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
    118         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
    119         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
    120         r[2] += a[2];
    121         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
    122         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
    123         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
    124         r[5] += a[5];
    125         r[6] = r[7] = 0.0f;
    126         r[8] = 1.0f;
    127     }
    128 private:
    129     float mya [9];
    130     float myb [9];
    131     float myr [9];
    132     typedef MatrixBench INHERITED;
    133 };
    134 
    135 static inline float SkDoubleToFloat(double x) {
    136     return static_cast<float>(x);
    137 }
    138 
    139 // Test the performance of setConcat() non-perspective case:
    140 // using floating point precision but casting up to float for
    141 // intermediate results during computations.
    142 class FloatDoubleConcatMatrixBench : public MatrixBench {
    143 public:
    144     FloatDoubleConcatMatrixBench() : INHERITED("concat_floatdouble") {
    145         init9(mya);
    146         init9(myb);
    147         init9(myr);
    148     }
    149 protected:
    150     virtual int mulLoopCount() const { return 4; }
    151 
    152     static inline void muladdmul(float a, float b, float c, float d,
    153                                    float* result) {
    154       *result = SkDoubleToFloat((double)a * b + (double)c * d);
    155     }
    156     virtual void performTest() {
    157         const float* a = mya;
    158         const float* b = myb;
    159         float* r = myr;
    160         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
    161         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
    162         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
    163         r[2] += a[2];
    164         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
    165         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
    166         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
    167         r[5] += a[5];
    168         r[6] = r[7] = 0.0f;
    169         r[8] = 1.0f;
    170     }
    171 private:
    172     float mya [9];
    173     float myb [9];
    174     float myr [9];
    175     typedef MatrixBench INHERITED;
    176 };
    177 
    178 // Test the performance of setConcat() non-perspective case:
    179 // using double precision only.
    180 class DoubleConcatMatrixBench : public MatrixBench {
    181 public:
    182     DoubleConcatMatrixBench() : INHERITED("concat_double") {
    183         init9(mya);
    184         init9(myb);
    185         init9(myr);
    186     }
    187 protected:
    188     virtual int mulLoopCount() const { return 4; }
    189 
    190     static inline void muladdmul(double a, double b, double c, double d,
    191                                    double* result) {
    192       *result = a * b + c * d;
    193     }
    194     virtual void performTest() {
    195         const double* a = mya;
    196         const double* b = myb;
    197         double* r = myr;
    198         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
    199         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
    200         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
    201         r[2] += a[2];
    202         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
    203         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
    204         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
    205         r[5] += a[5];
    206         r[6] = r[7] = 0.0;
    207         r[8] = 1.0;
    208     }
    209 private:
    210     double mya [9];
    211     double myb [9];
    212     double myr [9];
    213     typedef MatrixBench INHERITED;
    214 };
    215 
    216 class GetTypeMatrixBench : public MatrixBench {
    217 public:
    218     GetTypeMatrixBench()
    219         : INHERITED("gettype") {
    220         fArray[0] = (float) fRnd.nextS();
    221         fArray[1] = (float) fRnd.nextS();
    222         fArray[2] = (float) fRnd.nextS();
    223         fArray[3] = (float) fRnd.nextS();
    224         fArray[4] = (float) fRnd.nextS();
    225         fArray[5] = (float) fRnd.nextS();
    226         fArray[6] = (float) fRnd.nextS();
    227         fArray[7] = (float) fRnd.nextS();
    228         fArray[8] = (float) fRnd.nextS();
    229     }
    230 protected:
    231     // Putting random generation of the matrix inside performTest()
    232     // would help us avoid anomalous runs, but takes up 25% or
    233     // more of the function time.
    234     virtual void performTest() {
    235         fMatrix.setAll(fArray[0], fArray[1], fArray[2],
    236                        fArray[3], fArray[4], fArray[5],
    237                        fArray[6], fArray[7], fArray[8]);
    238         // xoring into a volatile prevents the compiler from optimizing these away
    239         volatile int junk = 0;
    240         junk ^= (fMatrix.getType());
    241         fMatrix.dirtyMatrixTypeCache();
    242         junk ^= (fMatrix.getType());
    243         fMatrix.dirtyMatrixTypeCache();
    244         junk ^= (fMatrix.getType());
    245         fMatrix.dirtyMatrixTypeCache();
    246         junk ^= (fMatrix.getType());
    247         fMatrix.dirtyMatrixTypeCache();
    248         junk ^= (fMatrix.getType());
    249         fMatrix.dirtyMatrixTypeCache();
    250         junk ^= (fMatrix.getType());
    251         fMatrix.dirtyMatrixTypeCache();
    252         junk ^= (fMatrix.getType());
    253         fMatrix.dirtyMatrixTypeCache();
    254         junk ^= (fMatrix.getType());
    255     }
    256 private:
    257     SkMatrix fMatrix;
    258     float fArray[9];
    259     SkRandom fRnd;
    260     typedef MatrixBench INHERITED;
    261 };
    262 
    263 class ScaleTransMixedMatrixBench : public MatrixBench {
    264  public:
    265     ScaleTransMixedMatrixBench() : INHERITED("scaletrans_mixed") {
    266         fMatrix.setAll(fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
    267                        fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
    268                        fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1());
    269         int i;
    270         for (i = 0; i < kCount; i++) {
    271             fSrc[i].fX = fRandom.nextSScalar1();
    272             fSrc[i].fY = fRandom.nextSScalar1();
    273             fDst[i].fX = fRandom.nextSScalar1();
    274             fDst[i].fY = fRandom.nextSScalar1();
    275         }
    276     }
    277  protected:
    278     virtual void performTest() {
    279         SkPoint* dst = fDst;
    280         const SkPoint* src = fSrc;
    281         int count = kCount;
    282         float mx = fMatrix[SkMatrix::kMScaleX];
    283         float my = fMatrix[SkMatrix::kMScaleY];
    284         float tx = fMatrix[SkMatrix::kMTransX];
    285         float ty = fMatrix[SkMatrix::kMTransY];
    286         do {
    287             dst->fY = SkScalarMulAdd(src->fY, my, ty);
    288             dst->fX = SkScalarMulAdd(src->fX, mx, tx);
    289             src += 1;
    290             dst += 1;
    291         } while (--count);
    292     }
    293  private:
    294     enum {
    295         kCount = 16
    296     };
    297     SkMatrix fMatrix;
    298     SkPoint fSrc [kCount];
    299     SkPoint fDst [kCount];
    300     SkRandom fRandom;
    301     typedef MatrixBench INHERITED;
    302 };
    303 
    304 class ScaleTransDoubleMatrixBench : public MatrixBench {
    305  public:
    306     ScaleTransDoubleMatrixBench() : INHERITED("scaletrans_double") {
    307         init9(fMatrix);
    308         int i;
    309         for (i = 0; i < kCount; i++) {
    310             fSrc[i].fX = fRandom.nextSScalar1();
    311             fSrc[i].fY = fRandom.nextSScalar1();
    312             fDst[i].fX = fRandom.nextSScalar1();
    313             fDst[i].fY = fRandom.nextSScalar1();
    314         }
    315     }
    316  protected:
    317     virtual void performTest() {
    318         SkPoint* dst = fDst;
    319         const SkPoint* src = fSrc;
    320         int count = kCount;
    321         // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
    322         float mx = (float) fMatrix[SkMatrix::kMScaleX];
    323         float my = (float) fMatrix[SkMatrix::kMScaleY];
    324         float tx = (float) fMatrix[SkMatrix::kMTransX];
    325         float ty = (float) fMatrix[SkMatrix::kMTransY];
    326         do {
    327             dst->fY = src->fY * my + ty;
    328             dst->fX = src->fX * mx + tx;
    329             src += 1;
    330             dst += 1;
    331         } while (--count);
    332     }
    333  private:
    334     enum {
    335         kCount = 16
    336     };
    337     double fMatrix [9];
    338     SkPoint fSrc [kCount];
    339     SkPoint fDst [kCount];
    340     SkRandom fRandom;
    341     typedef MatrixBench INHERITED;
    342 };
    343 
    344 class DecomposeMatrixBench : public MatrixBench {
    345 public:
    346     DecomposeMatrixBench() : INHERITED("decompose") {}
    347 
    348 protected:
    349     virtual void onPreDraw() {
    350         for (int i = 0; i < 10; ++i) {
    351             SkScalar rot0 = (fRandom.nextBool()) ? fRandom.nextRangeF(-180, 180) : 0.0f;
    352             SkScalar sx = fRandom.nextRangeF(-3000.f, 3000.f);
    353             SkScalar sy = (fRandom.nextBool()) ? fRandom.nextRangeF(-3000.f, 3000.f) : sx;
    354             SkScalar rot1 = fRandom.nextRangeF(-180, 180);
    355             fMatrix[i].setRotate(rot0);
    356             fMatrix[i].postScale(sx, sy);
    357             fMatrix[i].postRotate(rot1);
    358         }
    359     }
    360     virtual void performTest() {
    361         SkPoint rotation1, scale, rotation2;
    362         for (int i = 0; i < 10; ++i) {
    363             (void) SkDecomposeUpper2x2(fMatrix[i], &rotation1, &scale, &rotation2);
    364         }
    365     }
    366 private:
    367     SkMatrix fMatrix[10];
    368     SkRandom fRandom;
    369     typedef MatrixBench INHERITED;
    370 };
    371 
    372 class InvertMapRectMatrixBench : public MatrixBench {
    373 public:
    374     InvertMapRectMatrixBench(const char* name, int flags)
    375         : INHERITED(name)
    376         , fFlags(flags) {
    377         fMatrix.reset();
    378         fIteration = 0;
    379         if (flags & kScale_Flag) {
    380             fMatrix.postScale(1.5f, 2.5f);
    381         }
    382         if (flags & kTranslate_Flag) {
    383             fMatrix.postTranslate(1.5f, 2.5f);
    384         }
    385         if (flags & kRotate_Flag) {
    386             fMatrix.postRotate(45.0f);
    387         }
    388         if (flags & kPerspective_Flag) {
    389             fMatrix.setPerspX(1.5f);
    390             fMatrix.setPerspY(2.5f);
    391         }
    392         if (0 == (flags & kUncachedTypeMask_Flag)) {
    393             fMatrix.getType();
    394         }
    395     }
    396     enum Flag {
    397         kScale_Flag             = 0x01,
    398         kTranslate_Flag         = 0x02,
    399         kRotate_Flag            = 0x04,
    400         kPerspective_Flag       = 0x08,
    401         kUncachedTypeMask_Flag  = 0x10,
    402     };
    403 protected:
    404     virtual void performTest() {
    405         if (fFlags & kUncachedTypeMask_Flag) {
    406             // This will invalidate the typemask without
    407             // changing the matrix.
    408             fMatrix.setPerspX(fMatrix.getPerspX());
    409         }
    410         SkMatrix inv;
    411         bool invertible = fMatrix.invert(&inv);
    412         SkASSERT(invertible);
    413         SkRect transformedRect;
    414         // an arbitrary, small, non-zero rect to transform
    415         SkRect srcRect = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10));
    416         if (invertible) {
    417             inv.mapRect(&transformedRect, srcRect);
    418         }
    419     }
    420 private:
    421     SkMatrix fMatrix;
    422     int fFlags;
    423     unsigned fIteration;
    424     typedef MatrixBench INHERITED;
    425 };
    426 
    427 ///////////////////////////////////////////////////////////////////////////////
    428 
    429 DEF_BENCH( return new EqualsMatrixBench(); )
    430 DEF_BENCH( return new ScaleMatrixBench(); )
    431 DEF_BENCH( return new FloatConcatMatrixBench(); )
    432 DEF_BENCH( return new FloatDoubleConcatMatrixBench(); )
    433 DEF_BENCH( return new DoubleConcatMatrixBench(); )
    434 DEF_BENCH( return new GetTypeMatrixBench(); )
    435 DEF_BENCH( return new DecomposeMatrixBench(); )
    436 
    437 DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); )
    438 
    439 DEF_BENCH(return new InvertMapRectMatrixBench(
    440                                   "invert_maprect_rectstaysrect",
    441                                   InvertMapRectMatrixBench::kScale_Flag |
    442                                   InvertMapRectMatrixBench::kTranslate_Flag); )
    443 
    444 DEF_BENCH(return new InvertMapRectMatrixBench(
    445                                   "invert_maprect_translate",
    446                                   InvertMapRectMatrixBench::kTranslate_Flag); )
    447 
    448 DEF_BENCH(return new InvertMapRectMatrixBench(
    449                                   "invert_maprect_nonpersp",
    450                                   InvertMapRectMatrixBench::kScale_Flag |
    451                                   InvertMapRectMatrixBench::kRotate_Flag |
    452                                   InvertMapRectMatrixBench::kTranslate_Flag); )
    453 
    454 DEF_BENCH( return new InvertMapRectMatrixBench(
    455                                "invert_maprect_persp",
    456                                InvertMapRectMatrixBench::kPerspective_Flag); )
    457 
    458 DEF_BENCH( return new InvertMapRectMatrixBench(
    459                            "invert_maprect_typemask_rectstaysrect",
    460                            InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
    461                            InvertMapRectMatrixBench::kScale_Flag |
    462                            InvertMapRectMatrixBench::kTranslate_Flag); )
    463 
    464 DEF_BENCH( return new InvertMapRectMatrixBench(
    465                            "invert_maprect_typemask_nonpersp",
    466                            InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
    467                            InvertMapRectMatrixBench::kScale_Flag |
    468                            InvertMapRectMatrixBench::kRotate_Flag |
    469                            InvertMapRectMatrixBench::kTranslate_Flag); )
    470 
    471 DEF_BENCH( return new ScaleTransMixedMatrixBench(); )
    472 DEF_BENCH( return new ScaleTransDoubleMatrixBench(); )
    473