diff options
author | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-31 04:03:02 +0000 |
---|---|---|
committer | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-31 04:03:02 +0000 |
commit | d1b319fc3f77e744fb325a5a28b6ae448072a9ae (patch) | |
tree | cd4b30de4c88a730eaf2fe04cf02c6b10f227a25 /base/pickle.cc | |
parent | a979d27b84e0c363e0a3e640890a098374a5883b (diff) | |
download | chromium_src-d1b319fc3f77e744fb325a5a28b6ae448072a9ae.zip chromium_src-d1b319fc3f77e744fb325a5a28b6ae448072a9ae.tar.gz chromium_src-d1b319fc3f77e744fb325a5a28b6ae448072a9ae.tar.bz2 |
Pickle::Write* micro-optimizations
Pickle is hot in some benchmarks. This helps by reworking WriteBytes in a few of ways:
1- Fold BeginWrite and EndWrite into WriteBytes since it's the only caller now.
2- keep track of the write offset, always aligned, separately, so that we can do alignment checks on the field sizes rather than the payload size (for next point).
3- provides a template version of WriteBytes with specializations for predefined sizes, that inline/optimize away alignment checks, padding, and memcpy.
4- change the meaning of capacity_ to not take the header size into account. This simplifies some arithmetic.
BUG=307480
R=jar@chromium.org
Review URL: https://codereview.chromium.org/34413002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231987 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/pickle.cc')
-rw-r--r-- | base/pickle.cc | 117 |
1 files changed, 58 insertions, 59 deletions
diff --git a/base/pickle.cc b/base/pickle.cc index 1d06af3..c88503c 100644 --- a/base/pickle.cc +++ b/base/pickle.cc @@ -153,7 +153,8 @@ bool PickleIterator::ReadBytes(const char** data, int length) { Pickle::Pickle() : header_(NULL), header_size_(sizeof(Header)), - capacity_(0) { + capacity_after_header_(0), + write_offset_(0) { Resize(kPayloadUnit); header_->payload_size = 0; } @@ -161,7 +162,8 @@ Pickle::Pickle() Pickle::Pickle(int header_size) : header_(NULL), header_size_(AlignInt(header_size, sizeof(uint32))), - capacity_(0) { + capacity_after_header_(0), + write_offset_(0) { DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header)); DCHECK_LE(header_size, kPayloadUnit); Resize(kPayloadUnit); @@ -171,7 +173,8 @@ Pickle::Pickle(int header_size) Pickle::Pickle(const char* data, size_t data_len) : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), header_size_(0), - capacity_(kCapacityReadOnly) { + capacity_after_header_(kCapacityReadOnly), + write_offset_(0) { if (data_len >= sizeof(Header)) header_size_ = data_len - header_->payload_size; @@ -189,15 +192,15 @@ Pickle::Pickle(const char* data, size_t data_len) Pickle::Pickle(const Pickle& other) : header_(NULL), header_size_(other.header_size_), - capacity_(0) { + capacity_after_header_(0), + write_offset_(other.write_offset_) { size_t payload_size = header_size_ + other.header_->payload_size; - bool resized = Resize(payload_size); - CHECK(resized); // Realloc failed. + Resize(payload_size); memcpy(header_, other.header_, payload_size); } Pickle::~Pickle() { - if (capacity_ != kCapacityReadOnly) + if (capacity_after_header_ != kCapacityReadOnly) free(header_); } @@ -206,19 +209,19 @@ Pickle& Pickle::operator=(const Pickle& other) { NOTREACHED(); return *this; } - if (capacity_ == kCapacityReadOnly) { + if (capacity_after_header_ == kCapacityReadOnly) { header_ = NULL; - capacity_ = 0; + capacity_after_header_ = 0; } if (header_size_ != other.header_size_) { free(header_); header_ = NULL; header_size_ = other.header_size_; } - bool resized = Resize(other.header_size_ + other.header_->payload_size); - CHECK(resized); // Realloc failed. + Resize(other.header_->payload_size); memcpy(header_, other.header_, other.header_size_ + other.header_->payload_size); + write_offset_ = other.write_offset_; return *this; } @@ -249,64 +252,31 @@ bool Pickle::WriteData(const char* data, int length) { return length >= 0 && WriteInt(length) && WriteBytes(data, length); } -bool Pickle::WriteBytes(const void* data, int data_len) { - DCHECK_NE(kCapacityReadOnly, capacity_) << "oops: pickle is readonly"; - - char* dest = BeginWrite(data_len); - if (!dest) - return false; - - memcpy(dest, data, data_len); - - EndWrite(dest, data_len); +bool Pickle::WriteBytes(const void* data, int length) { + WriteBytesCommon(data, length); return true; } -void Pickle::Reserve(size_t additional_capacity) { - // Write at a uint32-aligned offset from the beginning of the header. - size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); - - size_t new_size = offset + additional_capacity; - size_t needed_size = header_size_ + new_size; - if (needed_size > capacity_) - Resize(capacity_ * 2 + needed_size); -} - -char* Pickle::BeginWrite(size_t length) { - // Write at a uint32-aligned offset from the beginning of the header. - size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); - - size_t new_size = offset + length; - size_t needed_size = header_size_ + new_size; - if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) - return NULL; - +void Pickle::Reserve(size_t length) { + size_t data_len = AlignInt(length, sizeof(uint32)); + DCHECK_GE(data_len, length); #ifdef ARCH_CPU_64_BITS - DCHECK_LE(length, kuint32max); + DCHECK_LE(data_len, kuint32max); #endif - - header_->payload_size = static_cast<uint32>(new_size); - return mutable_payload() + offset; -} - -void Pickle::EndWrite(char* dest, int length) { - // Zero-pad to keep tools like valgrind from complaining about uninitialized - // memory. - if (length % sizeof(uint32)) - memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32))); + DCHECK_LE(write_offset_, kuint32max - data_len); + size_t new_size = write_offset_ + data_len; + if (new_size > capacity_after_header_) + Resize(capacity_after_header_ * 2 + new_size); } -bool Pickle::Resize(size_t new_capacity) { +void Pickle::Resize(size_t new_capacity) { new_capacity = AlignInt(new_capacity, kPayloadUnit); - CHECK_NE(capacity_, kCapacityReadOnly); - void* p = realloc(header_, new_capacity); - if (!p) - return false; - + CHECK_NE(capacity_after_header_, kCapacityReadOnly); + void* p = realloc(header_, header_size_ + new_capacity); + CHECK(p); header_ = reinterpret_cast<Header*>(p); - capacity_ = new_capacity; - return true; + capacity_after_header_ = new_capacity; } // static @@ -327,3 +297,32 @@ const char* Pickle::FindNext(size_t header_size, return (payload_end > end) ? NULL : payload_end; } + +template <size_t length> void Pickle::WriteBytesStatic(const void* data) { + WriteBytesCommon(data, length); +} + +template void Pickle::WriteBytesStatic<2>(const void* data); +template void Pickle::WriteBytesStatic<4>(const void* data); +template void Pickle::WriteBytesStatic<8>(const void* data); + +inline void Pickle::WriteBytesCommon(const void* data, size_t length) { + DCHECK_NE(kCapacityReadOnly, capacity_after_header_) + << "oops: pickle is readonly"; + size_t data_len = AlignInt(length, sizeof(uint32)); + DCHECK_GE(data_len, length); +#ifdef ARCH_CPU_64_BITS + DCHECK_LE(data_len, kuint32max); +#endif + DCHECK_LE(write_offset_, kuint32max - data_len); + size_t new_size = write_offset_ + data_len; + if (new_size > capacity_after_header_) { + Resize(std::max(capacity_after_header_ * 2, new_size)); + } + + char* write = mutable_payload() + write_offset_; + memcpy(write, data, length); + memset(write + length, 0, data_len - length); + header_->payload_size = static_cast<uint32>(write_offset_ + length); + write_offset_ = new_size; +} |