|
7 | 7 | // distribution. The obvious way to do this is with the `#[global_allocator]` |
8 | 8 | // mechanism. However, for complicated reasons (see |
9 | 9 | // https://github.com/rust-lang/rust/pull/81782#issuecomment-784438001 for some |
10 | | -// details) that mechanism doesn't work here. Also, we'd like to use a |
11 | | -// consistent allocator across the rustc <-> llvm boundary, and |
12 | | -// `#[global_allocator]` wouldn't provide that. |
| 10 | +// details) that mechanism doesn't work here. Also, we must use a consistent |
| 11 | +// allocator across the rustc <-> llvm boundary, and `#[global_allocator]` |
| 12 | +// wouldn't provide that. |
13 | 13 | // |
14 | | -// Instead, we use a lower-level mechanism, namely the |
15 | | -// `"override_allocator_on_supported_platforms"` Cargo feature of jemalloc-sys. |
16 | | -// |
17 | | -// This makes jemalloc-sys override the libc/system allocator's implementation |
18 | | -// of `malloc`, `free`, etc.. This means that Rust's `System` allocator, which |
19 | | -// calls `libc::malloc()` et al., is actually calling into jemalloc. |
| 14 | +// Instead, we use a lower-level mechanism. rustc is linked with jemalloc in a |
| 15 | +// way such that jemalloc's implementation of `malloc`, `free`, etc., override |
| 16 | +// the libc allocator's implementation. This means that Rust's `System` |
| 17 | +// allocator, which calls `libc::malloc()` et al., is actually calling into |
| 18 | +// jemalloc. |
20 | 19 | // |
21 | 20 | // A consequence of not using `GlobalAlloc` (and the `tikv-jemallocator` crate |
22 | 21 | // provides an impl of that trait, which is called `Jemalloc`) is that we |
23 | 22 | // cannot use the sized deallocation APIs (`sdallocx`) that jemalloc provides. |
24 | 23 | // It's unclear how much performance is lost because of this. |
25 | 24 | // |
26 | | -// NOTE: Even though Cargo passes `--extern` with `tikv_jemalloc_sys`, we still need to `use` the |
27 | | -// crate for the compiler to see the `#[used]`, see https://github.com/rust-lang/rust/issues/64402. |
28 | | -// This is similarly required if we used a crate with `#[global_allocator]`. |
| 25 | +// As for the symbol overrides in `main` below: we're pulling in a static copy |
| 26 | +// of jemalloc. We need to actually reference its symbols for it to get linked. |
| 27 | +// The two crates we link to here, `std` and `rustc_driver`, are both dynamic |
| 28 | +// libraries. So we must reference jemalloc symbols one way or another, because |
| 29 | +// this file is the only object code in the rustc executable. |
29 | 30 | // |
30 | 31 | // NOTE: if you are reading this comment because you want to set a custom `global_allocator` for |
31 | 32 | // benchmarking, consider using the benchmarks in the `rustc-perf` collector suite instead: |
|
35 | 36 | // to compare their performance, see |
36 | 37 | // https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef |
37 | 38 | // for an example of how to do so. |
38 | | -#[cfg(feature = "jemalloc")] |
39 | | -use tikv_jemalloc_sys as _; |
40 | 39 |
|
41 | 40 | fn main() { |
| 41 | + // See the comment at the top of this file for an explanation of this. |
| 42 | + #[cfg(feature = "jemalloc")] |
| 43 | + { |
| 44 | + use std::os::raw::{c_int, c_void}; |
| 45 | + |
| 46 | + use tikv_jemalloc_sys as jemalloc_sys; |
| 47 | + |
| 48 | + #[used] |
| 49 | + static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc; |
| 50 | + #[used] |
| 51 | + static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = |
| 52 | + jemalloc_sys::posix_memalign; |
| 53 | + #[used] |
| 54 | + static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc; |
| 55 | + #[used] |
| 56 | + static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc; |
| 57 | + #[used] |
| 58 | + static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc; |
| 59 | + #[used] |
| 60 | + static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free; |
| 61 | + |
| 62 | + // On OSX, jemalloc doesn't directly override malloc/free, but instead |
| 63 | + // registers itself with the allocator's zone APIs in a ctor. However, |
| 64 | + // the linker doesn't seem to consider ctors as "used" when statically |
| 65 | + // linking, so we need to explicitly depend on the function. |
| 66 | + #[cfg(target_os = "macos")] |
| 67 | + { |
| 68 | + unsafe extern "C" { |
| 69 | + fn _rjem_je_zone_register(); |
| 70 | + } |
| 71 | + |
| 72 | + #[used] |
| 73 | + static _F7: unsafe extern "C" fn() = _rjem_je_zone_register; |
| 74 | + } |
| 75 | + } |
| 76 | + |
42 | 77 | rustc_driver::main() |
43 | 78 | } |
0 commit comments