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

allocators: don’t assume MIN_ALIGN for small sizes #46117

Merged
merged 3 commits into from
Nov 25, 2017

Conversation

SimonSapin
Copy link
Contributor

See individual commit messages.

…5955

The GNU C library (glibc) is documented to always allocate with an alignment
of at least 8 or 16 bytes, on 32-bit or 64-bit platforms:
https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html

This matches our use of `MIN_ALIGN` before this commit.
However, even when libc is glibc, the program might be linked
with another allocator that redefines the `malloc` symbol and friends.
(The `alloc_jemalloc` crate does, in some cases.)

So `alloc_system` doesn’t know which allocator it calls,
and needs to be conservative in assumptions it makes.

The C standard says:

https://port70.net/%7Ensz/c/c11/n1570.html#7.22.3
> The pointer returned if the allocation succeeds is suitably aligned
> so that it may be assigned to a pointer to any type of object
> with a fundamental alignment requirement

https://port70.net/~nsz/c/c11/n1570.html#6.2.8p2
> A fundamental alignment is represented by an alignment less than
> or equal to the greatest alignment supported by the implementation
> in all contexts, which is equal to `_Alignof (max_align_t)`.

`_Alignof (max_align_t)` depends on the ABI and doesn’t seem to have
a clear definition, but it seems to match our `MIN_ALIGN` in practice.

However, the size of objects is rounded up to the next multiple
of their alignment (since that size is also the stride used in arrays).
Conversely, the alignment of a non-zero-size object is at most its size.
So for example it seems ot be legal for `malloc(8)` to return a pointer
that’s only 8-bytes-aligned, even if `_Alignof (max_align_t)` is 16.
See previous commit’s message for what is expected of allocators
in general, and jemalloc/jemalloc#1072
for discussion of what jemalloc does specifically.
Most often, this code is used through the `std::heap::Heap`
and `#[gloabal_allocator]` indirection, so this branch is not
optimized out anymore.
@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @bluss (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@SimonSapin
Copy link
Contributor Author

I’d appreciate review of not only the diff, but also the assumptions. In particular, should alloc_system be even more conservative than this to support arbitrary malloc implementations? (This is all based on research I did in only the past few days, there may be things that are “common knowledge” but that I missed.)

We might also want to reconsider how useful this MIN_ALIGN optimization is in the first place. In alloc_system it seems important: calloc can probably do much better than posix_memalign + memset, and realloc than posix_memalign + memcpy (especially of platforms with virtual memory, for allocation at least as large as the page size).

In alloc_jemalloc however we only use it to avoid setting some flags. jemalloc does have some fast paths for flags == 0, but I don’t know how much benefit they provide if we need an extra branch on the Rust side. (That branch is likely not optimized away when using std::heap::Heap, because of the #[global_allocator] indirection: #45831.)

@RalfJung
Copy link
Member

So this does not fix System.alloc to call jemalloc, right? It just fixes System.alloc to at least satisfy the API when it is actually jemalloc.

@kennytm kennytm added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 20, 2017
@SimonSapin
Copy link
Contributor Author

@RalfJung Correct. System by definition calls malloc and friends on Unix platforms. That the standard library overrides malloc in some cases is a separate issue: #45966

@SimonSapin
Copy link
Contributor Author

CC @alexcrichton

@alexcrichton
Copy link
Member

Awesome, thanks! I'd personally think that the alloc_system implementation probably doesn't want to change too much (for the reasons you mentioned), but if we benchmark the jemalloc implementation and there's not much difference using flags vs not then seems fine to me to always specify the alignment!

Unfortunately I think it's basically just impossible to fix System.alloc calling jemalloc because of linker trickery. Our only recourse is to remove jemalloc.

@SimonSapin
Copy link
Contributor Author

@alexcrichton Let’s move the relevant discussion to #45966.

@alexcrichton
Copy link
Member

@bors: r+

@bors
Copy link
Contributor

bors commented Nov 20, 2017

📌 Commit 43e32b5 has been approved by alexcrichton

@kennytm kennytm added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 21, 2017
SimonSapin added a commit to SimonSapin/jemallocator that referenced this pull request Nov 22, 2017
Same as rust-lang/rust#46117

See also discussion of jemalloc’s behavior at
jemalloc/jemalloc#1072
@bors
Copy link
Contributor

bors commented Nov 25, 2017

⌛ Testing commit 43e32b5 with merge 59bf09d...

bors added a commit that referenced this pull request Nov 25, 2017
allocators: don’t assume MIN_ALIGN for small sizes

See individual commit messages.
@bors
Copy link
Contributor

bors commented Nov 25, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: alexcrichton
Pushing 59bf09d to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants