blob: 865e6f2abedda3188ff16c95b497d6cba1665cba [file] [log] [blame]
reed@google.com3fb51872011-06-01 15:11:22 +00001#include "SkBenchmark.h"
2#include "SkMatrix.h"
tomhudson@google.com7b4e1072011-06-03 19:16:56 +00003#include "SkRandom.h"
reed@google.com3fb51872011-06-01 15:11:22 +00004#include "SkString.h"
5
6class MatrixBench : public SkBenchmark {
7 SkString fName;
8 enum { N = 100000 };
9public:
10 MatrixBench(void* param, const char name[]) : INHERITED(param) {
11 fName.printf("matrix_%s", name);
12 }
13
14 virtual void performTest() = 0;
15
16protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +000017 virtual int mulLoopCount() const { return 1; }
18
reed@google.com3fb51872011-06-01 15:11:22 +000019 virtual const char* onGetName() {
20 return fName.c_str();
21 }
22
23 virtual void onDraw(SkCanvas* canvas) {
reed@google.comcbefd7d2011-06-06 13:31:30 +000024 int n = N * this->mulLoopCount();
25 for (int i = 0; i < n; i++) {
reed@google.com3fb51872011-06-01 15:11:22 +000026 this->performTest();
27 }
28 }
29
30private:
31 typedef SkBenchmark INHERITED;
32};
33
34// we want to stop the compiler from eliminating code that it thinks is a no-op
35// so we have a non-static global we increment, hoping that will convince the
36// compiler to execute everything
37int gMatrixBench_NonStaticGlobal;
38
39#define always_do(pred) \
40 do { \
41 if (pred) { \
42 ++gMatrixBench_NonStaticGlobal; \
43 } \
44 } while (0)
45
46class EqualsMatrixBench : public MatrixBench {
47public:
48 EqualsMatrixBench(void* param) : INHERITED(param, "equals") {}
49protected:
50 virtual void performTest() {
51 SkMatrix m0, m1, m2;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +000052
reed@google.com3fb51872011-06-01 15:11:22 +000053 m0.reset();
54 m1.reset();
55 m2.reset();
56 always_do(m0 == m1);
57 always_do(m1 == m2);
58 always_do(m2 == m0);
reed@google.com3fb51872011-06-01 15:11:22 +000059 }
60private:
61 typedef MatrixBench INHERITED;
62};
63
64class ScaleMatrixBench : public MatrixBench {
65public:
66 ScaleMatrixBench(void* param) : INHERITED(param, "scale") {
bungeman@google.com20809002011-06-08 19:38:53 +000067 fSX = fSY = SkFloatToScalar(1.5f);
reed@google.com3fb51872011-06-01 15:11:22 +000068 fM0.reset();
69 fM1.setScale(fSX, fSY);
70 fM2.setTranslate(fSX, fSY);
reed@google.com3fb51872011-06-01 15:11:22 +000071 }
72protected:
73 virtual void performTest() {
74 SkMatrix m;
75 m = fM0; m.preScale(fSX, fSY);
76 m = fM1; m.preScale(fSX, fSY);
77 m = fM2; m.preScale(fSX, fSY);
78 }
79private:
80 SkMatrix fM0, fM1, fM2;
81 SkScalar fSX, fSY;
82 typedef MatrixBench INHERITED;
83};
84
reed@google.come0dcde72011-06-06 13:20:29 +000085// having unknown values in our arrays can throw off the timing a lot, perhaps
86// handling NaN values is a lot slower. Anyway, this guy is just meant to put
87// reasonable values in our arrays.
88template <typename T> void init9(T array[9]) {
89 SkRandom rand;
90 for (int i = 0; i < 9; i++) {
91 array[i] = rand.nextSScalar1();
92 }
93}
94
tomhudson@google.com7b4e1072011-06-03 19:16:56 +000095// Test the performance of setConcat() non-perspective case:
96// using floating point precision only.
97class FloatConcatMatrixBench : public MatrixBench {
98public:
reed@google.come0dcde72011-06-06 13:20:29 +000099 FloatConcatMatrixBench(void* p) : INHERITED(p, "concat_floatfloat") {
100 init9(mya);
101 init9(myb);
102 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000103 }
104protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000105 virtual int mulLoopCount() const { return 4; }
106
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000107 static inline void muladdmul(float a, float b, float c, float d,
108 float* result) {
109 *result = a * b + c * d;
110 }
111 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000112 const float* a = mya;
113 const float* b = myb;
114 float* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000115 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
116 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
117 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000118 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000119 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
120 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
121 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000122 r[5] += a[5];
123 r[6] = r[7] = 0.0f;
124 r[8] = 1.0f;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000125 }
126private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000127 float mya [9];
128 float myb [9];
129 float myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000130 typedef MatrixBench INHERITED;
131};
132
133static inline float SkDoubleToFloat(double x) {
134 return static_cast<float>(x);
135}
136
137// Test the performance of setConcat() non-perspective case:
138// using floating point precision but casting up to float for
139// intermediate results during computations.
140class FloatDoubleConcatMatrixBench : public MatrixBench {
141public:
reed@google.come0dcde72011-06-06 13:20:29 +0000142 FloatDoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_floatdouble") {
143 init9(mya);
144 init9(myb);
145 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000146 }
147protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000148 virtual int mulLoopCount() const { return 4; }
149
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000150 static inline void muladdmul(float a, float b, float c, float d,
151 float* result) {
152 *result = SkDoubleToFloat((double)a * b + (double)c * d);
153 }
154 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000155 const float* a = mya;
156 const float* b = myb;
157 float* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000158 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
159 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
160 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000161 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000162 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
163 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
164 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000165 r[5] += a[5];
166 r[6] = r[7] = 0.0f;
167 r[8] = 1.0f;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000168 }
169private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000170 float mya [9];
171 float myb [9];
172 float myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000173 typedef MatrixBench INHERITED;
174};
175
176// Test the performance of setConcat() non-perspective case:
177// using double precision only.
178class DoubleConcatMatrixBench : public MatrixBench {
179public:
reed@google.come0dcde72011-06-06 13:20:29 +0000180 DoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_double") {
181 init9(mya);
182 init9(myb);
183 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000184 }
185protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000186 virtual int mulLoopCount() const { return 4; }
187
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000188 static inline void muladdmul(double a, double b, double c, double d,
189 double* result) {
190 *result = a * b + c * d;
191 }
192 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000193 const double* a = mya;
194 const double* b = myb;
195 double* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000196 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
197 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
198 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000199 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000200 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
201 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
202 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000203 r[5] += a[5];
204 r[6] = r[7] = 0.0;
205 r[8] = 1.0;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000206 }
207private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000208 double mya [9];
209 double myb [9];
210 double myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000211 typedef MatrixBench INHERITED;
212};
213
tomhudson@google.com317d5402011-06-24 18:30:49 +0000214class GetTypeMatrixBench : public MatrixBench {
215public:
216 GetTypeMatrixBench(void* param)
217 : INHERITED(param, "gettype") {
218 fArray[0] = fRnd.nextS();
219 fArray[1] = fRnd.nextS();
220 fArray[2] = fRnd.nextS();
221 fArray[3] = fRnd.nextS();
222 fArray[4] = fRnd.nextS();
223 fArray[5] = fRnd.nextS();
224 fArray[6] = fRnd.nextS();
225 fArray[7] = fRnd.nextS();
226 fArray[8] = fRnd.nextS();
227 }
228protected:
229 // Putting random generation of the matrix inside performTest()
230 // would help us avoid anomalous runs, but takes up 25% or
231 // more of the function time.
232 virtual void performTest() {
233 fMatrix.setAll(fArray[0], fArray[1], fArray[2],
234 fArray[3], fArray[4], fArray[5],
235 fArray[6], fArray[7], fArray[8]);
236 always_do(fMatrix.getType());
237 fMatrix.dirtyMatrixTypeCache();
238 always_do(fMatrix.getType());
239 fMatrix.dirtyMatrixTypeCache();
240 always_do(fMatrix.getType());
241 fMatrix.dirtyMatrixTypeCache();
242 always_do(fMatrix.getType());
243 fMatrix.dirtyMatrixTypeCache();
244 always_do(fMatrix.getType());
245 fMatrix.dirtyMatrixTypeCache();
246 always_do(fMatrix.getType());
247 fMatrix.dirtyMatrixTypeCache();
248 always_do(fMatrix.getType());
249 fMatrix.dirtyMatrixTypeCache();
250 always_do(fMatrix.getType());
251 }
252private:
253 SkMatrix fMatrix;
254 float fArray[9];
255 SkRandom fRnd;
256 typedef MatrixBench INHERITED;
257};
258
tomhudson@google.com288ff332011-06-07 14:31:38 +0000259#ifdef SK_SCALAR_IS_FLOAT
260class ScaleTransMixedMatrixBench : public MatrixBench {
261 public:
262 ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) {
263 fMatrix.setAll(fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
264 fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
265 fRandom.nextS(), fRandom.nextS(), fRandom.nextS());
266 int i;
267 for (i = 0; i < fCount; i++) {
268 fSrc[i].fX = fRandom.nextS();
269 fSrc[i].fY = fRandom.nextS();
270 fDst[i].fX = fRandom.nextS();
271 fDst[i].fY = fRandom.nextS();
272 }
273 }
274 protected:
275 virtual void performTest() {
276 SkPoint* dst = fDst;
277 const SkPoint* src = fSrc;
278 int count = fCount;
279 float mx = fMatrix[SkMatrix::kMScaleX];
280 float my = fMatrix[SkMatrix::kMScaleY];
281 float tx = fMatrix[SkMatrix::kMTransX];
282 float ty = fMatrix[SkMatrix::kMTransY];
283 do {
284 dst->fY = SkScalarMulAdd(src->fY, my, ty);
285 dst->fX = SkScalarMulAdd(src->fX, mx, tx);
286 src += 1;
287 dst += 1;
288 } while (--count);
289 }
290 private:
291 SkMatrix fMatrix;
292 SkPoint fSrc [16];
293 SkPoint fDst [16];
294 int fCount;
295 SkRandom fRandom;
296 typedef MatrixBench INHERITED;
297};
tomhudson@google.com317d5402011-06-24 18:30:49 +0000298>>>>>>> .r1709
tomhudson@google.com288ff332011-06-07 14:31:38 +0000299
300
301class ScaleTransDoubleMatrixBench : public MatrixBench {
302 public:
303 ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) {
304 init9(fMatrix);
305 int i;
306 for (i = 0; i < fCount; i++) {
307 fSrc[i].fX = fRandom.nextS();
308 fSrc[i].fY = fRandom.nextS();
309 fDst[i].fX = fRandom.nextS();
310 fDst[i].fY = fRandom.nextS();
311 }
312 }
313 protected:
314 virtual void performTest() {
315 SkPoint* dst = fDst;
316 const SkPoint* src = fSrc;
317 int count = fCount;
318 // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
319 float mx = fMatrix[SkMatrix::kMScaleX];
320 float my = fMatrix[SkMatrix::kMScaleY];
321 float tx = fMatrix[SkMatrix::kMTransX];
322 float ty = fMatrix[SkMatrix::kMTransY];
323 do {
324 dst->fY = src->fY * my + ty;
325 dst->fX = src->fX * mx + tx;
326 src += 1;
327 dst += 1;
328 } while (--count);
329 }
330 private:
331 double fMatrix [9];
332 SkPoint fSrc [16];
333 SkPoint fDst [16];
334 int fCount;
335 SkRandom fRandom;
336 typedef MatrixBench INHERITED;
337};
338#endif
339
340
341
342
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000343
reed@google.com3fb51872011-06-01 15:11:22 +0000344static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); }
345static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); }
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000346static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); }
347static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); }
348static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); }
tomhudson@google.com317d5402011-06-24 18:30:49 +0000349static SkBenchmark* M5(void* p) { return new GetTypeMatrixBench(p); }
reed@google.com3fb51872011-06-01 15:11:22 +0000350
351static BenchRegistry gReg0(M0);
352static BenchRegistry gReg1(M1);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000353static BenchRegistry gReg2(M2);
354static BenchRegistry gReg3(M3);
355static BenchRegistry gReg4(M4);
tomhudson@google.com317d5402011-06-24 18:30:49 +0000356static BenchRegistry gReg5(M5);
tomhudson@google.com288ff332011-06-07 14:31:38 +0000357
358#ifdef SK_SCALAR_IS_FLOAT
359static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); }
360static SkBenchmark* FlM1(void* p) { return new ScaleTransDoubleMatrixBench(p); }
361static BenchRegistry gFlReg5(FlM0);
362static BenchRegistry gFlReg6(FlM1);
363#endif