Home | History | Annotate | Download | only in bench
      1 #include "SkBenchmark.h"
      2 #include "SkColorPriv.h"
      3 #include "SkMatrix.h"
      4 #include "SkRandom.h"
      5 #include "SkString.h"
      6 #include "SkPaint.h"
      7 
      8 static float sk_fsel(float pred, float result_ge, float result_lt) {
      9     return pred >= 0 ? result_ge : result_lt;
     10 }
     11 
     12 static float fast_floor(float x) {
     13 //    float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23);
     14     float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23));
     15     return (x + big) - big;
     16 }
     17 
     18 class MathBench : public SkBenchmark {
     19     enum {
     20         kBuffer = 100,
     21         kLoop   = 10000
     22     };
     23     SkString    fName;
     24     float       fSrc[kBuffer], fDst[kBuffer];
     25 public:
     26     MathBench(void* param, const char name[]) : INHERITED(param) {
     27         fName.printf("math_%s", name);
     28 
     29         SkRandom rand;
     30         for (int i = 0; i < kBuffer; ++i) {
     31             fSrc[i] = rand.nextSScalar1();
     32         }
     33 
     34         fIsRendering = false;
     35     }
     36 
     37     virtual void performTest(float* SK_RESTRICT dst,
     38                               const float* SK_RESTRICT src,
     39                               int count) = 0;
     40 
     41 protected:
     42     virtual int mulLoopCount() const { return 1; }
     43 
     44     virtual const char* onGetName() {
     45         return fName.c_str();
     46     }
     47 
     48     virtual void onDraw(SkCanvas* canvas) {
     49         int n = SkBENCHLOOP(kLoop * this->mulLoopCount());
     50         for (int i = 0; i < n; i++) {
     51             this->performTest(fDst, fSrc, kBuffer);
     52         }
     53     }
     54 
     55 private:
     56     typedef SkBenchmark INHERITED;
     57 };
     58 
     59 class MathBenchU32 : public MathBench {
     60 public:
     61     MathBenchU32(void* param, const char name[]) : INHERITED(param, name) {}
     62 
     63 protected:
     64     virtual void performITest(uint32_t* SK_RESTRICT dst,
     65                               const uint32_t* SK_RESTRICT src,
     66                               int count) = 0;
     67 
     68     virtual void performTest(float* SK_RESTRICT dst,
     69                               const float* SK_RESTRICT src,
     70                               int count) SK_OVERRIDE {
     71         uint32_t* d = SkTCast<uint32_t*>(dst);
     72         const uint32_t* s = SkTCast<const uint32_t*>(src);
     73         this->performITest(d, s, count);
     74     }
     75 private:
     76     typedef MathBench INHERITED;
     77 };
     78 
     79 ///////////////////////////////////////////////////////////////////////////////
     80 
     81 class NoOpMathBench : public MathBench {
     82 public:
     83     NoOpMathBench(void* param) : INHERITED(param, "noOp") {}
     84 protected:
     85     virtual void performTest(float* SK_RESTRICT dst,
     86                               const float* SK_RESTRICT src,
     87                               int count) {
     88         for (int i = 0; i < count; ++i) {
     89             dst[i] = src[i] + 1;
     90         }
     91     }
     92 private:
     93     typedef MathBench INHERITED;
     94 };
     95 
     96 class SlowISqrtMathBench : public MathBench {
     97 public:
     98     SlowISqrtMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
     99 protected:
    100     virtual void performTest(float* SK_RESTRICT dst,
    101                               const float* SK_RESTRICT src,
    102                               int count) {
    103         for (int i = 0; i < count; ++i) {
    104             dst[i] = 1.0f / sk_float_sqrt(src[i]);
    105         }
    106     }
    107 private:
    108     typedef MathBench INHERITED;
    109 };
    110 
    111 static inline float SkFastInvSqrt(float x) {
    112     float xhalf = 0.5f*x;
    113     int i = *SkTCast<int*>(&x);
    114     i = 0x5f3759df - (i>>1);
    115     x = *SkTCast<float*>(&i);
    116     x = x*(1.5f-xhalf*x*x);
    117 //    x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6
    118     return x;
    119 }
    120 
    121 class FastISqrtMathBench : public MathBench {
    122 public:
    123     FastISqrtMathBench(void* param) : INHERITED(param, "fastIsqrt") {}
    124 protected:
    125     virtual void performTest(float* SK_RESTRICT dst,
    126                               const float* SK_RESTRICT src,
    127                               int count) {
    128         for (int i = 0; i < count; ++i) {
    129             dst[i] = SkFastInvSqrt(src[i]);
    130         }
    131     }
    132 private:
    133     typedef MathBench INHERITED;
    134 };
    135 
    136 static inline uint32_t QMul64(uint32_t value, U8CPU alpha) {
    137     SkASSERT((uint8_t)alpha == alpha);
    138     const uint32_t mask = 0xFF00FF;
    139 
    140     uint64_t tmp = value;
    141     tmp = (tmp & mask) | ((tmp & ~mask) << 24);
    142     tmp *= alpha;
    143     return (uint32_t) (((tmp >> 8) & mask) | ((tmp >> 32) & ~mask));
    144 }
    145 
    146 class QMul64Bench : public MathBenchU32 {
    147 public:
    148     QMul64Bench(void* param) : INHERITED(param, "qmul64") {}
    149 protected:
    150     virtual void performITest(uint32_t* SK_RESTRICT dst,
    151                               const uint32_t* SK_RESTRICT src,
    152                               int count) SK_OVERRIDE {
    153         for (int i = 0; i < count; ++i) {
    154             dst[i] = QMul64(src[i], (uint8_t)i);
    155         }
    156     }
    157 private:
    158     typedef MathBenchU32 INHERITED;
    159 };
    160 
    161 class QMul32Bench : public MathBenchU32 {
    162 public:
    163     QMul32Bench(void* param) : INHERITED(param, "qmul32") {}
    164 protected:
    165     virtual void performITest(uint32_t* SK_RESTRICT dst,
    166                               const uint32_t* SK_RESTRICT src,
    167                               int count) SK_OVERRIDE {
    168         for (int i = 0; i < count; ++i) {
    169             dst[i] = SkAlphaMulQ(src[i], (uint8_t)i);
    170         }
    171     }
    172 private:
    173     typedef MathBenchU32 INHERITED;
    174 };
    175 
    176 ///////////////////////////////////////////////////////////////////////////////
    177 
    178 static bool isFinite_int(float x) {
    179     uint32_t bits = SkFloat2Bits(x);    // need unsigned for our shifts
    180     int exponent = bits << 1 >> 24;
    181     return exponent != 0xFF;
    182 }
    183 
    184 static bool isFinite_float(float x) {
    185     return SkToBool(sk_float_isfinite(x));
    186 }
    187 
    188 static bool isFinite_mulzero(float x) {
    189     float y = x * 0;
    190     return y == y;
    191 }
    192 
    193 static bool isfinite_and_int(const float data[4]) {
    194     return  isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]);
    195 }
    196 
    197 static bool isfinite_and_float(const float data[4]) {
    198     return  isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]);
    199 }
    200 
    201 static bool isfinite_and_mulzero(const float data[4]) {
    202     return  isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]);
    203 }
    204 
    205 #define mulzeroadd(data)    (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0)
    206 
    207 static bool isfinite_plus_int(const float data[4]) {
    208     return  isFinite_int(mulzeroadd(data));
    209 }
    210 
    211 static bool isfinite_plus_float(const float data[4]) {
    212     return  !sk_float_isnan(mulzeroadd(data));
    213 }
    214 
    215 static bool isfinite_plus_mulzero(const float data[4]) {
    216     float x = mulzeroadd(data);
    217     return x == x;
    218 }
    219 
    220 typedef bool (*IsFiniteProc)(const float[]);
    221 
    222 #define MAKEREC(name)   { name, #name }
    223 
    224 static const struct {
    225     IsFiniteProc    fProc;
    226     const char*     fName;
    227 } gRec[] = {
    228     MAKEREC(isfinite_and_int),
    229     MAKEREC(isfinite_and_float),
    230     MAKEREC(isfinite_and_mulzero),
    231     MAKEREC(isfinite_plus_int),
    232     MAKEREC(isfinite_plus_float),
    233     MAKEREC(isfinite_plus_mulzero),
    234 };
    235 
    236 #undef MAKEREC
    237 
    238 static bool isFinite(const SkRect& r) {
    239     // x * 0 will be NaN iff x is infinity or NaN.
    240     // a + b will be NaN iff either a or b is NaN.
    241     float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
    242 
    243     // value is either NaN or it is finite (zero).
    244     // value==value will be true iff value is not NaN
    245     return value == value;
    246 }
    247 
    248 class IsFiniteBench : public SkBenchmark {
    249     enum {
    250         N = SkBENCHLOOP(1000),
    251         NN = SkBENCHLOOP(1000),
    252     };
    253     float fData[N];
    254 public:
    255 
    256     IsFiniteBench(void* param, int index) : INHERITED(param) {
    257         SkRandom rand;
    258 
    259         for (int i = 0; i < N; ++i) {
    260             fData[i] = rand.nextSScalar1();
    261         }
    262 
    263         if (index < 0) {
    264             fProc = NULL;
    265             fName = "isfinite_rect";
    266         } else {
    267             fProc = gRec[index].fProc;
    268             fName = gRec[index].fName;
    269         }
    270         fIsRendering = false;
    271     }
    272 
    273 protected:
    274     virtual void onDraw(SkCanvas* canvas) {
    275         IsFiniteProc proc = fProc;
    276         const float* data = fData;
    277         // do this so the compiler won't throw away the function call
    278         int counter = 0;
    279 
    280         if (proc) {
    281             for (int j = 0; j < NN; ++j) {
    282                 for (int i = 0; i < N - 4; ++i) {
    283                     counter += proc(&data[i]);
    284                 }
    285             }
    286         } else {
    287             for (int j = 0; j < NN; ++j) {
    288                 for (int i = 0; i < N - 4; ++i) {
    289                     const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
    290                     if (false) { // avoid bit rot, suppress warning
    291                         isFinite(*r);
    292                     }
    293                     counter += r->isFinite();
    294                 }
    295             }
    296         }
    297 
    298         SkPaint paint;
    299         if (paint.getAlpha() == 0) {
    300             SkDebugf("%d\n", counter);
    301         }
    302     }
    303 
    304     virtual const char* onGetName() {
    305         return fName;
    306     }
    307 
    308 private:
    309     IsFiniteProc    fProc;
    310     const char*     fName;
    311 
    312     typedef SkBenchmark INHERITED;
    313 };
    314 
    315 class FloorBench : public SkBenchmark {
    316     enum {
    317         ARRAY = SkBENCHLOOP(1000),
    318         LOOP = SkBENCHLOOP(1000),
    319     };
    320     float fData[ARRAY];
    321     bool fFast;
    322 public:
    323 
    324     FloorBench(void* param, bool fast) : INHERITED(param), fFast(fast) {
    325         SkRandom rand;
    326 
    327         for (int i = 0; i < ARRAY; ++i) {
    328             fData[i] = rand.nextSScalar1();
    329         }
    330 
    331         if (fast) {
    332             fName = "floor_fast";
    333         } else {
    334             fName = "floor_std";
    335         }
    336         fIsRendering = false;
    337     }
    338 
    339     virtual void process(float) {}
    340 
    341 protected:
    342     virtual void onDraw(SkCanvas* canvas) {
    343         SkRandom rand;
    344         float accum = 0;
    345         const float* data = fData;
    346 
    347         if (fFast) {
    348             for (int j = 0; j < LOOP; ++j) {
    349                 for (int i = 0; i < ARRAY; ++i) {
    350                     accum += fast_floor(data[i]);
    351                 }
    352                 this->process(accum);
    353             }
    354         } else {
    355             for (int j = 0; j < LOOP; ++j) {
    356                 for (int i = 0; i < ARRAY; ++i) {
    357                     accum += sk_float_floor(data[i]);
    358                 }
    359                 this->process(accum);
    360             }
    361         }
    362     }
    363 
    364     virtual const char* onGetName() {
    365         return fName;
    366     }
    367 
    368 private:
    369     const char*     fName;
    370 
    371     typedef SkBenchmark INHERITED;
    372 };
    373 
    374 ///////////////////////////////////////////////////////////////////////////////
    375 
    376 static SkBenchmark* M0(void* p) { return new NoOpMathBench(p); }
    377 static SkBenchmark* M1(void* p) { return new SlowISqrtMathBench(p); }
    378 static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }
    379 static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
    380 static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
    381 
    382 static SkBenchmark* M5neg1(void* p) { return new IsFiniteBench(p, -1); }
    383 static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
    384 static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
    385 static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
    386 static SkBenchmark* M53(void* p) { return new IsFiniteBench(p, 3); }
    387 static SkBenchmark* M54(void* p) { return new IsFiniteBench(p, 4); }
    388 static SkBenchmark* M55(void* p) { return new IsFiniteBench(p, 5); }
    389 
    390 static SkBenchmark* F0(void* p) { return new FloorBench(p, false); }
    391 static SkBenchmark* F1(void* p) { return new FloorBench(p, true); }
    392 
    393 static BenchRegistry gReg0(M0);
    394 static BenchRegistry gReg1(M1);
    395 static BenchRegistry gReg2(M2);
    396 static BenchRegistry gReg3(M3);
    397 static BenchRegistry gReg4(M4);
    398 
    399 static BenchRegistry gReg5neg1(M5neg1);
    400 static BenchRegistry gReg50(M50);
    401 static BenchRegistry gReg51(M51);
    402 static BenchRegistry gReg52(M52);
    403 static BenchRegistry gReg53(M53);
    404 static BenchRegistry gReg54(M54);
    405 static BenchRegistry gReg55(M55);
    406 
    407 static BenchRegistry gRF0(F0);
    408 static BenchRegistry gRF1(F1);
    409