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