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     }
     20 
     21     virtual void performTest() = 0;
     22 
     23 protected:
     24     virtual int mulLoopCount() const { return 1; }
     25 
     26     virtual const char* onGetName() {
     27         return fName.c_str();
     28     }
     29 
     30     virtual void onDraw(SkCanvas* canvas) {
     31         int n = SkBENCHLOOP(N * this->mulLoopCount());
     32         for (int i = 0; i < n; i++) {
     33             this->performTest();
     34         }
     35     }
     36 
     37 private:
     38     typedef SkBenchmark INHERITED;
     39 };
     40 
     41 // we want to stop the compiler from eliminating code that it thinks is a no-op
     42 // so we have a non-static global we increment, hoping that will convince the
     43 // compiler to execute everything
     44 int gMatrixBench_NonStaticGlobal;
     45 
     46 #define always_do(pred)                     \
     47     do {                                    \
     48         if (pred) {                         \
     49             ++gMatrixBench_NonStaticGlobal; \
     50         }                                   \
     51     } while (0)
     52 
     53 class EqualsMatrixBench : public MatrixBench {
     54 public:
     55     EqualsMatrixBench(void* param) : INHERITED(param, "equals") {}
     56 protected:
     57     virtual void performTest() {
     58         SkMatrix m0, m1, m2;
     59 
     60         m0.reset();
     61         m1.reset();
     62         m2.reset();
     63         always_do(m0 == m1);
     64         always_do(m1 == m2);
     65         always_do(m2 == m0);
     66     }
     67 private:
     68     typedef MatrixBench INHERITED;
     69 };
     70 
     71 class ScaleMatrixBench : public MatrixBench {
     72 public:
     73     ScaleMatrixBench(void* param) : INHERITED(param, "scale") {
     74         fSX = fSY = SkFloatToScalar(1.5f);
     75         fM0.reset();
     76         fM1.setScale(fSX, fSY);
     77         fM2.setTranslate(fSX, fSY);
     78     }
     79 protected:
     80     virtual void performTest() {
     81         SkMatrix m;
     82         m = fM0; m.preScale(fSX, fSY);
     83         m = fM1; m.preScale(fSX, fSY);
     84         m = fM2; m.preScale(fSX, fSY);
     85     }
     86 private:
     87     SkMatrix fM0, fM1, fM2;
     88     SkScalar fSX, fSY;
     89     typedef MatrixBench INHERITED;
     90 };
     91 
     92 // having unknown values in our arrays can throw off the timing a lot, perhaps
     93 // handling NaN values is a lot slower. Anyway, this guy is just meant to put
     94 // reasonable values in our arrays.
     95 template <typename T> void init9(T array[9]) {
     96     SkRandom rand;
     97     for (int i = 0; i < 9; i++) {
     98         array[i] = rand.nextSScalar1();
     99     }
    100 }
    101 
    102 // Test the performance of setConcat() non-perspective case:
    103 // using floating point precision only.
    104 class FloatConcatMatrixBench : public MatrixBench {
    105 public:
    106     FloatConcatMatrixBench(void* p) : INHERITED(p, "concat_floatfloat") {
    107         init9(mya);
    108         init9(myb);
    109         init9(myr);
    110     }
    111 protected:
    112     virtual int mulLoopCount() const { return 4; }
    113 
    114     static inline void muladdmul(float a, float b, float c, float d,
    115                                    float* result) {
    116       *result = a * b + c * d;
    117     }
    118     virtual void performTest() {
    119         const float* a = mya;
    120         const float* b = myb;
    121         float* r = myr;
    122         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
    123         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
    124         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
    125         r[2] += a[2];
    126         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
    127         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
    128         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
    129         r[5] += a[5];
    130         r[6] = r[7] = 0.0f;
    131         r[8] = 1.0f;
    132     }
    133 private:
    134     float mya [9];
    135     float myb [9];
    136     float myr [9];
    137     typedef MatrixBench INHERITED;
    138 };
    139 
    140 static inline float SkDoubleToFloat(double x) {
    141     return static_cast<float>(x);
    142 }
    143 
    144 // Test the performance of setConcat() non-perspective case:
    145 // using floating point precision but casting up to float for
    146 // intermediate results during computations.
    147 class FloatDoubleConcatMatrixBench : public MatrixBench {
    148 public:
    149     FloatDoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_floatdouble") {
    150         init9(mya);
    151         init9(myb);
    152         init9(myr);
    153     }
    154 protected:
    155     virtual int mulLoopCount() const { return 4; }
    156 
    157     static inline void muladdmul(float a, float b, float c, float d,
    158                                    float* result) {
    159       *result = SkDoubleToFloat((double)a * b + (double)c * d);
    160     }
    161     virtual void performTest() {
    162         const float* a = mya;
    163         const float* b = myb;
    164         float* r = myr;
    165         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
    166         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
    167         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
    168         r[2] += a[2];
    169         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
    170         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
    171         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
    172         r[5] += a[5];
    173         r[6] = r[7] = 0.0f;
    174         r[8] = 1.0f;
    175     }
    176 private:
    177     float mya [9];
    178     float myb [9];
    179     float myr [9];
    180     typedef MatrixBench INHERITED;
    181 };
    182 
    183 // Test the performance of setConcat() non-perspective case:
    184 // using double precision only.
    185 class DoubleConcatMatrixBench : public MatrixBench {
    186 public:
    187     DoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_double") {
    188         init9(mya);
    189         init9(myb);
    190         init9(myr);
    191     }
    192 protected:
    193     virtual int mulLoopCount() const { return 4; }
    194 
    195     static inline void muladdmul(double a, double b, double c, double d,
    196                                    double* result) {
    197       *result = a * b + c * d;
    198     }
    199     virtual void performTest() {
    200         const double* a = mya;
    201         const double* b = myb;
    202         double* r = myr;
    203         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
    204         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
    205         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
    206         r[2] += a[2];
    207         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
    208         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
    209         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
    210         r[5] += a[5];
    211         r[6] = r[7] = 0.0;
    212         r[8] = 1.0;
    213     }
    214 private:
    215     double mya [9];
    216     double myb [9];
    217     double myr [9];
    218     typedef MatrixBench INHERITED;
    219 };
    220 
    221 class GetTypeMatrixBench : public MatrixBench {
    222 public:
    223     GetTypeMatrixBench(void* param)
    224         : INHERITED(param, "gettype") {
    225         fArray[0] = (float) fRnd.nextS();
    226         fArray[1] = (float) fRnd.nextS();
    227         fArray[2] = (float) fRnd.nextS();
    228         fArray[3] = (float) fRnd.nextS();
    229         fArray[4] = (float) fRnd.nextS();
    230         fArray[5] = (float) fRnd.nextS();
    231         fArray[6] = (float) fRnd.nextS();
    232         fArray[7] = (float) fRnd.nextS();
    233         fArray[8] = (float) fRnd.nextS();
    234     }
    235 protected:
    236     // Putting random generation of the matrix inside performTest()
    237     // would help us avoid anomalous runs, but takes up 25% or
    238     // more of the function time.
    239     virtual void performTest() {
    240         fMatrix.setAll(fArray[0], fArray[1], fArray[2],
    241                        fArray[3], fArray[4], fArray[5],
    242                        fArray[6], fArray[7], fArray[8]);
    243         always_do(fMatrix.getType());
    244         fMatrix.dirtyMatrixTypeCache();
    245         always_do(fMatrix.getType());
    246         fMatrix.dirtyMatrixTypeCache();
    247         always_do(fMatrix.getType());
    248         fMatrix.dirtyMatrixTypeCache();
    249         always_do(fMatrix.getType());
    250         fMatrix.dirtyMatrixTypeCache();
    251         always_do(fMatrix.getType());
    252         fMatrix.dirtyMatrixTypeCache();
    253         always_do(fMatrix.getType());
    254         fMatrix.dirtyMatrixTypeCache();
    255         always_do(fMatrix.getType());
    256         fMatrix.dirtyMatrixTypeCache();
    257         always_do(fMatrix.getType());
    258     }
    259 private:
    260     SkMatrix fMatrix;
    261     float fArray[9];
    262     SkRandom fRnd;
    263     typedef MatrixBench INHERITED;
    264 };
    265 
    266 #ifdef SK_SCALAR_IS_FLOAT
    267 class ScaleTransMixedMatrixBench : public MatrixBench {
    268  public:
    269     ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) {
    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 < SkBENCHLOOP(fCount); 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 = SkBENCHLOOP(fCount);
    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     SkMatrix fMatrix;
    299     SkPoint fSrc [16];
    300     SkPoint fDst [16];
    301     int fCount;
    302     SkRandom fRandom;
    303     typedef MatrixBench INHERITED;
    304 };
    305 
    306 class ScaleTransDoubleMatrixBench : public MatrixBench {
    307  public:
    308     ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) {
    309         init9(fMatrix);
    310         int i;
    311         for (i = 0; i < SkBENCHLOOP(fCount); i++) {
    312             fSrc[i].fX = fRandom.nextSScalar1();
    313             fSrc[i].fY = fRandom.nextSScalar1();
    314             fDst[i].fX = fRandom.nextSScalar1();
    315             fDst[i].fY = fRandom.nextSScalar1();
    316         }
    317     }
    318  protected:
    319     virtual void performTest() {
    320         SkPoint* dst = fDst;
    321         const SkPoint* src = fSrc;
    322         int count = SkBENCHLOOP(fCount);
    323         // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
    324         float mx = (float) fMatrix[SkMatrix::kMScaleX];
    325         float my = (float) fMatrix[SkMatrix::kMScaleY];
    326         float tx = (float) fMatrix[SkMatrix::kMTransX];
    327         float ty = (float) fMatrix[SkMatrix::kMTransY];
    328         do {
    329             dst->fY = src->fY * my + ty;
    330             dst->fX = src->fX * mx + tx;
    331             src += 1;
    332             dst += 1;
    333         } while (--count);
    334     }
    335  private:
    336     double fMatrix [9];
    337     SkPoint fSrc [16];
    338     SkPoint fDst [16];
    339     int fCount;
    340     SkRandom fRandom;
    341     typedef MatrixBench INHERITED;
    342 };
    343 #endif
    344 
    345 
    346 
    347 
    348 
    349 static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); }
    350 static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); }
    351 static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); }
    352 static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); }
    353 static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); }
    354 static SkBenchmark* M5(void* p) { return new GetTypeMatrixBench(p); }
    355 
    356 static BenchRegistry gReg0(M0);
    357 static BenchRegistry gReg1(M1);
    358 static BenchRegistry gReg2(M2);
    359 static BenchRegistry gReg3(M3);
    360 static BenchRegistry gReg4(M4);
    361 static BenchRegistry gReg5(M5);
    362 
    363 #ifdef SK_SCALAR_IS_FLOAT
    364 static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); }
    365 static SkBenchmark* FlM1(void* p) { return new ScaleTransDoubleMatrixBench(p); }
    366 static BenchRegistry gFlReg5(FlM0);
    367 static BenchRegistry gFlReg6(FlM1);
    368 #endif
    369