This is an archive of the discontinued LLVM Phabricator instance.

[demangler] Fix buffer growth
ClosedPublic

Authored by urnathan on Feb 7 2022, 12:17 PM.

Details

Reviewers
ChuanqiXu
bruno
iains
serge-sans-paille
Group Reviewers
Restricted Project
Commits
rG995c4f306890: [demangler] Fix buffer growth
Summary

The output buffer growth algorithm had a couple of issues:

a) An off-by-one error in the initial size check, which uses '>='. This error was safe, but could cause us to reallocate when there was no need.

b) An inconsistency between the initial size check (>=) and the post-doubling check (>). The latter was somewhat obscured by the swapped operands.

c) There would be many reallocs with an initially-small buffer. Add a little initialization hysteresis.

Diff Detail

Event Timeline

urnathan requested review of this revision.Feb 7 2022, 12:17 PM
urnathan created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptFeb 7 2022, 12:17 PM
ChuanqiXu added inline comments.Feb 7 2022, 6:24 PM
libcxxabi/src/demangle/Utility.h
39

What's the meaning of the magic number 100? Generally we should make it configurable or at least we should give a name to it.

urnathan edited reviewers, added: serge-sans-paille; removed: aaron.ballman.Feb 8 2022, 4:53 AM
urnathan updated this revision to Diff 407172.Feb 9 2022, 8:35 AM

Let's make 1024 the minimum and use a constvar so we don't write it twice.

urnathan added inline comments.Feb 9 2022, 8:36 AM
libcxxabi/src/demangle/Utility.h
39

It seems dramatically over-engineering to make this configurable. You just want a number high enough for many symbols in one go, and big enough that larger symbols don't keep reallocating. But not so big that one allocates a tremendously excessive amount. The demangler Nodes themselves are probably the largest component?

100 seemed a good enough value. It's better than the current [non-configurable] zero :) I notice the demangler's node allocator (BumpPointerAllocator) allocates [unconfigurable] 4096 byte blocks. So let's go with 1024 here, ok?

urnathan marked an inline comment as done.Feb 9 2022, 8:38 AM
urnathan added inline comments.
libcxxabi/src/demangle/Utility.h
39

I've noticed the missing full stop on the comment.

ChuanqiXu added inline comments.Feb 9 2022, 6:08 PM
libcxxabi/src/demangle/Utility.h
40–42

It looks like that MinInitAlloc is a better name. I would like to move line 43~45 after line 38. Then we could simplify the code to:

size_t Need = N + CurrentPosition;
/// A comment here
constexpr size_t MinInitAlloc = 1024;
 if (!BufferCapacity)
      Need = max(Need, MinInitAlloc);
if (Need > BufferCapacity)
       BufferCapacity = max(Need, BufferCapacity * 2);
urnathan updated this revision to Diff 407477.Feb 10 2022, 4:48 AM
urnathan marked an inline comment as done.
urnathan added inline comments.
libcxxabi/src/demangle/Utility.h
40–42

I put the MinInitAlloc checking inside the outer if, to avoid making the non-allocating path more complex. We only need to check the minium when we know we're going to allocate

ChuanqiXu added inline comments.Feb 10 2022, 5:58 PM
libcxxabi/src/demangle/Utility.h
40–42

Now it lost the check: if (!BufferCapacity). Is it intentional? Now it wouldn't allocate at the initialization only. So the name may be not appropriate.

urnathan marked an inline comment as done.Feb 11 2022, 3:59 AM
urnathan added inline comments.
libcxxabi/src/demangle/Utility.h
40–42

that check is unnecessary, we'll only pick MinInitAlloc on the first allocation -- because later allocations will be for a greater amount.

urnathan marked an inline comment as done.Feb 11 2022, 4:47 AM
ChuanqiXu accepted this revision.Feb 13 2022, 6:01 PM
ChuanqiXu added inline comments.
libcxxabi/src/demangle/Utility.h
40–42

Yeah, it is true. I didn't figure it out previously.

This revision is now accepted and ready to land.Feb 13 2022, 6:01 PM
This revision was landed with ongoing or failed builds.Feb 14 2022, 4:00 AM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptFeb 14 2022, 4:00 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript
thakis added a subscriber: thakis.Feb 16 2022, 6:51 AM

This breaks building on one of our bots: https://logs.chromium.org/logs/chromium/buildbucket/cr-buildbucket/8822094137116818625/+/u/package_clang/stdout?format=raw

In file included from /opt/s/w/ir/cache/builder/src/third_party/llvm/llvm/unittests/Demangle/ItaniumDemangleTest.cpp:9:
 In file included from /opt/s/w/ir/cache/builder/src/third_party/llvm/llvm/include/llvm/Demangle/ItaniumDemangle.h:25:
 /opt/s/w/ir/cache/builder/src/third_party/llvm/llvm/include/llvm/Demangle/Utility.h:42:19: error: no member named 'max' in namespace 'std'; did you mean 'fmax'?
       Need = std::max(Need, MinInitAlloc);
              ~~~~~^~~
                   fmax

Looks like this now needs an include of <algorithm> for std::max(). That's a pretty heavy header though; maybe this should instead be rewritten to not use max, like on the lhs?

urnathan added a comment.EditedFeb 16 2022, 7:31 AM

Looks like this now needs an include of <algorithm> for std::max(). That's a pretty heavy header though; maybe this should instead be rewritten to not use max, like on the lhs?

stupid inconsistent header files :), yeah algorithm is rather large, I'll open-code it.

ETA: Ah, I see the copied header diverged from the original, lacking the <algorithm> include. See D119951 for fix.