Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

raw_svector_ostream will heap allocate without need #23769

Closed
llvmbot opened this issue May 2, 2015 · 5 comments
Closed

raw_svector_ostream will heap allocate without need #23769

llvmbot opened this issue May 2, 2015 · 5 comments
Labels
bugzilla Issues migrated from bugzilla

Comments

@llvmbot
Copy link
Collaborator

llvmbot commented May 2, 2015

Bugzilla Link 23395
Resolution FIXED
Resolved on Aug 26, 2015 23:49
Version trunk
OS Windows NT
Reporter LLVM Bugzilla Contributor
CC @chandlerc,@dexonsmith,@silvasean

Extended Description

The code line

OS.reserve(OS.size() + 64);

called from raw_svector_ostream::write_impl called from raw_svector_ostream::~raw_svector_ostream will heap allocate without need. The issue is already documented:

raw_svector_ostream::~raw_svector_ostream() {
// FIXME: Prevent resizing during this flush().
flush();
}

And a solution is provided in raw_svector_ostream::init():

// Set up the initial external buffer. We make sure that the buffer has at
// least 128 bytes free; raw_ostream itself only requires 64, but we want to
// make sure that we don't grow the buffer unnecessarily on destruction (when
// the data is flushed). See the FIXME below.
OS.reserve(OS.size() + 128);

This solution may be worse than the problem. In total:

  • If the SmallString was less than 128 bytes init() will always(!) heap allocate.
  • If it's more or equal to 128 bytes but upon destruction less than 64 bytes are left unused it will heap allocate for no reason.

A careful programmer who did size the SmallString to match its use + small reserve will find either of these heap allocations surprising, negating the SmallString advantage and then paying memcpy cost.

@dexonsmith
Copy link
Mannequin

dexonsmith mannequin commented May 2, 2015

I haven't looked very closely, but I don't understand why there are any speculative calls to reserve(). push_back() and append() take care of resizing efficiently, and only when necessary.

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 2, 2015

I didn't understand either why it buffers a memory buffer... ultimately I hope a low-overhead class like raw_char_ostream will replace StringStream + raw_svector_ostream usage but given the amount of such existing code this issue should be solved regardless.

@dexonsmith
Copy link
Mannequin

dexonsmith mannequin commented May 2, 2015

I think you should delete both/all the speculative calls to reserve() and see if the tests pass (maybe a caller is relying on something strange?).

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 2, 2015

raw_ostream assumes that the buffer has at least one byte available. This is asserted in raw_ostream::SetBufferAndMode

assert(((Mode == Unbuffered && !BufferStart && Size == 0) ||
(Mode != Unbuffered && BufferStart && Size != 0)) &&
"stream must be unbuffered or have at least one byte");

and required in raw_ostream::write

if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
  assert(NumBytes != 0 && "undefined behavior");
  size_t BytesToWrite = Size - (Size % NumBytes);
  write_impl(Ptr, BytesToWrite);

To make this work further changes are required.

raw_ostreaem::write logic is designed for independent buffer and stream so it is a bad, complex solution when buffer == stream. With raw_char_ostream I overrode write() completely instead of patching it yet more, resulting in a smaller, simpler, clearer code.

It may be possible to do the same for raw_svector_ostream. Some overhead of coordinating between raw_svector_ostream and SmallString which is not really required will remain but this may be neglible.

I'll try this approach too and see if it can achieve near-raw_char_ostream speed.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Aug 27, 2015

r244870

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla
Projects
None yet
Development

No branches or pull requests

1 participant