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 "SkFloatBits.h"
10#include "SkRandom.h"
11#include "SkRect.h"
12#include "SkString.h"
13
14class ScalarBench : public SkBenchmark {
15    SkString    fName;
16    enum { N = 100000 };
17public:
18    ScalarBench(void* param, const char name[]) : INHERITED(param) {
19        fName.printf("scalar_%s", name);
20        fIsRendering = false;
21    }
22
23    virtual void performTest() = 0;
24
25protected:
26    virtual int mulLoopCount() const { return 1; }
27
28    virtual const char* onGetName() SK_OVERRIDE {
29        return fName.c_str();
30    }
31
32    virtual void onDraw(SkCanvas* canvas) {
33        int n = SkBENCHLOOP(N * this->mulLoopCount());
34        for (int i = 0; i < n; i++) {
35            this->performTest();
36        }
37    }
38
39private:
40    typedef SkBenchmark INHERITED;
41};
42
43// we want to stop the compiler from eliminating code that it thinks is a no-op
44// so we have a non-static global we increment, hoping that will convince the
45// compiler to execute everything
46int gScalarBench_NonStaticGlobal;
47
48#define always_do(pred)                     \
49    do {                                    \
50        if (pred) {                         \
51            ++gScalarBench_NonStaticGlobal; \
52        }                                   \
53    } while (0)
54
55// having unknown values in our arrays can throw off the timing a lot, perhaps
56// handling NaN values is a lot slower. Anyway, this guy is just meant to put
57// reasonable values in our arrays.
58template <typename T> void init9(T array[9]) {
59    SkRandom rand;
60    for (int i = 0; i < 9; i++) {
61        array[i] = rand.nextSScalar1();
62    }
63}
64
65class FloatComparisonBench : public ScalarBench {
66public:
67    FloatComparisonBench(void* param) : INHERITED(param, "compare_float") {
68        init9(fArray);
69    }
70protected:
71    virtual int mulLoopCount() const { return 4; }
72    virtual void performTest() {
73        always_do(fArray[6] != 0.0f || fArray[7] != 0.0f || fArray[8] != 1.0f);
74        always_do(fArray[2] != 0.0f || fArray[5] != 0.0f);
75    }
76private:
77    float fArray[9];
78    typedef ScalarBench INHERITED;
79};
80
81class ForcedIntComparisonBench : public ScalarBench {
82public:
83    ForcedIntComparisonBench(void* param)
84    : INHERITED(param, "compare_forced_int") {
85        init9(fArray);
86    }
87protected:
88    virtual int mulLoopCount() const { return 4; }
89    virtual void performTest() {
90        always_do(SkScalarAs2sCompliment(fArray[6]) |
91                  SkScalarAs2sCompliment(fArray[7]) |
92                  (SkScalarAs2sCompliment(fArray[8]) - kPersp1Int));
93        always_do(SkScalarAs2sCompliment(fArray[2]) |
94                  SkScalarAs2sCompliment(fArray[5]));
95    }
96private:
97    static const int32_t kPersp1Int = 0x3f800000;
98    SkScalar fArray[9];
99    typedef ScalarBench INHERITED;
100};
101
102class IsFiniteScalarBench : public ScalarBench {
103public:
104    IsFiniteScalarBench(void* param) : INHERITED(param, "isfinite") {
105        SkRandom rand;
106        for (size_t i = 0; i < ARRAY_N; ++i) {
107            fArray[i] = rand.nextSScalar1();
108        }
109    }
110protected:
111    virtual int mulLoopCount() const { return 1; }
112    virtual void performTest() SK_OVERRIDE {
113        int sum = 0;
114        for (size_t i = 0; i < ARRAY_N; ++i) {
115            // We pass -fArray[i], so the compiler can't cheat and treat the
116            // value as an int (even though we tell it that it is a float)
117            sum += SkScalarIsFinite(-fArray[i]);
118        }
119        // we do this so the compiler won't optimize our loop away...
120        this->doSomething(fArray, sum);
121    }
122
123    virtual void doSomething(SkScalar array[], int sum) {}
124private:
125    enum {
126        ARRAY_N = 64
127    };
128    SkScalar fArray[ARRAY_N];
129
130    typedef ScalarBench INHERITED;
131};
132
133///////////////////////////////////////////////////////////////////////////////
134
135class RectBoundsBench : public SkBenchmark {
136    enum {
137        PTS = 100,
138        N = SkBENCHLOOP(10000)
139    };
140    SkPoint fPts[PTS];
141
142public:
143    RectBoundsBench(void* param) : INHERITED(param) {
144        SkRandom rand;
145        for (int i = 0; i < PTS; ++i) {
146            fPts[i].fX = rand.nextSScalar1();
147            fPts[i].fY = rand.nextSScalar1();
148        }
149        fIsRendering = false;
150    }
151
152protected:
153    virtual const char* onGetName() SK_OVERRIDE {
154        return "rect_bounds";
155    }
156
157    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
158        SkRect r;
159        for (int i = 0; i < N; ++i) {
160            r.set(fPts, PTS);
161        }
162    }
163
164private:
165    typedef SkBenchmark INHERITED;
166};
167
168///////////////////////////////////////////////////////////////////////////////
169
170static SkBenchmark* S0(void* p) { return new FloatComparisonBench(p); }
171static SkBenchmark* S1(void* p) { return new ForcedIntComparisonBench(p); }
172static SkBenchmark* S2(void* p) { return new RectBoundsBench(p); }
173static SkBenchmark* S3(void* p) { return new IsFiniteScalarBench(p); }
174
175static BenchRegistry gReg0(S0);
176static BenchRegistry gReg1(S1);
177static BenchRegistry gReg2(S2);
178static BenchRegistry gReg3(S3);
179