blob: 61ac26bbb677546e959fe968110f1dd3dda805c3 [file] [log] [blame]
reed@google.comddc518b2011-08-29 17:49:23 +00001#include "SkBenchmark.h"
reed@google.come05cc8e2011-10-10 14:19:40 +00002#include "SkColorPriv.h"
reed@google.comddc518b2011-08-29 17:49:23 +00003#include "SkMatrix.h"
4#include "SkRandom.h"
5#include "SkString.h"
reed@google.com16078632011-12-06 18:56:37 +00006#include "SkPaint.h"
reed@google.comddc518b2011-08-29 17:49:23 +00007
8class MathBench : public SkBenchmark {
9 enum {
10 kBuffer = 100,
11 kLoop = 10000
12 };
13 SkString fName;
14 float fSrc[kBuffer], fDst[kBuffer];
15public:
16 MathBench(void* param, const char name[]) : INHERITED(param) {
17 fName.printf("math_%s", name);
18
19 SkRandom rand;
20 for (int i = 0; i < kBuffer; ++i) {
21 fSrc[i] = rand.nextSScalar1();
22 }
23 }
24
robertphillips@google.com6853e802012-04-16 15:50:18 +000025 virtual void performTest(float* SK_RESTRICT dst,
26 const float* SK_RESTRICT src,
27 int count) = 0;
reed@google.comddc518b2011-08-29 17:49:23 +000028
29protected:
30 virtual int mulLoopCount() const { return 1; }
31
32 virtual const char* onGetName() {
33 return fName.c_str();
34 }
35
36 virtual void onDraw(SkCanvas* canvas) {
tomhudson@google.comca529d32011-10-28 15:34:49 +000037 int n = SkBENCHLOOP(kLoop * this->mulLoopCount());
reed@google.comddc518b2011-08-29 17:49:23 +000038 for (int i = 0; i < n; i++) {
39 this->performTest(fDst, fSrc, kBuffer);
40 }
41 }
42
43private:
44 typedef SkBenchmark INHERITED;
45};
46
reed@google.come05cc8e2011-10-10 14:19:40 +000047class MathBenchU32 : public MathBench {
48public:
49 MathBenchU32(void* param, const char name[]) : INHERITED(param, name) {}
reed@google.comddc518b2011-08-29 17:49:23 +000050
reed@google.come05cc8e2011-10-10 14:19:40 +000051protected:
robertphillips@google.com6853e802012-04-16 15:50:18 +000052 virtual void performITest(uint32_t* SK_RESTRICT dst,
53 const uint32_t* SK_RESTRICT src,
54 int count) = 0;
reed@google.come05cc8e2011-10-10 14:19:40 +000055
robertphillips@google.com6853e802012-04-16 15:50:18 +000056 virtual void performTest(float* SK_RESTRICT dst,
57 const float* SK_RESTRICT src,
58 int count) SK_OVERRIDE {
reed@google.come05cc8e2011-10-10 14:19:40 +000059 uint32_t* d = SkTCast<uint32_t*>(dst);
60 const uint32_t* s = SkTCast<const uint32_t*>(src);
61 this->performITest(d, s, count);
62 }
63private:
64 typedef MathBench INHERITED;
65};
66
67///////////////////////////////////////////////////////////////////////////////
reed@google.comddc518b2011-08-29 17:49:23 +000068
69class NoOpMathBench : public MathBench {
70public:
bungeman@google.com9399cac2011-08-31 19:47:59 +000071 NoOpMathBench(void* param) : INHERITED(param, "noOp") {}
reed@google.comddc518b2011-08-29 17:49:23 +000072protected:
robertphillips@google.com6853e802012-04-16 15:50:18 +000073 virtual void performTest(float* SK_RESTRICT dst,
74 const float* SK_RESTRICT src,
75 int count) {
reed@google.comddc518b2011-08-29 17:49:23 +000076 for (int i = 0; i < count; ++i) {
77 dst[i] = src[i] + 1;
78 }
79 }
80private:
81 typedef MathBench INHERITED;
82};
83
84class SlowISqrtMathBench : public MathBench {
85public:
86 SlowISqrtMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
87protected:
robertphillips@google.com6853e802012-04-16 15:50:18 +000088 virtual void performTest(float* SK_RESTRICT dst,
89 const float* SK_RESTRICT src,
90 int count) {
reed@google.comddc518b2011-08-29 17:49:23 +000091 for (int i = 0; i < count; ++i) {
92 dst[i] = 1.0f / sk_float_sqrt(src[i]);
93 }
94 }
95private:
96 typedef MathBench INHERITED;
97};
98
99static inline float SkFastInvSqrt(float x) {
100 float xhalf = 0.5f*x;
101 int i = *(int*)&x;
102 i = 0x5f3759df - (i>>1);
103 x = *(float*)&i;
104 x = x*(1.5f-xhalf*x*x);
105// x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6
106 return x;
107}
108
109class FastISqrtMathBench : public MathBench {
110public:
111 FastISqrtMathBench(void* param) : INHERITED(param, "fastIsqrt") {}
112protected:
robertphillips@google.com6853e802012-04-16 15:50:18 +0000113 virtual void performTest(float* SK_RESTRICT dst,
114 const float* SK_RESTRICT src,
115 int count) {
reed@google.comddc518b2011-08-29 17:49:23 +0000116 for (int i = 0; i < count; ++i) {
117 dst[i] = SkFastInvSqrt(src[i]);
118 }
119 }
120private:
121 typedef MathBench INHERITED;
122};
123
reed@google.come05cc8e2011-10-10 14:19:40 +0000124static inline uint32_t QMul64(uint32_t value, U8CPU alpha) {
125 SkASSERT((uint8_t)alpha == alpha);
126 const uint32_t mask = 0xFF00FF;
127
128 uint64_t tmp = value;
129 tmp = (tmp & mask) | ((tmp & ~mask) << 24);
130 tmp *= alpha;
131 return ((tmp >> 8) & mask) | ((tmp >> 32) & ~mask);
132}
133
134class QMul64Bench : public MathBenchU32 {
135public:
136 QMul64Bench(void* param) : INHERITED(param, "qmul64") {}
137protected:
138 virtual void performITest(uint32_t* SK_RESTRICT dst,
139 const uint32_t* SK_RESTRICT src,
140 int count) SK_OVERRIDE {
141 for (int i = 0; i < count; ++i) {
142 dst[i] = QMul64(src[i], (uint8_t)i);
143 }
144 }
145private:
146 typedef MathBenchU32 INHERITED;
147};
148
149class QMul32Bench : public MathBenchU32 {
150public:
151 QMul32Bench(void* param) : INHERITED(param, "qmul32") {}
152protected:
153 virtual void performITest(uint32_t* SK_RESTRICT dst,
154 const uint32_t* SK_RESTRICT src,
155 int count) SK_OVERRIDE {
156 for (int i = 0; i < count; ++i) {
157 dst[i] = SkAlphaMulQ(src[i], (uint8_t)i);
158 }
159 }
160private:
161 typedef MathBenchU32 INHERITED;
162};
163
reed@google.comddc518b2011-08-29 17:49:23 +0000164///////////////////////////////////////////////////////////////////////////////
165
reed@google.com0be5eb72011-12-05 21:53:22 +0000166static bool isFinite_int(float x) {
167 uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
168 int exponent = bits << 1 >> 24;
169 return exponent != 0xFF;
170}
171
172static bool isFinite_float(float x) {
robertphillips@google.com6853e802012-04-16 15:50:18 +0000173 return SkToBool(sk_float_isfinite(x));
reed@google.com0be5eb72011-12-05 21:53:22 +0000174}
175
176static bool isFinite_mulzero(float x) {
177 float y = x * 0;
178 return y == y;
179}
180
181static bool isfinite_and_int(const float data[4]) {
182 return isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]);
183}
184
185static bool isfinite_and_float(const float data[4]) {
186 return isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]);
187}
188
189static bool isfinite_and_mulzero(const float data[4]) {
190 return isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]);
191}
192
193#define mulzeroadd(data) (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0)
194
195static bool isfinite_plus_int(const float data[4]) {
196 return isFinite_int(mulzeroadd(data));
197}
198
199static bool isfinite_plus_float(const float data[4]) {
reed@google.com5ae777d2011-12-06 20:18:05 +0000200 return !sk_float_isnan(mulzeroadd(data));
reed@google.com0be5eb72011-12-05 21:53:22 +0000201}
202
203static bool isfinite_plus_mulzero(const float data[4]) {
204 float x = mulzeroadd(data);
205 return x == x;
206}
207
208typedef bool (*IsFiniteProc)(const float[]);
209
210#define MAKEREC(name) { name, #name }
211
212static const struct {
213 IsFiniteProc fProc;
214 const char* fName;
215} gRec[] = {
216 MAKEREC(isfinite_and_int),
217 MAKEREC(isfinite_and_float),
218 MAKEREC(isfinite_and_mulzero),
219 MAKEREC(isfinite_plus_int),
220 MAKEREC(isfinite_plus_float),
221 MAKEREC(isfinite_plus_mulzero),
222};
223
224#undef MAKEREC
225
reed@google.com16078632011-12-06 18:56:37 +0000226static bool isFinite(const SkRect& r) {
227 // x * 0 will be NaN iff x is infinity or NaN.
228 // a + b will be NaN iff either a or b is NaN.
229 float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
230
231 // value is either NaN or it is finite (zero).
232 // value==value will be true iff value is not NaN
233 return value == value;
234}
235
reed@google.com0be5eb72011-12-05 21:53:22 +0000236class IsFiniteBench : public SkBenchmark {
237 enum {
238 N = SkBENCHLOOP(1000),
239 NN = SkBENCHLOOP(1000),
240 };
241 float fData[N];
242public:
243
244 IsFiniteBench(void* param, int index) : INHERITED(param) {
245 SkRandom rand;
246
247 for (int i = 0; i < N; ++i) {
248 fData[i] = rand.nextSScalar1();
249 }
reed@google.com16078632011-12-06 18:56:37 +0000250
251 if (index < 0) {
252 fProc = NULL;
253 fName = "isfinite_rect";
254 } else {
255 fProc = gRec[index].fProc;
256 fName = gRec[index].fName;
257 }
reed@google.com0be5eb72011-12-05 21:53:22 +0000258 }
259
260protected:
261 virtual void onDraw(SkCanvas* canvas) {
262 IsFiniteProc proc = fProc;
263 const float* data = fData;
reed@google.com16078632011-12-06 18:56:37 +0000264 // do this so the compiler won't throw away the function call
265 int counter = 0;
reed@google.com0be5eb72011-12-05 21:53:22 +0000266
reed@google.com16078632011-12-06 18:56:37 +0000267 if (proc) {
268 for (int j = 0; j < NN; ++j) {
269 for (int i = 0; i < N - 4; ++i) {
270 counter += proc(&data[i]);
271 }
reed@google.com0be5eb72011-12-05 21:53:22 +0000272 }
reed@google.com16078632011-12-06 18:56:37 +0000273 } else {
274 for (int j = 0; j < NN; ++j) {
275 for (int i = 0; i < N - 4; ++i) {
276 const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
277 counter += r->isFinite();
278 }
279 }
280 }
281
282 SkPaint paint;
283 if (paint.getAlpha() == 0) {
284 SkDebugf("%d\n", counter);
reed@google.com0be5eb72011-12-05 21:53:22 +0000285 }
286 }
287
288 virtual const char* onGetName() {
289 return fName;
290 }
291
292private:
293 IsFiniteProc fProc;
294 const char* fName;
295
296 typedef SkBenchmark INHERITED;
297};
298
299///////////////////////////////////////////////////////////////////////////////
300
reed@google.comddc518b2011-08-29 17:49:23 +0000301static SkBenchmark* M0(void* p) { return new NoOpMathBench(p); }
302static SkBenchmark* M1(void* p) { return new SlowISqrtMathBench(p); }
303static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }
reed@google.come05cc8e2011-10-10 14:19:40 +0000304static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
305static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
reed@google.comddc518b2011-08-29 17:49:23 +0000306
reed@google.com16078632011-12-06 18:56:37 +0000307static SkBenchmark* M5neg1(void* p) { return new IsFiniteBench(p, -1); }
reed@google.com0be5eb72011-12-05 21:53:22 +0000308static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
309static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
310static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
311static SkBenchmark* M53(void* p) { return new IsFiniteBench(p, 3); }
312static SkBenchmark* M54(void* p) { return new IsFiniteBench(p, 4); }
313static SkBenchmark* M55(void* p) { return new IsFiniteBench(p, 5); }
314
reed@google.comddc518b2011-08-29 17:49:23 +0000315static BenchRegistry gReg0(M0);
316static BenchRegistry gReg1(M1);
317static BenchRegistry gReg2(M2);
reed@google.come05cc8e2011-10-10 14:19:40 +0000318static BenchRegistry gReg3(M3);
319static BenchRegistry gReg4(M4);
reed@google.com0be5eb72011-12-05 21:53:22 +0000320
reed@google.com16078632011-12-06 18:56:37 +0000321static BenchRegistry gReg5neg1(M5neg1);
reed@google.com0be5eb72011-12-05 21:53:22 +0000322static BenchRegistry gReg50(M50);
323static BenchRegistry gReg51(M51);
324static BenchRegistry gReg52(M52);
325static BenchRegistry gReg53(M53);
326static BenchRegistry gReg54(M54);
327static BenchRegistry gReg55(M55);