1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "bench/Benchmark.h"
9cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
10cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
11cb93a386Sopenharmony_ci#include "include/core/SkString.h"
12cb93a386Sopenharmony_ci#include "include/private/SkColorData.h"
13cb93a386Sopenharmony_ci#include "include/private/SkFixed.h"
14cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h"
15cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_cistatic float sk_fsel(float pred, float result_ge, float result_lt) {
18cb93a386Sopenharmony_ci    return pred >= 0 ? result_ge : result_lt;
19cb93a386Sopenharmony_ci}
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_cistatic float fast_floor(float x) {
22cb93a386Sopenharmony_ci//    float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23);
23cb93a386Sopenharmony_ci    float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23));
24cb93a386Sopenharmony_ci    return (x + big) - big;
25cb93a386Sopenharmony_ci}
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciclass MathBench : public Benchmark {
28cb93a386Sopenharmony_ci    enum {
29cb93a386Sopenharmony_ci        kBuffer = 100,
30cb93a386Sopenharmony_ci    };
31cb93a386Sopenharmony_ci    SkString    fName;
32cb93a386Sopenharmony_ci    float       fSrc[kBuffer], fDst[kBuffer];
33cb93a386Sopenharmony_cipublic:
34cb93a386Sopenharmony_ci    MathBench(const char name[])  {
35cb93a386Sopenharmony_ci        fName.printf("math_%s", name);
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ci        SkRandom rand;
38cb93a386Sopenharmony_ci        for (int i = 0; i < kBuffer; ++i) {
39cb93a386Sopenharmony_ci            fSrc[i] = rand.nextSScalar1();
40cb93a386Sopenharmony_ci        }
41cb93a386Sopenharmony_ci    }
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
44cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
45cb93a386Sopenharmony_ci    }
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    virtual void performTest(float* SK_RESTRICT dst,
48cb93a386Sopenharmony_ci                              const float* SK_RESTRICT src,
49cb93a386Sopenharmony_ci                              int count) = 0;
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ciprotected:
52cb93a386Sopenharmony_ci    virtual int mulLoopCount() const { return 1; }
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci    const char* onGetName() override {
55cb93a386Sopenharmony_ci        return fName.c_str();
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
59cb93a386Sopenharmony_ci        int n = loops * this->mulLoopCount();
60cb93a386Sopenharmony_ci        for (int i = 0; i < n; i++) {
61cb93a386Sopenharmony_ci            this->performTest(fDst, fSrc, kBuffer);
62cb93a386Sopenharmony_ci        }
63cb93a386Sopenharmony_ci    }
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ciprivate:
66cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
67cb93a386Sopenharmony_ci};
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ciclass MathBenchU32 : public MathBench {
70cb93a386Sopenharmony_cipublic:
71cb93a386Sopenharmony_ci    MathBenchU32(const char name[]) : INHERITED(name) {}
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ciprotected:
74cb93a386Sopenharmony_ci    virtual void performITest(uint32_t* SK_RESTRICT dst,
75cb93a386Sopenharmony_ci                              const uint32_t* SK_RESTRICT src,
76cb93a386Sopenharmony_ci                              int count) = 0;
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
79cb93a386Sopenharmony_ci        uint32_t* d = reinterpret_cast<uint32_t*>(dst);
80cb93a386Sopenharmony_ci        const uint32_t* s = reinterpret_cast<const uint32_t*>(src);
81cb93a386Sopenharmony_ci        this->performITest(d, s, count);
82cb93a386Sopenharmony_ci    }
83cb93a386Sopenharmony_ciprivate:
84cb93a386Sopenharmony_ci    using INHERITED = MathBench;
85cb93a386Sopenharmony_ci};
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ciclass NoOpMathBench : public MathBench {
90cb93a386Sopenharmony_cipublic:
91cb93a386Sopenharmony_ci    NoOpMathBench() : INHERITED("noOp") {}
92cb93a386Sopenharmony_ciprotected:
93cb93a386Sopenharmony_ci    void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
94cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
95cb93a386Sopenharmony_ci            dst[i] = src[i] + 1;
96cb93a386Sopenharmony_ci        }
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ciprivate:
99cb93a386Sopenharmony_ci    using INHERITED = MathBench;
100cb93a386Sopenharmony_ci};
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ciclass SkRSqrtMathBench : public MathBench {
103cb93a386Sopenharmony_cipublic:
104cb93a386Sopenharmony_ci    SkRSqrtMathBench() : INHERITED("sk_float_rsqrt") {}
105cb93a386Sopenharmony_ciprotected:
106cb93a386Sopenharmony_ci    void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
107cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
108cb93a386Sopenharmony_ci            dst[i] = sk_float_rsqrt(src[i]);
109cb93a386Sopenharmony_ci        }
110cb93a386Sopenharmony_ci    }
111cb93a386Sopenharmony_ciprivate:
112cb93a386Sopenharmony_ci    using INHERITED = MathBench;
113cb93a386Sopenharmony_ci};
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ciclass SlowISqrtMathBench : public MathBench {
117cb93a386Sopenharmony_cipublic:
118cb93a386Sopenharmony_ci    SlowISqrtMathBench() : INHERITED("slowIsqrt") {}
119cb93a386Sopenharmony_ciprotected:
120cb93a386Sopenharmony_ci    void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
121cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
122cb93a386Sopenharmony_ci            dst[i] = 1.0f / sk_float_sqrt(src[i]);
123cb93a386Sopenharmony_ci        }
124cb93a386Sopenharmony_ci    }
125cb93a386Sopenharmony_ciprivate:
126cb93a386Sopenharmony_ci    using INHERITED = MathBench;
127cb93a386Sopenharmony_ci};
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ciclass FastISqrtMathBench : public MathBench {
130cb93a386Sopenharmony_cipublic:
131cb93a386Sopenharmony_ci    FastISqrtMathBench() : INHERITED("fastIsqrt") {}
132cb93a386Sopenharmony_ciprotected:
133cb93a386Sopenharmony_ci    void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
134cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
135cb93a386Sopenharmony_ci            dst[i] = sk_float_rsqrt(src[i]);
136cb93a386Sopenharmony_ci        }
137cb93a386Sopenharmony_ci    }
138cb93a386Sopenharmony_ciprivate:
139cb93a386Sopenharmony_ci    using INHERITED = MathBench;
140cb93a386Sopenharmony_ci};
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_cistatic inline uint32_t QMul64(uint32_t value, U8CPU alpha) {
143cb93a386Sopenharmony_ci    SkASSERT((uint8_t)alpha == alpha);
144cb93a386Sopenharmony_ci    const uint32_t mask = 0xFF00FF;
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    uint64_t tmp = value;
147cb93a386Sopenharmony_ci    tmp = (tmp & mask) | ((tmp & ~mask) << 24);
148cb93a386Sopenharmony_ci    tmp *= alpha;
149cb93a386Sopenharmony_ci    return (uint32_t) (((tmp >> 8) & mask) | ((tmp >> 32) & ~mask));
150cb93a386Sopenharmony_ci}
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ciclass QMul64Bench : public MathBenchU32 {
153cb93a386Sopenharmony_cipublic:
154cb93a386Sopenharmony_ci    QMul64Bench() : INHERITED("qmul64") {}
155cb93a386Sopenharmony_ciprotected:
156cb93a386Sopenharmony_ci    void performITest(uint32_t* SK_RESTRICT dst,
157cb93a386Sopenharmony_ci                      const uint32_t* SK_RESTRICT src,
158cb93a386Sopenharmony_ci                      int count) override {
159cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
160cb93a386Sopenharmony_ci            dst[i] = QMul64(src[i], (uint8_t)i);
161cb93a386Sopenharmony_ci        }
162cb93a386Sopenharmony_ci    }
163cb93a386Sopenharmony_ciprivate:
164cb93a386Sopenharmony_ci    using INHERITED = MathBenchU32;
165cb93a386Sopenharmony_ci};
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ciclass QMul32Bench : public MathBenchU32 {
168cb93a386Sopenharmony_cipublic:
169cb93a386Sopenharmony_ci    QMul32Bench() : INHERITED("qmul32") {}
170cb93a386Sopenharmony_ciprotected:
171cb93a386Sopenharmony_ci    void performITest(uint32_t* SK_RESTRICT dst,
172cb93a386Sopenharmony_ci                      const uint32_t* SK_RESTRICT src,
173cb93a386Sopenharmony_ci                      int count) override {
174cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
175cb93a386Sopenharmony_ci            dst[i] = SkAlphaMulQ(src[i], (uint8_t)i);
176cb93a386Sopenharmony_ci        }
177cb93a386Sopenharmony_ci    }
178cb93a386Sopenharmony_ciprivate:
179cb93a386Sopenharmony_ci    using INHERITED = MathBenchU32;
180cb93a386Sopenharmony_ci};
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_cistatic bool isFinite_int(float x) {
185cb93a386Sopenharmony_ci    uint32_t bits = SkFloat2Bits(x);    // need unsigned for our shifts
186cb93a386Sopenharmony_ci    int exponent = bits << 1 >> 24;
187cb93a386Sopenharmony_ci    return exponent != 0xFF;
188cb93a386Sopenharmony_ci}
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_cistatic bool isFinite_float(float x) {
191cb93a386Sopenharmony_ci    return SkToBool(sk_float_isfinite(x));
192cb93a386Sopenharmony_ci}
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_cistatic bool isFinite_mulzero(float x) {
195cb93a386Sopenharmony_ci    float y = x * 0;
196cb93a386Sopenharmony_ci    return y == y;
197cb93a386Sopenharmony_ci}
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_cistatic bool isfinite_and_int(const float data[4]) {
200cb93a386Sopenharmony_ci    return  isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]);
201cb93a386Sopenharmony_ci}
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_cistatic bool isfinite_and_float(const float data[4]) {
204cb93a386Sopenharmony_ci    return  isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]);
205cb93a386Sopenharmony_ci}
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_cistatic bool isfinite_and_mulzero(const float data[4]) {
208cb93a386Sopenharmony_ci    return  isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]);
209cb93a386Sopenharmony_ci}
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_ci#define mulzeroadd(data)    (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0)
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_cistatic bool isfinite_plus_int(const float data[4]) {
214cb93a386Sopenharmony_ci    return  isFinite_int(mulzeroadd(data));
215cb93a386Sopenharmony_ci}
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_cistatic bool isfinite_plus_float(const float data[4]) {
218cb93a386Sopenharmony_ci    return  !sk_float_isnan(mulzeroadd(data));
219cb93a386Sopenharmony_ci}
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_cistatic bool isfinite_plus_mulzero(const float data[4]) {
222cb93a386Sopenharmony_ci    float x = mulzeroadd(data);
223cb93a386Sopenharmony_ci    return x == x;
224cb93a386Sopenharmony_ci}
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_citypedef bool (*IsFiniteProc)(const float[]);
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci#define MAKEREC(name)   { name, #name }
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_cistatic const struct {
231cb93a386Sopenharmony_ci    IsFiniteProc    fProc;
232cb93a386Sopenharmony_ci    const char*     fName;
233cb93a386Sopenharmony_ci} gRec[] = {
234cb93a386Sopenharmony_ci    MAKEREC(isfinite_and_int),
235cb93a386Sopenharmony_ci    MAKEREC(isfinite_and_float),
236cb93a386Sopenharmony_ci    MAKEREC(isfinite_and_mulzero),
237cb93a386Sopenharmony_ci    MAKEREC(isfinite_plus_int),
238cb93a386Sopenharmony_ci    MAKEREC(isfinite_plus_float),
239cb93a386Sopenharmony_ci    MAKEREC(isfinite_plus_mulzero),
240cb93a386Sopenharmony_ci};
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_ci#undef MAKEREC
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_cistatic bool isFinite(const SkRect& r) {
245cb93a386Sopenharmony_ci    // x * 0 will be NaN iff x is infinity or NaN.
246cb93a386Sopenharmony_ci    // a + b will be NaN iff either a or b is NaN.
247cb93a386Sopenharmony_ci    float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci    // value is either NaN or it is finite (zero).
250cb93a386Sopenharmony_ci    // value==value will be true iff value is not NaN
251cb93a386Sopenharmony_ci    return value == value;
252cb93a386Sopenharmony_ci}
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ciclass IsFiniteBench : public Benchmark {
255cb93a386Sopenharmony_ci    enum {
256cb93a386Sopenharmony_ci        N = 1000,
257cb93a386Sopenharmony_ci    };
258cb93a386Sopenharmony_ci    float fData[N];
259cb93a386Sopenharmony_cipublic:
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ci    IsFiniteBench(int index)  {
262cb93a386Sopenharmony_ci        SkRandom rand;
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
265cb93a386Sopenharmony_ci            fData[i] = rand.nextSScalar1();
266cb93a386Sopenharmony_ci        }
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci        if (index < 0) {
269cb93a386Sopenharmony_ci            fProc = nullptr;
270cb93a386Sopenharmony_ci            fName = "isfinite_rect";
271cb93a386Sopenharmony_ci        } else {
272cb93a386Sopenharmony_ci            fProc = gRec[index].fProc;
273cb93a386Sopenharmony_ci            fName = gRec[index].fName;
274cb93a386Sopenharmony_ci        }
275cb93a386Sopenharmony_ci    }
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
278cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ciprotected:
282cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
283cb93a386Sopenharmony_ci        IsFiniteProc proc = fProc;
284cb93a386Sopenharmony_ci        const float* data = fData;
285cb93a386Sopenharmony_ci        // do this so the compiler won't throw away the function call
286cb93a386Sopenharmony_ci        int counter = 0;
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_ci        if (proc) {
289cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
290cb93a386Sopenharmony_ci                for (int i = 0; i < N - 4; ++i) {
291cb93a386Sopenharmony_ci                    counter += proc(&data[i]);
292cb93a386Sopenharmony_ci                }
293cb93a386Sopenharmony_ci            }
294cb93a386Sopenharmony_ci        } else {
295cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
296cb93a386Sopenharmony_ci                for (int i = 0; i < N - 4; ++i) {
297cb93a386Sopenharmony_ci                    const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
298cb93a386Sopenharmony_ci                    if (false) { // avoid bit rot, suppress warning
299cb93a386Sopenharmony_ci                        isFinite(*r);
300cb93a386Sopenharmony_ci                    }
301cb93a386Sopenharmony_ci                    counter += r->isFinite();
302cb93a386Sopenharmony_ci                }
303cb93a386Sopenharmony_ci            }
304cb93a386Sopenharmony_ci        }
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ci        SkPaint paint;
307cb93a386Sopenharmony_ci        if (paint.getAlpha() == 0) {
308cb93a386Sopenharmony_ci            SkDebugf("%d\n", counter);
309cb93a386Sopenharmony_ci        }
310cb93a386Sopenharmony_ci    }
311cb93a386Sopenharmony_ci
312cb93a386Sopenharmony_ci    const char* onGetName() override {
313cb93a386Sopenharmony_ci        return fName;
314cb93a386Sopenharmony_ci    }
315cb93a386Sopenharmony_ci
316cb93a386Sopenharmony_ciprivate:
317cb93a386Sopenharmony_ci    IsFiniteProc    fProc;
318cb93a386Sopenharmony_ci    const char*     fName;
319cb93a386Sopenharmony_ci
320cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
321cb93a386Sopenharmony_ci};
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ciclass FloorBench : public Benchmark {
324cb93a386Sopenharmony_ci    enum {
325cb93a386Sopenharmony_ci        ARRAY = 1000,
326cb93a386Sopenharmony_ci    };
327cb93a386Sopenharmony_ci    float fData[ARRAY];
328cb93a386Sopenharmony_ci    bool fFast;
329cb93a386Sopenharmony_cipublic:
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ci    FloorBench(bool fast) : fFast(fast) {
332cb93a386Sopenharmony_ci        SkRandom rand;
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ci        for (int i = 0; i < ARRAY; ++i) {
335cb93a386Sopenharmony_ci            fData[i] = rand.nextSScalar1();
336cb93a386Sopenharmony_ci        }
337cb93a386Sopenharmony_ci
338cb93a386Sopenharmony_ci        if (fast) {
339cb93a386Sopenharmony_ci            fName = "floor_fast";
340cb93a386Sopenharmony_ci        } else {
341cb93a386Sopenharmony_ci            fName = "floor_std";
342cb93a386Sopenharmony_ci        }
343cb93a386Sopenharmony_ci    }
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
346cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
347cb93a386Sopenharmony_ci    }
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ci    virtual void process(float) {}
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_ciprotected:
352cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
353cb93a386Sopenharmony_ci        SkRandom rand;
354cb93a386Sopenharmony_ci        float accum = 0;
355cb93a386Sopenharmony_ci        const float* data = fData;
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci        if (fFast) {
358cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
359cb93a386Sopenharmony_ci                for (int i = 0; i < ARRAY; ++i) {
360cb93a386Sopenharmony_ci                    accum += fast_floor(data[i]);
361cb93a386Sopenharmony_ci                }
362cb93a386Sopenharmony_ci                this->process(accum);
363cb93a386Sopenharmony_ci            }
364cb93a386Sopenharmony_ci        } else {
365cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
366cb93a386Sopenharmony_ci                for (int i = 0; i < ARRAY; ++i) {
367cb93a386Sopenharmony_ci                    accum += sk_float_floor(data[i]);
368cb93a386Sopenharmony_ci                }
369cb93a386Sopenharmony_ci                this->process(accum);
370cb93a386Sopenharmony_ci            }
371cb93a386Sopenharmony_ci        }
372cb93a386Sopenharmony_ci    }
373cb93a386Sopenharmony_ci
374cb93a386Sopenharmony_ci    const char* onGetName() override {
375cb93a386Sopenharmony_ci        return fName;
376cb93a386Sopenharmony_ci    }
377cb93a386Sopenharmony_ci
378cb93a386Sopenharmony_ciprivate:
379cb93a386Sopenharmony_ci    const char*     fName;
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
382cb93a386Sopenharmony_ci};
383cb93a386Sopenharmony_ci
384cb93a386Sopenharmony_ciclass CLZBench : public Benchmark {
385cb93a386Sopenharmony_ci    enum {
386cb93a386Sopenharmony_ci        ARRAY = 1000,
387cb93a386Sopenharmony_ci    };
388cb93a386Sopenharmony_ci    uint32_t fData[ARRAY];
389cb93a386Sopenharmony_ci    bool fUsePortable;
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_cipublic:
392cb93a386Sopenharmony_ci    CLZBench(bool usePortable) : fUsePortable(usePortable) {
393cb93a386Sopenharmony_ci
394cb93a386Sopenharmony_ci        SkRandom rand;
395cb93a386Sopenharmony_ci        for (int i = 0; i < ARRAY; ++i) {
396cb93a386Sopenharmony_ci            fData[i] = rand.nextU();
397cb93a386Sopenharmony_ci        }
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci        if (fUsePortable) {
400cb93a386Sopenharmony_ci            fName = "clz_portable";
401cb93a386Sopenharmony_ci        } else {
402cb93a386Sopenharmony_ci            fName = "clz_intrinsic";
403cb93a386Sopenharmony_ci        }
404cb93a386Sopenharmony_ci    }
405cb93a386Sopenharmony_ci
406cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
407cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
408cb93a386Sopenharmony_ci    }
409cb93a386Sopenharmony_ci
410cb93a386Sopenharmony_ci    // just so the compiler doesn't remove our loops
411cb93a386Sopenharmony_ci    virtual void process(int) {}
412cb93a386Sopenharmony_ci
413cb93a386Sopenharmony_ciprotected:
414cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
415cb93a386Sopenharmony_ci        int accum = 0;
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci        if (fUsePortable) {
418cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
419cb93a386Sopenharmony_ci                for (int i = 0; i < ARRAY; ++i) {
420cb93a386Sopenharmony_ci                    accum += SkCLZ_portable(fData[i]);
421cb93a386Sopenharmony_ci                }
422cb93a386Sopenharmony_ci                this->process(accum);
423cb93a386Sopenharmony_ci            }
424cb93a386Sopenharmony_ci        } else {
425cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
426cb93a386Sopenharmony_ci                for (int i = 0; i < ARRAY; ++i) {
427cb93a386Sopenharmony_ci                    accum += SkCLZ(fData[i]);
428cb93a386Sopenharmony_ci                }
429cb93a386Sopenharmony_ci                this->process(accum);
430cb93a386Sopenharmony_ci            }
431cb93a386Sopenharmony_ci        }
432cb93a386Sopenharmony_ci    }
433cb93a386Sopenharmony_ci
434cb93a386Sopenharmony_ci    const char* onGetName() override {
435cb93a386Sopenharmony_ci        return fName;
436cb93a386Sopenharmony_ci    }
437cb93a386Sopenharmony_ci
438cb93a386Sopenharmony_ciprivate:
439cb93a386Sopenharmony_ci    const char* fName;
440cb93a386Sopenharmony_ci
441cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
442cb93a386Sopenharmony_ci};
443cb93a386Sopenharmony_ci
444cb93a386Sopenharmony_ciclass CTZBench : public Benchmark {
445cb93a386Sopenharmony_ci    enum {
446cb93a386Sopenharmony_ci        ARRAY = 1000,
447cb93a386Sopenharmony_ci    };
448cb93a386Sopenharmony_ci    uint32_t fData[ARRAY];
449cb93a386Sopenharmony_ci    bool fUsePortable;
450cb93a386Sopenharmony_ci
451cb93a386Sopenharmony_cipublic:
452cb93a386Sopenharmony_ci    CTZBench(bool usePortable) : fUsePortable(usePortable) {
453cb93a386Sopenharmony_ci
454cb93a386Sopenharmony_ci        SkRandom rand;
455cb93a386Sopenharmony_ci        for (int i = 0; i < ARRAY; ++i) {
456cb93a386Sopenharmony_ci            fData[i] = rand.nextU();
457cb93a386Sopenharmony_ci        }
458cb93a386Sopenharmony_ci
459cb93a386Sopenharmony_ci        if (fUsePortable) {
460cb93a386Sopenharmony_ci            fName = "ctz_portable";
461cb93a386Sopenharmony_ci        } else {
462cb93a386Sopenharmony_ci            fName = "ctz_intrinsic";
463cb93a386Sopenharmony_ci        }
464cb93a386Sopenharmony_ci    }
465cb93a386Sopenharmony_ci
466cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
467cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
468cb93a386Sopenharmony_ci    }
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ci    // just so the compiler doesn't remove our loops
471cb93a386Sopenharmony_ci    virtual void process(int) {}
472cb93a386Sopenharmony_ci
473cb93a386Sopenharmony_ciprotected:
474cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
475cb93a386Sopenharmony_ci        int accum = 0;
476cb93a386Sopenharmony_ci
477cb93a386Sopenharmony_ci        if (fUsePortable) {
478cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
479cb93a386Sopenharmony_ci                for (int i = 0; i < ARRAY; ++i) {
480cb93a386Sopenharmony_ci                    accum += SkCTZ_portable(fData[i]);
481cb93a386Sopenharmony_ci                }
482cb93a386Sopenharmony_ci                this->process(accum);
483cb93a386Sopenharmony_ci            }
484cb93a386Sopenharmony_ci        } else {
485cb93a386Sopenharmony_ci            for (int j = 0; j < loops; ++j) {
486cb93a386Sopenharmony_ci                for (int i = 0; i < ARRAY; ++i) {
487cb93a386Sopenharmony_ci                    accum += SkCTZ(fData[i]);
488cb93a386Sopenharmony_ci                }
489cb93a386Sopenharmony_ci                this->process(accum);
490cb93a386Sopenharmony_ci            }
491cb93a386Sopenharmony_ci        }
492cb93a386Sopenharmony_ci    }
493cb93a386Sopenharmony_ci
494cb93a386Sopenharmony_ci    const char* onGetName() override {
495cb93a386Sopenharmony_ci        return fName;
496cb93a386Sopenharmony_ci    }
497cb93a386Sopenharmony_ci
498cb93a386Sopenharmony_ciprivate:
499cb93a386Sopenharmony_ci    const char* fName;
500cb93a386Sopenharmony_ci
501cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
502cb93a386Sopenharmony_ci};
503cb93a386Sopenharmony_ci
504cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ciclass NormalizeBench : public Benchmark {
507cb93a386Sopenharmony_ci    enum {
508cb93a386Sopenharmony_ci        ARRAY =1000,
509cb93a386Sopenharmony_ci    };
510cb93a386Sopenharmony_ci    SkVector fVec[ARRAY];
511cb93a386Sopenharmony_ci
512cb93a386Sopenharmony_cipublic:
513cb93a386Sopenharmony_ci    NormalizeBench() {
514cb93a386Sopenharmony_ci        SkRandom rand;
515cb93a386Sopenharmony_ci        for (int i = 0; i < ARRAY; ++i) {
516cb93a386Sopenharmony_ci            fVec[i].set(rand.nextSScalar1(), rand.nextSScalar1());
517cb93a386Sopenharmony_ci        }
518cb93a386Sopenharmony_ci
519cb93a386Sopenharmony_ci        fName = "point_normalize";
520cb93a386Sopenharmony_ci    }
521cb93a386Sopenharmony_ci
522cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
523cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
524cb93a386Sopenharmony_ci    }
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci    // just so the compiler doesn't remove our loops
527cb93a386Sopenharmony_ci    virtual void process(int) {}
528cb93a386Sopenharmony_ci
529cb93a386Sopenharmony_ciprotected:
530cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
531cb93a386Sopenharmony_ci        int accum = 0;
532cb93a386Sopenharmony_ci
533cb93a386Sopenharmony_ci        for (int j = 0; j < loops; ++j) {
534cb93a386Sopenharmony_ci            for (int i = 0; i < ARRAY; ++i) {
535cb93a386Sopenharmony_ci                accum += fVec[i].normalize();
536cb93a386Sopenharmony_ci            }
537cb93a386Sopenharmony_ci            this->process(accum);
538cb93a386Sopenharmony_ci        }
539cb93a386Sopenharmony_ci    }
540cb93a386Sopenharmony_ci
541cb93a386Sopenharmony_ci    const char* onGetName() override {
542cb93a386Sopenharmony_ci        return fName;
543cb93a386Sopenharmony_ci    }
544cb93a386Sopenharmony_ci
545cb93a386Sopenharmony_ciprivate:
546cb93a386Sopenharmony_ci    const char* fName;
547cb93a386Sopenharmony_ci
548cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
549cb93a386Sopenharmony_ci};
550cb93a386Sopenharmony_ci
551cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
552cb93a386Sopenharmony_ci
553cb93a386Sopenharmony_ciclass FixedMathBench : public Benchmark {
554cb93a386Sopenharmony_ci    enum {
555cb93a386Sopenharmony_ci        N = 1000,
556cb93a386Sopenharmony_ci    };
557cb93a386Sopenharmony_ci    float fData[N];
558cb93a386Sopenharmony_ci    SkFixed fResult[N];
559cb93a386Sopenharmony_cipublic:
560cb93a386Sopenharmony_ci
561cb93a386Sopenharmony_ci    FixedMathBench()  {
562cb93a386Sopenharmony_ci        SkRandom rand;
563cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
564cb93a386Sopenharmony_ci            fData[i] = rand.nextSScalar1();
565cb93a386Sopenharmony_ci        }
566cb93a386Sopenharmony_ci
567cb93a386Sopenharmony_ci    }
568cb93a386Sopenharmony_ci
569cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
570cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
571cb93a386Sopenharmony_ci    }
572cb93a386Sopenharmony_ci
573cb93a386Sopenharmony_ciprotected:
574cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
575cb93a386Sopenharmony_ci        for (int j = 0; j < loops; ++j) {
576cb93a386Sopenharmony_ci            for (int i = 0; i < N - 4; ++i) {
577cb93a386Sopenharmony_ci                fResult[i] = SkFloatToFixed(fData[i]);
578cb93a386Sopenharmony_ci            }
579cb93a386Sopenharmony_ci        }
580cb93a386Sopenharmony_ci
581cb93a386Sopenharmony_ci        SkPaint paint;
582cb93a386Sopenharmony_ci        if (paint.getAlpha() == 0) {
583cb93a386Sopenharmony_ci            SkDebugf("%d\n", fResult[0]);
584cb93a386Sopenharmony_ci        }
585cb93a386Sopenharmony_ci    }
586cb93a386Sopenharmony_ci
587cb93a386Sopenharmony_ci    const char* onGetName() override {
588cb93a386Sopenharmony_ci        return "float_to_fixed";
589cb93a386Sopenharmony_ci    }
590cb93a386Sopenharmony_ci
591cb93a386Sopenharmony_ciprivate:
592cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
593cb93a386Sopenharmony_ci};
594cb93a386Sopenharmony_ci
595cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
596cb93a386Sopenharmony_ci
597cb93a386Sopenharmony_citemplate <typename T>
598cb93a386Sopenharmony_ciclass DivModBench : public Benchmark {
599cb93a386Sopenharmony_ci    SkString fName;
600cb93a386Sopenharmony_cipublic:
601cb93a386Sopenharmony_ci    explicit DivModBench(const char* name) {
602cb93a386Sopenharmony_ci        fName.printf("divmod_%s", name);
603cb93a386Sopenharmony_ci    }
604cb93a386Sopenharmony_ci
605cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
606cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
607cb93a386Sopenharmony_ci    }
608cb93a386Sopenharmony_ci
609cb93a386Sopenharmony_ciprotected:
610cb93a386Sopenharmony_ci    const char* onGetName() override {
611cb93a386Sopenharmony_ci        return fName.c_str();
612cb93a386Sopenharmony_ci    }
613cb93a386Sopenharmony_ci
614cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
615cb93a386Sopenharmony_ci        volatile T a = 0, b = 0;
616cb93a386Sopenharmony_ci        T div = 0, mod = 0;
617cb93a386Sopenharmony_ci        for (int i = 0; i < loops; i++) {
618cb93a386Sopenharmony_ci            if ((T)i == 0) continue;  // Small T will wrap around.
619cb93a386Sopenharmony_ci            SkTDivMod((T)(i+1), (T)i, &div, &mod);
620cb93a386Sopenharmony_ci            a ^= div;
621cb93a386Sopenharmony_ci            b ^= mod;
622cb93a386Sopenharmony_ci        }
623cb93a386Sopenharmony_ci    }
624cb93a386Sopenharmony_ci};
625cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<uint8_t>("uint8_t"))
626cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<uint16_t>("uint16_t"))
627cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<uint32_t>("uint32_t"))
628cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<uint64_t>("uint64_t"))
629cb93a386Sopenharmony_ci
630cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<int8_t>("int8_t"))
631cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<int16_t>("int16_t"))
632cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<int32_t>("int32_t"))
633cb93a386Sopenharmony_ciDEF_BENCH(return new DivModBench<int64_t>("int64_t"))
634cb93a386Sopenharmony_ci
635cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
636cb93a386Sopenharmony_ci
637cb93a386Sopenharmony_ciDEF_BENCH( return new NoOpMathBench(); )
638cb93a386Sopenharmony_ciDEF_BENCH( return new SkRSqrtMathBench(); )
639cb93a386Sopenharmony_ciDEF_BENCH( return new SlowISqrtMathBench(); )
640cb93a386Sopenharmony_ciDEF_BENCH( return new FastISqrtMathBench(); )
641cb93a386Sopenharmony_ciDEF_BENCH( return new QMul64Bench(); )
642cb93a386Sopenharmony_ciDEF_BENCH( return new QMul32Bench(); )
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_ciDEF_BENCH( return new IsFiniteBench(-1); )
645cb93a386Sopenharmony_ciDEF_BENCH( return new IsFiniteBench(0); )
646cb93a386Sopenharmony_ciDEF_BENCH( return new IsFiniteBench(1); )
647cb93a386Sopenharmony_ciDEF_BENCH( return new IsFiniteBench(2); )
648cb93a386Sopenharmony_ciDEF_BENCH( return new IsFiniteBench(3); )
649cb93a386Sopenharmony_ciDEF_BENCH( return new IsFiniteBench(4); )
650cb93a386Sopenharmony_ciDEF_BENCH( return new IsFiniteBench(5); )
651cb93a386Sopenharmony_ci
652cb93a386Sopenharmony_ciDEF_BENCH( return new FloorBench(false); )
653cb93a386Sopenharmony_ciDEF_BENCH( return new FloorBench(true); )
654cb93a386Sopenharmony_ci
655cb93a386Sopenharmony_ciDEF_BENCH( return new CLZBench(false); )
656cb93a386Sopenharmony_ciDEF_BENCH( return new CLZBench(true); )
657cb93a386Sopenharmony_ciDEF_BENCH( return new CTZBench(false); )
658cb93a386Sopenharmony_ciDEF_BENCH( return new CTZBench(true); )
659cb93a386Sopenharmony_ci
660cb93a386Sopenharmony_ciDEF_BENCH( return new NormalizeBench(); )
661cb93a386Sopenharmony_ci
662cb93a386Sopenharmony_ciDEF_BENCH( return new FixedMathBench(); )
663cb93a386Sopenharmony_ci
664cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////
665cb93a386Sopenharmony_ci
666cb93a386Sopenharmony_ci#include "include/private/SkFloatBits.h"
667cb93a386Sopenharmony_ciclass Floor2IntBench : public Benchmark {
668cb93a386Sopenharmony_ci    enum {
669cb93a386Sopenharmony_ci        ARRAY = 1000,
670cb93a386Sopenharmony_ci    };
671cb93a386Sopenharmony_ci    float fData[ARRAY];
672cb93a386Sopenharmony_ci    const bool fSat;
673cb93a386Sopenharmony_cipublic:
674cb93a386Sopenharmony_ci
675cb93a386Sopenharmony_ci    Floor2IntBench(bool sat) : fSat(sat) {
676cb93a386Sopenharmony_ci        SkRandom rand;
677cb93a386Sopenharmony_ci
678cb93a386Sopenharmony_ci        for (int i = 0; i < ARRAY; ++i) {
679cb93a386Sopenharmony_ci            fData[i] = SkBits2Float(rand.nextU());
680cb93a386Sopenharmony_ci        }
681cb93a386Sopenharmony_ci
682cb93a386Sopenharmony_ci        if (sat) {
683cb93a386Sopenharmony_ci            fName = "floor2int_sat";
684cb93a386Sopenharmony_ci        } else {
685cb93a386Sopenharmony_ci            fName = "floor2int_undef";
686cb93a386Sopenharmony_ci        }
687cb93a386Sopenharmony_ci    }
688cb93a386Sopenharmony_ci
689cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
690cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
691cb93a386Sopenharmony_ci    }
692cb93a386Sopenharmony_ci
693cb93a386Sopenharmony_ci    // These exist to try to stop the compiler from detecting what we doing, and throwing
694cb93a386Sopenharmony_ci    // parts away (or knowing exactly how big the loop counts are).
695cb93a386Sopenharmony_ci    virtual void process(unsigned) {}
696cb93a386Sopenharmony_ci    virtual int count() { return ARRAY; }
697cb93a386Sopenharmony_ci
698cb93a386Sopenharmony_ciprotected:
699cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
700cb93a386Sopenharmony_ci        // used unsigned to avoid undefined behavior if/when the += might overflow
701cb93a386Sopenharmony_ci        unsigned accum = 0;
702cb93a386Sopenharmony_ci
703cb93a386Sopenharmony_ci        for (int j = 0; j < loops; ++j) {
704cb93a386Sopenharmony_ci            int n = this->count();
705cb93a386Sopenharmony_ci            if (fSat) {
706cb93a386Sopenharmony_ci                for (int i = 0; i < n; ++i) {
707cb93a386Sopenharmony_ci                    accum += sk_float_floor2int(fData[i]);
708cb93a386Sopenharmony_ci                }
709cb93a386Sopenharmony_ci            } else {
710cb93a386Sopenharmony_ci                for (int i = 0; i < n; ++i) {
711cb93a386Sopenharmony_ci                    accum += sk_float_floor2int_no_saturate(fData[i]);
712cb93a386Sopenharmony_ci                }
713cb93a386Sopenharmony_ci            }
714cb93a386Sopenharmony_ci            this->process(accum);
715cb93a386Sopenharmony_ci        }
716cb93a386Sopenharmony_ci    }
717cb93a386Sopenharmony_ci
718cb93a386Sopenharmony_ci    const char* onGetName() override { return fName; }
719cb93a386Sopenharmony_ci
720cb93a386Sopenharmony_ciprivate:
721cb93a386Sopenharmony_ci    const char* fName;
722cb93a386Sopenharmony_ci
723cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
724cb93a386Sopenharmony_ci};
725cb93a386Sopenharmony_ciDEF_BENCH( return new Floor2IntBench(false); )
726cb93a386Sopenharmony_ciDEF_BENCH( return new Floor2IntBench(true); )
727cb93a386Sopenharmony_ci
728