blob: 1644a9e2003d3f0463044a83ea989e5dafd82e21 [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"
6
7class MathBench : public SkBenchmark {
8 enum {
9 kBuffer = 100,
10 kLoop = 10000
11 };
12 SkString fName;
13 float fSrc[kBuffer], fDst[kBuffer];
14public:
15 MathBench(void* param, const char name[]) : INHERITED(param) {
16 fName.printf("math_%s", name);
17
18 SkRandom rand;
19 for (int i = 0; i < kBuffer; ++i) {
20 fSrc[i] = rand.nextSScalar1();
21 }
22 }
23
24 virtual void performTest(float dst[], const float src[], int count) = 0;
25
26protected:
27 virtual int mulLoopCount() const { return 1; }
28
29 virtual const char* onGetName() {
30 return fName.c_str();
31 }
32
33 virtual void onDraw(SkCanvas* canvas) {
tomhudson@google.comca529d32011-10-28 15:34:49 +000034 int n = SkBENCHLOOP(kLoop * this->mulLoopCount());
reed@google.comddc518b2011-08-29 17:49:23 +000035 for (int i = 0; i < n; i++) {
36 this->performTest(fDst, fSrc, kBuffer);
37 }
38 }
39
40private:
41 typedef SkBenchmark INHERITED;
42};
43
reed@google.come05cc8e2011-10-10 14:19:40 +000044class MathBenchU32 : public MathBench {
45public:
46 MathBenchU32(void* param, const char name[]) : INHERITED(param, name) {}
reed@google.comddc518b2011-08-29 17:49:23 +000047
reed@google.come05cc8e2011-10-10 14:19:40 +000048protected:
49 virtual void performITest(uint32_t* dst, const uint32_t* src, int count) = 0;
50
51 virtual void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src,
52 int count) SK_OVERRIDE {
53 uint32_t* d = SkTCast<uint32_t*>(dst);
54 const uint32_t* s = SkTCast<const uint32_t*>(src);
55 this->performITest(d, s, count);
56 }
57private:
58 typedef MathBench INHERITED;
59};
60
61///////////////////////////////////////////////////////////////////////////////
reed@google.comddc518b2011-08-29 17:49:23 +000062
63class NoOpMathBench : public MathBench {
64public:
bungeman@google.com9399cac2011-08-31 19:47:59 +000065 NoOpMathBench(void* param) : INHERITED(param, "noOp") {}
reed@google.comddc518b2011-08-29 17:49:23 +000066protected:
67 virtual void performTest(float dst[], const float src[], int count) {
68 for (int i = 0; i < count; ++i) {
69 dst[i] = src[i] + 1;
70 }
71 }
72private:
73 typedef MathBench INHERITED;
74};
75
76class SlowISqrtMathBench : public MathBench {
77public:
78 SlowISqrtMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
79protected:
80 virtual void performTest(float dst[], const float src[], int count) {
81 for (int i = 0; i < count; ++i) {
82 dst[i] = 1.0f / sk_float_sqrt(src[i]);
83 }
84 }
85private:
86 typedef MathBench INHERITED;
87};
88
89static inline float SkFastInvSqrt(float x) {
90 float xhalf = 0.5f*x;
91 int i = *(int*)&x;
92 i = 0x5f3759df - (i>>1);
93 x = *(float*)&i;
94 x = x*(1.5f-xhalf*x*x);
95// x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6
96 return x;
97}
98
99class FastISqrtMathBench : public MathBench {
100public:
101 FastISqrtMathBench(void* param) : INHERITED(param, "fastIsqrt") {}
102protected:
103 virtual void performTest(float dst[], const float src[], int count) {
104 for (int i = 0; i < count; ++i) {
105 dst[i] = SkFastInvSqrt(src[i]);
106 }
107 }
108private:
109 typedef MathBench INHERITED;
110};
111
reed@google.come05cc8e2011-10-10 14:19:40 +0000112static inline uint32_t QMul64(uint32_t value, U8CPU alpha) {
113 SkASSERT((uint8_t)alpha == alpha);
114 const uint32_t mask = 0xFF00FF;
115
116 uint64_t tmp = value;
117 tmp = (tmp & mask) | ((tmp & ~mask) << 24);
118 tmp *= alpha;
119 return ((tmp >> 8) & mask) | ((tmp >> 32) & ~mask);
120}
121
122class QMul64Bench : public MathBenchU32 {
123public:
124 QMul64Bench(void* param) : INHERITED(param, "qmul64") {}
125protected:
126 virtual void performITest(uint32_t* SK_RESTRICT dst,
127 const uint32_t* SK_RESTRICT src,
128 int count) SK_OVERRIDE {
129 for (int i = 0; i < count; ++i) {
130 dst[i] = QMul64(src[i], (uint8_t)i);
131 }
132 }
133private:
134 typedef MathBenchU32 INHERITED;
135};
136
137class QMul32Bench : public MathBenchU32 {
138public:
139 QMul32Bench(void* param) : INHERITED(param, "qmul32") {}
140protected:
141 virtual void performITest(uint32_t* SK_RESTRICT dst,
142 const uint32_t* SK_RESTRICT src,
143 int count) SK_OVERRIDE {
144 for (int i = 0; i < count; ++i) {
145 dst[i] = SkAlphaMulQ(src[i], (uint8_t)i);
146 }
147 }
148private:
149 typedef MathBenchU32 INHERITED;
150};
151
reed@google.comddc518b2011-08-29 17:49:23 +0000152///////////////////////////////////////////////////////////////////////////////
153
reed@google.com0be5eb72011-12-05 21:53:22 +0000154static bool isFinite_int(float x) {
155 uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
156 int exponent = bits << 1 >> 24;
157 return exponent != 0xFF;
158}
159
160static bool isFinite_float(float x) {
161 return sk_float_isfinite(x);
162}
163
164static bool isFinite_mulzero(float x) {
165 float y = x * 0;
166 return y == y;
167}
168
169static bool isfinite_and_int(const float data[4]) {
170 return isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]);
171}
172
173static bool isfinite_and_float(const float data[4]) {
174 return isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]);
175}
176
177static bool isfinite_and_mulzero(const float data[4]) {
178 return isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]);
179}
180
181#define mulzeroadd(data) (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0)
182
183static bool isfinite_plus_int(const float data[4]) {
184 return isFinite_int(mulzeroadd(data));
185}
186
187static bool isfinite_plus_float(const float data[4]) {
188 return !sk_float_isNaN(mulzeroadd(data));
189}
190
191static bool isfinite_plus_mulzero(const float data[4]) {
192 float x = mulzeroadd(data);
193 return x == x;
194}
195
196typedef bool (*IsFiniteProc)(const float[]);
197
198#define MAKEREC(name) { name, #name }
199
200static const struct {
201 IsFiniteProc fProc;
202 const char* fName;
203} gRec[] = {
204 MAKEREC(isfinite_and_int),
205 MAKEREC(isfinite_and_float),
206 MAKEREC(isfinite_and_mulzero),
207 MAKEREC(isfinite_plus_int),
208 MAKEREC(isfinite_plus_float),
209 MAKEREC(isfinite_plus_mulzero),
210};
211
212#undef MAKEREC
213
214class IsFiniteBench : public SkBenchmark {
215 enum {
216 N = SkBENCHLOOP(1000),
217 NN = SkBENCHLOOP(1000),
218 };
219 float fData[N];
220public:
221
222 IsFiniteBench(void* param, int index) : INHERITED(param) {
223 SkRandom rand;
224
225 for (int i = 0; i < N; ++i) {
226 fData[i] = rand.nextSScalar1();
227 }
228
229 fProc = gRec[index].fProc;
230 fName = gRec[index].fName;
231 }
232
233protected:
234 virtual void onDraw(SkCanvas* canvas) {
235 IsFiniteProc proc = fProc;
236 const float* data = fData;
237
238 for (int j = 0; j < NN; ++j) {
239 for (int i = 0; i < N - 4; ++i) {
240 proc(&data[i]);
241 }
242 }
243 }
244
245 virtual const char* onGetName() {
246 return fName;
247 }
248
249private:
250 IsFiniteProc fProc;
251 const char* fName;
252
253 typedef SkBenchmark INHERITED;
254};
255
256///////////////////////////////////////////////////////////////////////////////
257
reed@google.comddc518b2011-08-29 17:49:23 +0000258static SkBenchmark* M0(void* p) { return new NoOpMathBench(p); }
259static SkBenchmark* M1(void* p) { return new SlowISqrtMathBench(p); }
260static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }
reed@google.come05cc8e2011-10-10 14:19:40 +0000261static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
262static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
reed@google.comddc518b2011-08-29 17:49:23 +0000263
reed@google.com0be5eb72011-12-05 21:53:22 +0000264static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
265static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
266static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
267static SkBenchmark* M53(void* p) { return new IsFiniteBench(p, 3); }
268static SkBenchmark* M54(void* p) { return new IsFiniteBench(p, 4); }
269static SkBenchmark* M55(void* p) { return new IsFiniteBench(p, 5); }
270
reed@google.comddc518b2011-08-29 17:49:23 +0000271static BenchRegistry gReg0(M0);
272static BenchRegistry gReg1(M1);
273static BenchRegistry gReg2(M2);
reed@google.come05cc8e2011-10-10 14:19:40 +0000274static BenchRegistry gReg3(M3);
275static BenchRegistry gReg4(M4);
reed@google.com0be5eb72011-12-05 21:53:22 +0000276
277static BenchRegistry gReg50(M50);
278static BenchRegistry gReg51(M51);
279static BenchRegistry gReg52(M52);
280static BenchRegistry gReg53(M53);
281static BenchRegistry gReg54(M54);
282static BenchRegistry gReg55(M55);