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 "SkMatrix.h" 10#include "SkRandom.h" 11#include "SkString.h" 12 13class MatrixBench : public SkBenchmark { 14 SkString fName; 15 enum { N = 100000 }; 16public: 17 MatrixBench(void* param, const char name[]) : INHERITED(param) { 18 fName.printf("matrix_%s", name); 19 } 20 21 virtual void performTest() = 0; 22 23protected: 24 virtual int mulLoopCount() const { return 1; } 25 26 virtual const char* onGetName() { 27 return fName.c_str(); 28 } 29 30 virtual void onDraw(SkCanvas* canvas) { 31 int n = SkBENCHLOOP(N * this->mulLoopCount()); 32 for (int i = 0; i < n; i++) { 33 this->performTest(); 34 } 35 } 36 37private: 38 typedef SkBenchmark INHERITED; 39}; 40 41// we want to stop the compiler from eliminating code that it thinks is a no-op 42// so we have a non-static global we increment, hoping that will convince the 43// compiler to execute everything 44int gMatrixBench_NonStaticGlobal; 45 46#define always_do(pred) \ 47 do { \ 48 if (pred) { \ 49 ++gMatrixBench_NonStaticGlobal; \ 50 } \ 51 } while (0) 52 53class EqualsMatrixBench : public MatrixBench { 54public: 55 EqualsMatrixBench(void* param) : INHERITED(param, "equals") {} 56protected: 57 virtual void performTest() { 58 SkMatrix m0, m1, m2; 59 60 m0.reset(); 61 m1.reset(); 62 m2.reset(); 63 always_do(m0 == m1); 64 always_do(m1 == m2); 65 always_do(m2 == m0); 66 } 67private: 68 typedef MatrixBench INHERITED; 69}; 70 71class ScaleMatrixBench : public MatrixBench { 72public: 73 ScaleMatrixBench(void* param) : INHERITED(param, "scale") { 74 fSX = fSY = SkFloatToScalar(1.5f); 75 fM0.reset(); 76 fM1.setScale(fSX, fSY); 77 fM2.setTranslate(fSX, fSY); 78 } 79protected: 80 virtual void performTest() { 81 SkMatrix m; 82 m = fM0; m.preScale(fSX, fSY); 83 m = fM1; m.preScale(fSX, fSY); 84 m = fM2; m.preScale(fSX, fSY); 85 } 86private: 87 SkMatrix fM0, fM1, fM2; 88 SkScalar fSX, fSY; 89 typedef MatrixBench INHERITED; 90}; 91 92// having unknown values in our arrays can throw off the timing a lot, perhaps 93// handling NaN values is a lot slower. Anyway, this guy is just meant to put 94// reasonable values in our arrays. 95template <typename T> void init9(T array[9]) { 96 SkRandom rand; 97 for (int i = 0; i < 9; i++) { 98 array[i] = rand.nextSScalar1(); 99 } 100} 101 102// Test the performance of setConcat() non-perspective case: 103// using floating point precision only. 104class FloatConcatMatrixBench : public MatrixBench { 105public: 106 FloatConcatMatrixBench(void* p) : INHERITED(p, "concat_floatfloat") { 107 init9(mya); 108 init9(myb); 109 init9(myr); 110 } 111protected: 112 virtual int mulLoopCount() const { return 4; } 113 114 static inline void muladdmul(float a, float b, float c, float d, 115 float* result) { 116 *result = a * b + c * d; 117 } 118 virtual void performTest() { 119 const float* a = mya; 120 const float* b = myb; 121 float* r = myr; 122 muladdmul(a[0], b[0], a[1], b[3], &r[0]); 123 muladdmul(a[0], b[1], a[1], b[4], &r[1]); 124 muladdmul(a[0], b[2], a[1], b[5], &r[2]); 125 r[2] += a[2]; 126 muladdmul(a[3], b[0], a[4], b[3], &r[3]); 127 muladdmul(a[3], b[1], a[4], b[4], &r[4]); 128 muladdmul(a[3], b[2], a[4], b[5], &r[5]); 129 r[5] += a[5]; 130 r[6] = r[7] = 0.0f; 131 r[8] = 1.0f; 132 } 133private: 134 float mya [9]; 135 float myb [9]; 136 float myr [9]; 137 typedef MatrixBench INHERITED; 138}; 139 140static inline float SkDoubleToFloat(double x) { 141 return static_cast<float>(x); 142} 143 144// Test the performance of setConcat() non-perspective case: 145// using floating point precision but casting up to float for 146// intermediate results during computations. 147class FloatDoubleConcatMatrixBench : public MatrixBench { 148public: 149 FloatDoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_floatdouble") { 150 init9(mya); 151 init9(myb); 152 init9(myr); 153 } 154protected: 155 virtual int mulLoopCount() const { return 4; } 156 157 static inline void muladdmul(float a, float b, float c, float d, 158 float* result) { 159 *result = SkDoubleToFloat((double)a * b + (double)c * d); 160 } 161 virtual void performTest() { 162 const float* a = mya; 163 const float* b = myb; 164 float* r = myr; 165 muladdmul(a[0], b[0], a[1], b[3], &r[0]); 166 muladdmul(a[0], b[1], a[1], b[4], &r[1]); 167 muladdmul(a[0], b[2], a[1], b[5], &r[2]); 168 r[2] += a[2]; 169 muladdmul(a[3], b[0], a[4], b[3], &r[3]); 170 muladdmul(a[3], b[1], a[4], b[4], &r[4]); 171 muladdmul(a[3], b[2], a[4], b[5], &r[5]); 172 r[5] += a[5]; 173 r[6] = r[7] = 0.0f; 174 r[8] = 1.0f; 175 } 176private: 177 float mya [9]; 178 float myb [9]; 179 float myr [9]; 180 typedef MatrixBench INHERITED; 181}; 182 183// Test the performance of setConcat() non-perspective case: 184// using double precision only. 185class DoubleConcatMatrixBench : public MatrixBench { 186public: 187 DoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_double") { 188 init9(mya); 189 init9(myb); 190 init9(myr); 191 } 192protected: 193 virtual int mulLoopCount() const { return 4; } 194 195 static inline void muladdmul(double a, double b, double c, double d, 196 double* result) { 197 *result = a * b + c * d; 198 } 199 virtual void performTest() { 200 const double* a = mya; 201 const double* b = myb; 202 double* r = myr; 203 muladdmul(a[0], b[0], a[1], b[3], &r[0]); 204 muladdmul(a[0], b[1], a[1], b[4], &r[1]); 205 muladdmul(a[0], b[2], a[1], b[5], &r[2]); 206 r[2] += a[2]; 207 muladdmul(a[3], b[0], a[4], b[3], &r[3]); 208 muladdmul(a[3], b[1], a[4], b[4], &r[4]); 209 muladdmul(a[3], b[2], a[4], b[5], &r[5]); 210 r[5] += a[5]; 211 r[6] = r[7] = 0.0; 212 r[8] = 1.0; 213 } 214private: 215 double mya [9]; 216 double myb [9]; 217 double myr [9]; 218 typedef MatrixBench INHERITED; 219}; 220 221class GetTypeMatrixBench : public MatrixBench { 222public: 223 GetTypeMatrixBench(void* param) 224 : INHERITED(param, "gettype") { 225 fArray[0] = (float) fRnd.nextS(); 226 fArray[1] = (float) fRnd.nextS(); 227 fArray[2] = (float) fRnd.nextS(); 228 fArray[3] = (float) fRnd.nextS(); 229 fArray[4] = (float) fRnd.nextS(); 230 fArray[5] = (float) fRnd.nextS(); 231 fArray[6] = (float) fRnd.nextS(); 232 fArray[7] = (float) fRnd.nextS(); 233 fArray[8] = (float) fRnd.nextS(); 234 } 235protected: 236 // Putting random generation of the matrix inside performTest() 237 // would help us avoid anomalous runs, but takes up 25% or 238 // more of the function time. 239 virtual void performTest() { 240 fMatrix.setAll(fArray[0], fArray[1], fArray[2], 241 fArray[3], fArray[4], fArray[5], 242 fArray[6], fArray[7], fArray[8]); 243 always_do(fMatrix.getType()); 244 fMatrix.dirtyMatrixTypeCache(); 245 always_do(fMatrix.getType()); 246 fMatrix.dirtyMatrixTypeCache(); 247 always_do(fMatrix.getType()); 248 fMatrix.dirtyMatrixTypeCache(); 249 always_do(fMatrix.getType()); 250 fMatrix.dirtyMatrixTypeCache(); 251 always_do(fMatrix.getType()); 252 fMatrix.dirtyMatrixTypeCache(); 253 always_do(fMatrix.getType()); 254 fMatrix.dirtyMatrixTypeCache(); 255 always_do(fMatrix.getType()); 256 fMatrix.dirtyMatrixTypeCache(); 257 always_do(fMatrix.getType()); 258 } 259private: 260 SkMatrix fMatrix; 261 float fArray[9]; 262 SkRandom fRnd; 263 typedef MatrixBench INHERITED; 264}; 265 266#ifdef SK_SCALAR_IS_FLOAT 267class ScaleTransMixedMatrixBench : public MatrixBench { 268 public: 269 ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) { 270 fMatrix.setAll(fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(), 271 fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(), 272 fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1()); 273 int i; 274 for (i = 0; i < SkBENCHLOOP(fCount); i++) { 275 fSrc[i].fX = fRandom.nextSScalar1(); 276 fSrc[i].fY = fRandom.nextSScalar1(); 277 fDst[i].fX = fRandom.nextSScalar1(); 278 fDst[i].fY = fRandom.nextSScalar1(); 279 } 280 } 281 protected: 282 virtual void performTest() { 283 SkPoint* dst = fDst; 284 const SkPoint* src = fSrc; 285 int count = SkBENCHLOOP(fCount); 286 float mx = fMatrix[SkMatrix::kMScaleX]; 287 float my = fMatrix[SkMatrix::kMScaleY]; 288 float tx = fMatrix[SkMatrix::kMTransX]; 289 float ty = fMatrix[SkMatrix::kMTransY]; 290 do { 291 dst->fY = SkScalarMulAdd(src->fY, my, ty); 292 dst->fX = SkScalarMulAdd(src->fX, mx, tx); 293 src += 1; 294 dst += 1; 295 } while (--count); 296 } 297 private: 298 SkMatrix fMatrix; 299 SkPoint fSrc [16]; 300 SkPoint fDst [16]; 301 int fCount; 302 SkRandom fRandom; 303 typedef MatrixBench INHERITED; 304}; 305 306class ScaleTransDoubleMatrixBench : public MatrixBench { 307 public: 308 ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) { 309 init9(fMatrix); 310 int i; 311 for (i = 0; i < SkBENCHLOOP(fCount); i++) { 312 fSrc[i].fX = fRandom.nextSScalar1(); 313 fSrc[i].fY = fRandom.nextSScalar1(); 314 fDst[i].fX = fRandom.nextSScalar1(); 315 fDst[i].fY = fRandom.nextSScalar1(); 316 } 317 } 318 protected: 319 virtual void performTest() { 320 SkPoint* dst = fDst; 321 const SkPoint* src = fSrc; 322 int count = SkBENCHLOOP(fCount); 323 // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode 324 float mx = (float) fMatrix[SkMatrix::kMScaleX]; 325 float my = (float) fMatrix[SkMatrix::kMScaleY]; 326 float tx = (float) fMatrix[SkMatrix::kMTransX]; 327 float ty = (float) fMatrix[SkMatrix::kMTransY]; 328 do { 329 dst->fY = src->fY * my + ty; 330 dst->fX = src->fX * mx + tx; 331 src += 1; 332 dst += 1; 333 } while (--count); 334 } 335 private: 336 double fMatrix [9]; 337 SkPoint fSrc [16]; 338 SkPoint fDst [16]; 339 int fCount; 340 SkRandom fRandom; 341 typedef MatrixBench INHERITED; 342}; 343#endif 344 345 346 347 348 349static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); } 350static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); } 351static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); } 352static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); } 353static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); } 354static SkBenchmark* M5(void* p) { return new GetTypeMatrixBench(p); } 355 356static BenchRegistry gReg0(M0); 357static BenchRegistry gReg1(M1); 358static BenchRegistry gReg2(M2); 359static BenchRegistry gReg3(M3); 360static BenchRegistry gReg4(M4); 361static BenchRegistry gReg5(M5); 362 363#ifdef SK_SCALAR_IS_FLOAT 364static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); } 365static SkBenchmark* FlM1(void* p) { return new ScaleTransDoubleMatrixBench(p); } 366static BenchRegistry gFlReg5(FlM0); 367static BenchRegistry gFlReg6(FlM1); 368#endif 369