123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- /*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "bench/Benchmark.h"
- #include "include/core/SkMatrix.h"
- #include "include/core/SkPaint.h"
- #include "include/core/SkString.h"
- #include "include/private/SkColorData.h"
- #include "include/private/SkFixed.h"
- #include "include/utils/SkRandom.h"
- #include "src/core/SkMathPriv.h"
- static float sk_fsel(float pred, float result_ge, float result_lt) {
- return pred >= 0 ? result_ge : result_lt;
- }
- static float fast_floor(float x) {
- // float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23);
- float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23));
- return (x + big) - big;
- }
- class MathBench : public Benchmark {
- enum {
- kBuffer = 100,
- };
- SkString fName;
- float fSrc[kBuffer], fDst[kBuffer];
- public:
- MathBench(const char name[]) {
- fName.printf("math_%s", name);
- SkRandom rand;
- for (int i = 0; i < kBuffer; ++i) {
- fSrc[i] = rand.nextSScalar1();
- }
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- virtual void performTest(float* SK_RESTRICT dst,
- const float* SK_RESTRICT src,
- int count) = 0;
- protected:
- virtual int mulLoopCount() const { return 1; }
- const char* onGetName() override {
- return fName.c_str();
- }
- void onDraw(int loops, SkCanvas*) override {
- int n = loops * this->mulLoopCount();
- for (int i = 0; i < n; i++) {
- this->performTest(fDst, fSrc, kBuffer);
- }
- }
- private:
- typedef Benchmark INHERITED;
- };
- class MathBenchU32 : public MathBench {
- public:
- MathBenchU32(const char name[]) : INHERITED(name) {}
- protected:
- virtual void performITest(uint32_t* SK_RESTRICT dst,
- const uint32_t* SK_RESTRICT src,
- int count) = 0;
- void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
- uint32_t* d = reinterpret_cast<uint32_t*>(dst);
- const uint32_t* s = reinterpret_cast<const uint32_t*>(src);
- this->performITest(d, s, count);
- }
- private:
- typedef MathBench INHERITED;
- };
- ///////////////////////////////////////////////////////////////////////////////
- class NoOpMathBench : public MathBench {
- public:
- NoOpMathBench() : INHERITED("noOp") {}
- protected:
- void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
- for (int i = 0; i < count; ++i) {
- dst[i] = src[i] + 1;
- }
- }
- private:
- typedef MathBench INHERITED;
- };
- class SkRSqrtMathBench : public MathBench {
- public:
- SkRSqrtMathBench() : INHERITED("sk_float_rsqrt") {}
- protected:
- void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
- for (int i = 0; i < count; ++i) {
- dst[i] = sk_float_rsqrt(src[i]);
- }
- }
- private:
- typedef MathBench INHERITED;
- };
- class SlowISqrtMathBench : public MathBench {
- public:
- SlowISqrtMathBench() : INHERITED("slowIsqrt") {}
- protected:
- void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
- for (int i = 0; i < count; ++i) {
- dst[i] = 1.0f / sk_float_sqrt(src[i]);
- }
- }
- private:
- typedef MathBench INHERITED;
- };
- class FastISqrtMathBench : public MathBench {
- public:
- FastISqrtMathBench() : INHERITED("fastIsqrt") {}
- protected:
- void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src, int count) override {
- for (int i = 0; i < count; ++i) {
- dst[i] = sk_float_rsqrt(src[i]);
- }
- }
- private:
- typedef MathBench INHERITED;
- };
- static inline uint32_t QMul64(uint32_t value, U8CPU alpha) {
- SkASSERT((uint8_t)alpha == alpha);
- const uint32_t mask = 0xFF00FF;
- uint64_t tmp = value;
- tmp = (tmp & mask) | ((tmp & ~mask) << 24);
- tmp *= alpha;
- return (uint32_t) (((tmp >> 8) & mask) | ((tmp >> 32) & ~mask));
- }
- class QMul64Bench : public MathBenchU32 {
- public:
- QMul64Bench() : INHERITED("qmul64") {}
- protected:
- void performITest(uint32_t* SK_RESTRICT dst,
- const uint32_t* SK_RESTRICT src,
- int count) override {
- for (int i = 0; i < count; ++i) {
- dst[i] = QMul64(src[i], (uint8_t)i);
- }
- }
- private:
- typedef MathBenchU32 INHERITED;
- };
- class QMul32Bench : public MathBenchU32 {
- public:
- QMul32Bench() : INHERITED("qmul32") {}
- protected:
- void performITest(uint32_t* SK_RESTRICT dst,
- const uint32_t* SK_RESTRICT src,
- int count) override {
- for (int i = 0; i < count; ++i) {
- dst[i] = SkAlphaMulQ(src[i], (uint8_t)i);
- }
- }
- private:
- typedef MathBenchU32 INHERITED;
- };
- ///////////////////////////////////////////////////////////////////////////////
- static bool isFinite_int(float x) {
- uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
- int exponent = bits << 1 >> 24;
- return exponent != 0xFF;
- }
- static bool isFinite_float(float x) {
- return SkToBool(sk_float_isfinite(x));
- }
- static bool isFinite_mulzero(float x) {
- float y = x * 0;
- return y == y;
- }
- static bool isfinite_and_int(const float data[4]) {
- return isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]);
- }
- static bool isfinite_and_float(const float data[4]) {
- return isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]);
- }
- static bool isfinite_and_mulzero(const float data[4]) {
- return isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]);
- }
- #define mulzeroadd(data) (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0)
- static bool isfinite_plus_int(const float data[4]) {
- return isFinite_int(mulzeroadd(data));
- }
- static bool isfinite_plus_float(const float data[4]) {
- return !sk_float_isnan(mulzeroadd(data));
- }
- static bool isfinite_plus_mulzero(const float data[4]) {
- float x = mulzeroadd(data);
- return x == x;
- }
- typedef bool (*IsFiniteProc)(const float[]);
- #define MAKEREC(name) { name, #name }
- static const struct {
- IsFiniteProc fProc;
- const char* fName;
- } gRec[] = {
- MAKEREC(isfinite_and_int),
- MAKEREC(isfinite_and_float),
- MAKEREC(isfinite_and_mulzero),
- MAKEREC(isfinite_plus_int),
- MAKEREC(isfinite_plus_float),
- MAKEREC(isfinite_plus_mulzero),
- };
- #undef MAKEREC
- static bool isFinite(const SkRect& r) {
- // x * 0 will be NaN iff x is infinity or NaN.
- // a + b will be NaN iff either a or b is NaN.
- float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
- // value is either NaN or it is finite (zero).
- // value==value will be true iff value is not NaN
- return value == value;
- }
- class IsFiniteBench : public Benchmark {
- enum {
- N = 1000,
- };
- float fData[N];
- public:
- IsFiniteBench(int index) {
- SkRandom rand;
- for (int i = 0; i < N; ++i) {
- fData[i] = rand.nextSScalar1();
- }
- if (index < 0) {
- fProc = nullptr;
- fName = "isfinite_rect";
- } else {
- fProc = gRec[index].fProc;
- fName = gRec[index].fName;
- }
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- protected:
- void onDraw(int loops, SkCanvas*) override {
- IsFiniteProc proc = fProc;
- const float* data = fData;
- // do this so the compiler won't throw away the function call
- int counter = 0;
- if (proc) {
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < N - 4; ++i) {
- counter += proc(&data[i]);
- }
- }
- } else {
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < N - 4; ++i) {
- const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
- if (false) { // avoid bit rot, suppress warning
- isFinite(*r);
- }
- counter += r->isFinite();
- }
- }
- }
- SkPaint paint;
- if (paint.getAlpha() == 0) {
- SkDebugf("%d\n", counter);
- }
- }
- const char* onGetName() override {
- return fName;
- }
- private:
- IsFiniteProc fProc;
- const char* fName;
- typedef Benchmark INHERITED;
- };
- class FloorBench : public Benchmark {
- enum {
- ARRAY = 1000,
- };
- float fData[ARRAY];
- bool fFast;
- public:
- FloorBench(bool fast) : fFast(fast) {
- SkRandom rand;
- for (int i = 0; i < ARRAY; ++i) {
- fData[i] = rand.nextSScalar1();
- }
- if (fast) {
- fName = "floor_fast";
- } else {
- fName = "floor_std";
- }
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- virtual void process(float) {}
- protected:
- void onDraw(int loops, SkCanvas*) override {
- SkRandom rand;
- float accum = 0;
- const float* data = fData;
- if (fFast) {
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < ARRAY; ++i) {
- accum += fast_floor(data[i]);
- }
- this->process(accum);
- }
- } else {
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < ARRAY; ++i) {
- accum += sk_float_floor(data[i]);
- }
- this->process(accum);
- }
- }
- }
- const char* onGetName() override {
- return fName;
- }
- private:
- const char* fName;
- typedef Benchmark INHERITED;
- };
- class CLZBench : public Benchmark {
- enum {
- ARRAY = 1000,
- };
- uint32_t fData[ARRAY];
- bool fUsePortable;
- public:
- CLZBench(bool usePortable) : fUsePortable(usePortable) {
- SkRandom rand;
- for (int i = 0; i < ARRAY; ++i) {
- fData[i] = rand.nextU();
- }
- if (fUsePortable) {
- fName = "clz_portable";
- } else {
- fName = "clz_intrinsic";
- }
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- // just so the compiler doesn't remove our loops
- virtual void process(int) {}
- protected:
- void onDraw(int loops, SkCanvas*) override {
- int accum = 0;
- if (fUsePortable) {
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < ARRAY; ++i) {
- accum += SkCLZ_portable(fData[i]);
- }
- this->process(accum);
- }
- } else {
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < ARRAY; ++i) {
- accum += SkCLZ(fData[i]);
- }
- this->process(accum);
- }
- }
- }
- const char* onGetName() override {
- return fName;
- }
- private:
- const char* fName;
- typedef Benchmark INHERITED;
- };
- ///////////////////////////////////////////////////////////////////////////////
- class NormalizeBench : public Benchmark {
- enum {
- ARRAY =1000,
- };
- SkVector fVec[ARRAY];
- public:
- NormalizeBench() {
- SkRandom rand;
- for (int i = 0; i < ARRAY; ++i) {
- fVec[i].set(rand.nextSScalar1(), rand.nextSScalar1());
- }
- fName = "point_normalize";
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- // just so the compiler doesn't remove our loops
- virtual void process(int) {}
- protected:
- void onDraw(int loops, SkCanvas*) override {
- int accum = 0;
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < ARRAY; ++i) {
- accum += fVec[i].normalize();
- }
- this->process(accum);
- }
- }
- const char* onGetName() override {
- return fName;
- }
- private:
- const char* fName;
- typedef Benchmark INHERITED;
- };
- ///////////////////////////////////////////////////////////////////////////////
- class FixedMathBench : public Benchmark {
- enum {
- N = 1000,
- };
- float fData[N];
- SkFixed fResult[N];
- public:
- FixedMathBench() {
- SkRandom rand;
- for (int i = 0; i < N; ++i) {
- fData[i] = rand.nextSScalar1();
- }
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- protected:
- void onDraw(int loops, SkCanvas*) override {
- for (int j = 0; j < loops; ++j) {
- for (int i = 0; i < N - 4; ++i) {
- fResult[i] = SkFloatToFixed(fData[i]);
- }
- }
- SkPaint paint;
- if (paint.getAlpha() == 0) {
- SkDebugf("%d\n", fResult[0]);
- }
- }
- const char* onGetName() override {
- return "float_to_fixed";
- }
- private:
- typedef Benchmark INHERITED;
- };
- ///////////////////////////////////////////////////////////////////////////////
- template <typename T>
- class DivModBench : public Benchmark {
- SkString fName;
- public:
- explicit DivModBench(const char* name) {
- fName.printf("divmod_%s", name);
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- protected:
- const char* onGetName() override {
- return fName.c_str();
- }
- void onDraw(int loops, SkCanvas*) override {
- volatile T a = 0, b = 0;
- T div = 0, mod = 0;
- for (int i = 0; i < loops; i++) {
- if ((T)i == 0) continue; // Small T will wrap around.
- SkTDivMod((T)(i+1), (T)i, &div, &mod);
- a ^= div;
- b ^= mod;
- }
- }
- };
- DEF_BENCH(return new DivModBench<uint8_t>("uint8_t"))
- DEF_BENCH(return new DivModBench<uint16_t>("uint16_t"))
- DEF_BENCH(return new DivModBench<uint32_t>("uint32_t"))
- DEF_BENCH(return new DivModBench<uint64_t>("uint64_t"))
- DEF_BENCH(return new DivModBench<int8_t>("int8_t"))
- DEF_BENCH(return new DivModBench<int16_t>("int16_t"))
- DEF_BENCH(return new DivModBench<int32_t>("int32_t"))
- DEF_BENCH(return new DivModBench<int64_t>("int64_t"))
- ///////////////////////////////////////////////////////////////////////////////
- DEF_BENCH( return new NoOpMathBench(); )
- DEF_BENCH( return new SkRSqrtMathBench(); )
- DEF_BENCH( return new SlowISqrtMathBench(); )
- DEF_BENCH( return new FastISqrtMathBench(); )
- DEF_BENCH( return new QMul64Bench(); )
- DEF_BENCH( return new QMul32Bench(); )
- DEF_BENCH( return new IsFiniteBench(-1); )
- DEF_BENCH( return new IsFiniteBench(0); )
- DEF_BENCH( return new IsFiniteBench(1); )
- DEF_BENCH( return new IsFiniteBench(2); )
- DEF_BENCH( return new IsFiniteBench(3); )
- DEF_BENCH( return new IsFiniteBench(4); )
- DEF_BENCH( return new IsFiniteBench(5); )
- DEF_BENCH( return new FloorBench(false); )
- DEF_BENCH( return new FloorBench(true); )
- DEF_BENCH( return new CLZBench(false); )
- DEF_BENCH( return new CLZBench(true); )
- DEF_BENCH( return new NormalizeBench(); )
- DEF_BENCH( return new FixedMathBench(); )
- //////////////////////////////////////////////////////////////
- #include "include/private/SkFloatBits.h"
- class Floor2IntBench : public Benchmark {
- enum {
- ARRAY = 1000,
- };
- float fData[ARRAY];
- const bool fSat;
- public:
- Floor2IntBench(bool sat) : fSat(sat) {
- SkRandom rand;
- for (int i = 0; i < ARRAY; ++i) {
- fData[i] = SkBits2Float(rand.nextU());
- }
- if (sat) {
- fName = "floor2int_sat";
- } else {
- fName = "floor2int_undef";
- }
- }
- bool isSuitableFor(Backend backend) override {
- return backend == kNonRendering_Backend;
- }
- // These exist to try to stop the compiler from detecting what we doing, and throwing
- // parts away (or knowing exactly how big the loop counts are).
- virtual void process(unsigned) {}
- virtual int count() { return ARRAY; }
- protected:
- void onDraw(int loops, SkCanvas*) override {
- // used unsigned to avoid undefined behavior if/when the += might overflow
- unsigned accum = 0;
- for (int j = 0; j < loops; ++j) {
- int n = this->count();
- if (fSat) {
- for (int i = 0; i < n; ++i) {
- accum += sk_float_floor2int(fData[i]);
- }
- } else {
- for (int i = 0; i < n; ++i) {
- accum += sk_float_floor2int_no_saturate(fData[i]);
- }
- }
- this->process(accum);
- }
- }
- const char* onGetName() override { return fName; }
- private:
- const char* fName;
- typedef Benchmark INHERITED;
- };
- DEF_BENCH( return new Floor2IntBench(false); )
- DEF_BENCH( return new Floor2IntBench(true); )
|