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