diff options
author | Mike Reed <reed@google.com> | 2016-12-15 14:11:37 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2016-12-15 19:49:31 +0000 |
commit | 9c457ad27b35022e36d62b6fe1a6aee530213cf6 (patch) | |
tree | c06396d0b044d2631b1685d3553406d8f48fd5ae /src/core/SkStream.cpp | |
parent | e4bf164225cc6d027566e9bfa0c8492629a6e090 (diff) |
speedup dynamicwstream
- move bytesWritten calculation to query the tail, allowing write() to be faster since it doesn't have to update anything extra per-write.
- enforce that all blocks are multiple-of-4 bytes big
- update the minimum block size to 4K
Before: 30ms
After: 23ms for non-4-bytes writes
13ms for 4-bytes writes
BUG=skia:
Change-Id: Id06ecad3b9fe426747e02accf1393595e3356ce3
Reviewed-on: https://skia-review.googlesource.com/6087
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>
Diffstat (limited to 'src/core/SkStream.cpp')
-rw-r--r-- | src/core/SkStream.cpp | 128 |
1 files changed, 82 insertions, 46 deletions
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp index 20afe2b701..cf473e76c4 100644 --- a/src/core/SkStream.cpp +++ b/src/core/SkStream.cpp @@ -107,20 +107,6 @@ bool SkWStream::writeScalarAsText(SkScalar value) return this->write(buffer, stop - buffer); } -bool SkWStream::write8(U8CPU value) { - uint8_t v = SkToU8(value); - return this->write(&v, 1); -} - -bool SkWStream::write16(U16CPU value) { - uint16_t v = SkToU16(value); - return this->write(&v, 2); -} - -bool SkWStream::write32(uint32_t value) { - return this->write(&value, 4); -} - bool SkWStream::writeScalar(SkScalar value) { return this->write(&value, sizeof(value)); } @@ -467,7 +453,15 @@ bool SkMemoryWStream::write(const void* buffer, size_t size) { //////////////////////////////////////////////////////////////////////// -#define SkDynamicMemoryWStream_MinBlockSize 256 +static inline void sk_memcpy_4bytes(void* dst, const void* src, size_t size) { + if (size == 4) { + memcpy(dst, src, 4); + } else { + memcpy(dst, src, size); + } +} + +#define SkDynamicMemoryWStream_MinBlockSize 4096 struct SkDynamicMemoryWStream::Block { Block* fNext; @@ -479,29 +473,26 @@ struct SkDynamicMemoryWStream::Block { size_t avail() const { return fStop - fCurr; } size_t written() const { return fCurr - this->start(); } - void init(size_t size) - { + void init(size_t size) { fNext = nullptr; fCurr = this->start(); fStop = this->start() + size; } - const void* append(const void* data, size_t size) - { + const void* append(const void* data, size_t size) { SkASSERT((size_t)(fStop - fCurr) >= size); - memcpy(fCurr, data, size); + sk_memcpy_4bytes(fCurr, data, size); fCurr += size; return (const void*)((const char*)data + size); } }; SkDynamicMemoryWStream::SkDynamicMemoryWStream() - : fHead(nullptr), fTail(nullptr), fBytesWritten(0) + : fHead(nullptr), fTail(nullptr), fBytesWrittenBeforeTail(0) {} -SkDynamicMemoryWStream::~SkDynamicMemoryWStream() -{ - reset(); +SkDynamicMemoryWStream::~SkDynamicMemoryWStream() { + this->reset(); } void SkDynamicMemoryWStream::reset() { @@ -512,25 +503,39 @@ void SkDynamicMemoryWStream::reset() { block = next; } fHead = fTail = nullptr; - fBytesWritten = 0; + fBytesWrittenBeforeTail = 0; +} + +size_t SkDynamicMemoryWStream::bytesWritten() const { + this->validate(); + + if (fTail) { + return fBytesWrittenBeforeTail + fTail->written(); + } + return 0; } bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) { if (count > 0) { - fBytesWritten += count; - size_t size; - if (fTail != nullptr && fTail->avail() > 0) { - size = SkTMin(fTail->avail(), count); - buffer = fTail->append(buffer, size); - SkASSERT(count >= size); - count -= size; - if (count == 0) - return true; + if (fTail) { + if (fTail->avail() > 0) { + size = SkTMin(fTail->avail(), count); + buffer = fTail->append(buffer, size); + SkASSERT(count >= size); + count -= size; + if (count == 0) { + return true; + } + } + // If we get here, we've just exhausted fTail, so update our tracker + fBytesWrittenBeforeTail += fTail->written(); } - size = SkTMax<size_t>(count, SkDynamicMemoryWStream_MinBlockSize); + size = SkTMax<size_t>(count, SkDynamicMemoryWStream_MinBlockSize - sizeof(Block)); + size = SkAlign4(size); // ensure we're always a multiple of 4 (see padToAlign4()) + Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); block->init(size); block->append(buffer, count); @@ -540,14 +545,15 @@ bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) { else fHead = fTail = block; fTail = block; + this->validate(); } return true; } -bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) -{ - if (offset + count > fBytesWritten) +bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) { + if (offset + count > this->bytesWritten()) { return false; // test does not partially modify + } Block* block = fHead; while (block != nullptr) { size_t size = block->written(); @@ -581,14 +587,19 @@ void SkDynamicMemoryWStream::writeToStream(SkWStream* dst) const { } } -void SkDynamicMemoryWStream::padToAlign4() -{ - // cast to remove unary-minus warning - int padBytes = -(int)fBytesWritten & 0x03; - if (padBytes == 0) - return; - int zero = 0; - write(&zero, padBytes); +void SkDynamicMemoryWStream::padToAlign4() { + // The contract is to write zeros until the entire stream has written a multiple of 4 bytes. + // Our Blocks are guaranteed always be (a) full (except the tail) and (b) a multiple of 4 + // so it is sufficient to just examine the tail (if present). + + if (fTail) { + // cast to remove unary-minus warning + int padBytes = -(int)fTail->written() & 0x03; + if (padBytes) { + int zero = 0; + fTail->append(&zero, padBytes); + } + } } sk_sp<SkData> SkDynamicMemoryWStream::detachAsData() { @@ -603,6 +614,31 @@ sk_sp<SkData> SkDynamicMemoryWStream::detachAsData() { return data; } +#ifdef SK_DEBUG +void SkDynamicMemoryWStream::validate() const { + if (!fHead) { + SkASSERT(!fTail); + SkASSERT(fBytesWrittenBeforeTail == 0); + return; + } + SkASSERT(fTail); + + size_t bytes = 0; + const Block* block = fHead; + while (block) { + if (block->fNext) { + SkASSERT(block->avail() == 0); + bytes += block->written(); + SkASSERT(bytes == SkAlign4(bytes)); // see padToAlign4() + } + block = block->fNext; + } + SkASSERT(bytes == fBytesWrittenBeforeTail); +} +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////// + class SkBlockMemoryRefCnt : public SkRefCnt { public: explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { } |