diff options
-rw-r--r-- | bench/ChecksumBench.cpp | 83 | ||||
-rw-r--r-- | bench/PictureRecordBench.cpp | 57 | ||||
-rw-r--r-- | gyp/bench.gypi | 1 | ||||
-rw-r--r-- | gyp/core.gyp | 1 | ||||
-rw-r--r-- | include/core/SkChecksum.h | 70 | ||||
-rw-r--r-- | include/core/SkDescriptor.h | 15 | ||||
-rw-r--r-- | src/core/SkPictureFlat.cpp | 23 | ||||
-rw-r--r-- | src/core/SkPictureFlat.h | 28 |
8 files changed, 264 insertions, 14 deletions
diff --git a/bench/ChecksumBench.cpp b/bench/ChecksumBench.cpp new file mode 100644 index 0000000000..9057d1272b --- /dev/null +++ b/bench/ChecksumBench.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "SkBenchmark.h" +#include "SkCanvas.h" +#include "SkChecksum.h" +#include "SkString.h" + +class ComputeChecksumBench : public SkBenchmark { +public: + ComputeChecksumBench(void* param, const char name[]) : INHERITED(param) { + fName.printf("compute_checksum_%s", name); + } + + enum { + DATA_SIZE = 1024, + N = SkBENCHLOOP(100000), + }; +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(SkCanvas* canvas) { + uint64_t data[DATA_SIZE / sizeof(uint64_t)]; + computeChecksum(data, DATA_SIZE); + } + + virtual void computeChecksum(const uint64_t*, size_t) = 0; + + SkString fName; +private: + typedef SkBenchmark INHERITED; +}; + +/* + * Use SkComputeChecksum32 to compute a checksum on a datablock + */ +class ComputeChecksum32Bench : public ComputeChecksumBench { +public: + ComputeChecksum32Bench(void* param) + : INHERITED(param, "32") { } + +protected: + virtual void computeChecksum(const uint64_t* data, size_t len) { + for (int i = 0; i < N; i++) { + volatile uint32_t result = SkComputeChecksum32(reinterpret_cast<const uint32_t*>(data), len); + } + } + +private: + typedef ComputeChecksumBench INHERITED; +}; + +/* + * Use SkComputeChecksum64 to compute a checksum on a datablock + */ +class ComputeChecksum64Bench : public ComputeChecksumBench { +public: + ComputeChecksum64Bench(void* param) + : INHERITED(param, "64") { } + +protected: + virtual void computeChecksum(const uint64_t* data, size_t len) { + for (int i = 0; i < N; i++) { + volatile uint64_t result = SkComputeChecksum64(data, len); + } + } + +private: + typedef ComputeChecksumBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static SkBenchmark* Fact0(void* p) { return new ComputeChecksum32Bench(p); } +static SkBenchmark* Fact1(void* p) { return new ComputeChecksum64Bench(p); } + +static BenchRegistry gReg0(Fact0); +static BenchRegistry gReg1(Fact1); diff --git a/bench/PictureRecordBench.cpp b/bench/PictureRecordBench.cpp index e42e5346e1..2e01d6c11e 100644 --- a/bench/PictureRecordBench.cpp +++ b/bench/PictureRecordBench.cpp @@ -123,8 +123,65 @@ private: typedef PictureRecordBench INHERITED; }; +/* + * Populates the SkPaint dictionary with a large number of unique paint + * objects that differ only by color + */ +class UniquePaintDictionaryRecordBench : public PictureRecordBench { +public: + UniquePaintDictionaryRecordBench(void* param) + : INHERITED(param, "unique_paint_dictionary") { } + + enum { + M = SkBENCHLOOP(15000), // number of unique paint objects + }; +protected: + virtual void recordCanvas(SkCanvas* canvas) { + + for (int i = 0; i < M; i++) { + SkPaint paint; + paint.setColor(i); + canvas->drawPaint(paint); + } + } + +private: + typedef PictureRecordBench INHERITED; +}; + +/* + * Populates the SkPaint dictionary with a number of unique paint + * objects that get reused repeatedly + */ +class RecurringPaintDictionaryRecordBench : public PictureRecordBench { +public: + RecurringPaintDictionaryRecordBench(void* param) + : INHERITED(param, "recurring_paint_dictionary") { } + + enum { + ObjCount = 100, // number of unique paint objects + M = SkBENCHLOOP(50000), // number of draw iterations + }; +protected: + virtual void recordCanvas(SkCanvas* canvas) { + + for (int i = 0; i < M; i++) { + SkPaint paint; + paint.setColor(i % ObjCount); + canvas->drawPaint(paint); + } + } + +private: + typedef PictureRecordBench INHERITED; +}; + /////////////////////////////////////////////////////////////////////////////// static SkBenchmark* Fact0(void* p) { return new DictionaryRecordBench(p); } +static SkBenchmark* Fact1(void* p) { return new UniquePaintDictionaryRecordBench(p); } +static SkBenchmark* Fact2(void* p) { return new RecurringPaintDictionaryRecordBench(p); } static BenchRegistry gReg0(Fact0); +static BenchRegistry gReg1(Fact1); +static BenchRegistry gReg2(Fact2); diff --git a/gyp/bench.gypi b/gyp/bench.gypi index b11211ffe7..f809b6431e 100644 --- a/gyp/bench.gypi +++ b/gyp/bench.gypi @@ -9,6 +9,7 @@ '../bench/AAClipBench.cpp', '../bench/BitmapBench.cpp', '../bench/BlurBench.cpp', + '../bench/ChecksumBench.cpp', '../bench/ChromeBench.cpp', '../bench/DashBench.cpp', '../bench/DecodeBench.cpp', diff --git a/gyp/core.gyp b/gyp/core.gyp index ab2e117ea2..5386407eca 100644 --- a/gyp/core.gyp +++ b/gyp/core.gyp @@ -163,6 +163,7 @@ '../include/core/SkBounder.h', '../include/core/SkBuffer.h', '../include/core/SkCanvas.h', + '../include/core/SkChecksum.h', '../include/core/SkChunkAlloc.h', '../include/core/SkClipStack.h', '../include/core/SkColor.h', diff --git a/include/core/SkChecksum.h b/include/core/SkChecksum.h new file mode 100644 index 0000000000..76f1461ed9 --- /dev/null +++ b/include/core/SkChecksum.h @@ -0,0 +1,70 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkChecksum_DEFINED +#define SkChecksum_DEFINED + +#include "SkTypes.h" + +#if !defined(SK_PREFER_32BIT_CHECKSUM) +#define SK_PREFER_32BIT_CHECKSUM 0 +#endif + +enum { + ChecksumRotateBits = 17 +}; + +#define SkCHECKSUM_MASH(CHECKSUM, NEW_CHUNK) \ + CHECKSUM = (((CHECKSUM) >> (sizeof(CHECKSUM)*8 - ChecksumRotateBits)) + \ + ((CHECKSUM) << ChecksumRotateBits)) ^ (NEW_CHUNK); + + +/** + * Compute a 64-bit checksum for a given data block + * + * @param data Memory address of the data block to be processed. Must be + * 32-bit aligned + * @param size Size of the data block in bytes. Must be a multiple of 8. + * @return checksum result + */ +inline uint64_t SkComputeChecksum64(const uint64_t* ptr, size_t size) { + SkASSERT(SkIsAlign8(size)); + // Strict 8-byte alignment is not required on ptr. On current + // CPUs there is no measurable performance difference between 32-bit + // and 64-bit aligned access to uint64_t data + SkASSERT(SkIsAlign4((intptr_t)ptr)); + + const uint64_t* stop = ptr + (size >> 3); + uint64_t result = 0; + while (ptr < stop) { + SkCHECKSUM_MASH(result, *ptr); + ptr++; + } + return result; +} + +/** + * Compute a 32-bit checksum for a given data block + * + * @param data Memory address of the data block to be processed. Must be + * 32-bit aligned. + * @param size Size of the data block in bytes. Must be a multiple of 4. + * @return checksum result + */ +inline uint32_t SkComputeChecksum32(const uint32_t* ptr, size_t size) { + SkASSERT(SkIsAlign4(size)); + SkASSERT(SkIsAlign4((intptr_t)ptr)); + + const uint32_t* stop = ptr + (size >> 2); + uint32_t result = 0; + while (ptr < stop) { + SkCHECKSUM_MASH(result, *ptr); + ptr++; + } + return result; +} +#endif
\ No newline at end of file diff --git a/include/core/SkDescriptor.h b/include/core/SkDescriptor.h index b97b75f949..00bc9aa924 100644 --- a/include/core/SkDescriptor.h +++ b/include/core/SkDescriptor.h @@ -10,6 +10,7 @@ #ifndef SkDescriptor_DEFINED #define SkDescriptor_DEFINED +#include "SkChecksum.h" #include "SkTypes.h" class SkDescriptor : SkNoncopyable { @@ -131,17 +132,9 @@ private: static uint32_t ComputeChecksum(const SkDescriptor* desc) { - const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field - const uint32_t* stop = (const uint32_t*)((const char*)desc + desc->fLength); - uint32_t sum = 0; - - SkASSERT(ptr < stop); - do { - sum = (sum << 1) | (sum >> 31); - sum ^= *ptr++; - } while (ptr < stop); - - return sum; + const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field + const size_t len = desc->fLength-sizeof(uint32_t); + return SkComputeChecksum32(ptr, len); } // private so no one can create one except our factories diff --git a/src/core/SkPictureFlat.cpp b/src/core/SkPictureFlat.cpp index 14d912d929..ec04495db9 100644 --- a/src/core/SkPictureFlat.cpp +++ b/src/core/SkPictureFlat.cpp @@ -7,6 +7,7 @@ */ #include "SkPictureFlat.h" +#include "SkChecksum.h" #include "SkColorFilter.h" #include "SkDrawLooper.h" #include "SkMaskFilter.h" @@ -79,7 +80,13 @@ SkFlatData* SkFlatData::Create(SkChunkAlloc* heap, const void* obj, flattenProc(buffer, obj); uint32_t size = buffer.size(); - // allocate the enough memory to hold both SkFlatData and the serialized + +#if !SK_PREFER_32BIT_CHECKSUM + uint32_t unpaddedSize = size; + size = SkAlign8(size); +#endif + + // allocate enough memory to hold both SkFlatData and the serialized // contents SkFlatData* result = (SkFlatData*) heap->allocThrow(size + sizeof(SkFlatData)); result->fIndex = index; @@ -87,6 +94,18 @@ SkFlatData* SkFlatData::Create(SkChunkAlloc* heap, const void* obj, // put the serialized contents into the data section of the new allocation buffer.flatten(result->data()); +#if SK_PREFER_32BIT_CHECKSUM + result->fChecksum = + SkComputeChecksum32(reinterpret_cast<uint32_t*>(result->data()), size); +#else + if (size != unpaddedSize) { + // Flat data is padded: put zeros in the last 32 bits. + SkASSERT(size - 4 == unpaddedSize); + *((uint32_t*)((char*)result->data() + unpaddedSize)) = 0; + } + result->fChecksum = + SkComputeChecksum64(reinterpret_cast<uint64_t*>(result->data()), size); +#endif return result; } @@ -103,5 +122,5 @@ void SkFlatData::unflatten(void* result, facePlayback->setupBuffer(buffer); } unflattenProc(buffer, result); - SkASSERT(fAllocSize == (int32_t)buffer.offset()); + SkASSERT(fAllocSize == SkAlign8((int32_t)buffer.offset())); } diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index 832a645864..5918261204 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -155,7 +155,25 @@ class SkFlatData { public: static int Compare(const SkFlatData* a, const SkFlatData* b) { - return memcmp(a->data(), b->data(), a->fAllocSize); + size_t bytesToCompare = sizeof(a->fChecksum) + a->fAllocSize; +#if SK_PREFER_32BIT_CHECKSUM + typedef uint32_t CompareType; + SkASSERT(SkIsAlign4(bytesToCompare)); +#else + typedef uint64_t CompareType; + SkASSERT(SkIsAlign8(bytesToCompare)); +#endif + const CompareType* a_ptr = &(a->fChecksum); + const CompareType* b_ptr = &(b->fChecksum); + const CompareType* stop = a_ptr + bytesToCompare / sizeof(CompareType); + while(a_ptr < stop) { + if (*a_ptr != *b_ptr) { + return (*a_ptr < *b_ptr) ? -1 : 1; + } + a_ptr++; + b_ptr++; + } + return 0; } int index() const { return fIndex; } @@ -176,8 +194,16 @@ public: SkTypefacePlayback* facePlayback = NULL) const; private: + // Data members add-up to 128 bits of storage, so data() is 128-bit + // aligned, which helps performance of memcpy in SkWriter32::flatten int fIndex; int32_t fAllocSize; + // fChecksum must be defined last in order to be contiguous with data() +#if SK_PREFER_32BIT_CHECKSUM + uint32_t fChecksum; +#else + uint64_t fChecksum; +#endif }; template <class T> |