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

call Vec::shrink_to_vec in a few strategic spots #120

Merged
merged 3 commits into from
Aug 10, 2023
Merged

Conversation

BurntSushi
Copy link
Owner

See the commit messages for more details.

This work was overall inspired by the investigation I did in this issue: G-Research/ahocorasick_rs#62

TL;DR - Creating lots of Vecs can lead to a lot of spare unused capacity hanging around. This invariably leads to potentially large discrepancies between a process's peak memory usage and the memory usage as reported by something like NFA::memory_usage.

I think I started with a contiguous representation but switched to
nested allocs. Which is kind of unfortunate, and I'd like to fix that,
but for now we should document reality.
Previously the heap usage required for storing the lengths of each
pattern was not included in the memory usage reported.
This commit reduces the *actual* heap memory used by noncontiguous
NFAs, contiguous NFAs and DFAs. Previously, all three would report
memory usage that only included what was actually being used within
each Vec. But each Vec might actually have a lot more heap memory
inside of it in the form of unused capacity. Potentially ~twice as
much. This is because a Vec amortizes its growth.

So when Vecs are used to build NFAs and DFAs, some of them wind up
with potentially a lot of additional capacity that goes unused and
unreported. This commit partially fixes that by calling shrink_to_vec
in a few strategic places. However, there are still some nested Vecs,
notably in the noncontiguous NFA, that remain unshrinked. I tried doing
it, but the perf impact it had on construction was non-trivial.

This is a good example of one of those things where you of course know
that Vecs amortize their growth by reserving potentially extra capacity
that yuo won't end up using, but still remain ignorant of the broader
effects of this strategy in aggregate. Especially at the extremes when
you start trying to build Aho-Corasick automatons with millions of
patterns.

We should think more carefully about using linked lists in the
non-contiguous NFA to reduce memory usage, or perhaps thinking of some
other way to avoid nested Vecs. It turns out that they end up
penalizing us quite a bit.

This commit was inspired by the investigation I did as part of this
issue: G-Research/ahocorasick_rs#62
@BurntSushi BurntSushi merged commit 474393b into master Aug 10, 2023
@BurntSushi BurntSushi deleted the ag/shrink-vecs branch August 10, 2023 02:37
BurntSushi added a commit to BurntSushi/ripgrep that referenced this pull request Aug 15, 2023
This brings in [1,2], which improves memory usage substantially when
Aho-Corasick is used.

[1]: BurntSushi/aho-corasick#120
[2]: BurntSushi/aho-corasick#121
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant