Skip to content

LLVM doesn't know about jemalloc #22159

Description

@XMPPwocky

LLVM can remove "dead" calls to malloc() (where the return value is ignored, or immediately free()-d (possibly after being compared with NULL)). However, this is basically hardcoded to the "malloc" symbol (and "free", etc.); it is not aware of jemalloc (specifically je_mallocx and je_sdallocx), which Rust uses.

LLVM is very good at removing temporary allocations, as it turns out:

extern crate libc;
extern crate test;

fn main() {

unsafe {
    // totally dead (and a memory leak)
    // produces no calls to libc malloc
    let _ = libc::malloc(4);

    // freed immediately, no allocations
    libc::free(libc::malloc(4));

    // allocated, used to store something temporarily, then freed
    // still no allocations!
    let x = libc::malloc(std::mem::size_of::<i32>() as libc::size_t);
    assert!(!x.is_null());
    *(x as *mut i32) = 42i32;
    let y = *(x as *mut i32);
    libc::free(x);
    test::black_box(y);
}

}

will not call malloc or free (at -O2).

On the other hand, even the most trivial allocation using liballoc...

fn main() {
    let _ = Box::new(42i32);
}

will invoke je_mallocx and je_sdallocx, even at -O3.

/cc @dotdash

Activity

  1. bstrie commented on Feb 11, 2015

    @bstrie
    Contributor

    I feel like we must have opened an issue for this at some point, but a cursory search doesn't show one.

  2. added
    I-slowIssue: Problems and improvements with respect to performance of generated code.
    on Feb 11, 2015
  3. bstrie commented on Feb 11, 2015

    @bstrie
    Contributor

    I believe that past discussions of this behavior have involved making jemalloc pretend to be malloc in order to trigger the optimization, but here are we proposing to change LLVM itself?

  4. XMPPwocky commented on Feb 11, 2015

    @XMPPwocky
    ContributorAuthor

    Apparently Rust already uses a few patches on LLVM; adding another one is probably not that bad.

    I think the best way for this to be handled is for there to be some way to indicate "malloc-y stuff" to LLVM; currently, LLVM is just hardcoded. The easiest change would just be replacing "malloc" with "je_mallocx", and "free" with "je_sdallocx", but removing the hardcoding entirely (and contributing that back to LLVM upstream) is probably ideal.

    It's arguable that this is actually LLVM's issue, but because we are already not using "stock" LLVM, it may be worth it to diverge a little further from LLVM master.

    I'm not sure how jemalloc could pretend to be malloc, because the APIs are different; from what I saw of LLVM's code, it checks both the function name and the signature. Any wins from better optimization here are unlikely to be worth giving up sized deallocation and alignment, for example.

  5. steveklabnik commented on Feb 11, 2015

    @steveklabnik
    Contributor

    Apparently Rust already uses a few patches on LLVM; adding another one is probably not that bad.

    Most (maybe all?) of them are performance related these days, and we try to move them upstream. Building with standard LLVM will be important for things like packaging Rust.

  6. alexchandel commented on Feb 11, 2015

    @alexchandel

    This is significant, since for a basic hello world program,

    fn main() {
        let _ = Box::new(42i32);
    }

    jemalloc consumes approximately 70% of the resulting executable (on x86_64 OS X).

  7. XMPPwocky commented on Feb 12, 2015

    @XMPPwocky
    ContributorAuthor

    @steveklabnik This is also a performance-related change, and should be backwards- and forwards- compatible (can only tell it's there by examining performance or jemalloc instrumentation; otherwise you can remove it or add it and nobody's the wiser.).

  8. added
    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.
    on Feb 13, 2015
  9. XMPPwocky commented on Feb 13, 2015

    @XMPPwocky
    ContributorAuthor

    This would fix many of the issues caused by #13996 , as allocation functions are automatically marked noalias.

  10. XMPPwocky commented on Feb 13, 2015

    @XMPPwocky
    ContributorAuthor
  11. alexchandel commented on Feb 14, 2015

    @alexchandel

    @XMPPwocky Please put this in a PR! The fix is so simple, we can safely apply it to our branch. It solves the here-and-now problem, it doesn't require us to address custom allocators first, and it doesn't fundamentally change the language—just the optimization capabilities of our implementation. It can even be applied to a future stable release like LLVM 3.6, should that happen before Rust 1.0. True, the librustc available from rust-lang.org wouldn't be statically linked against an unmodified, stable release of LLVM, but the gains speak for themselves.

  12. XMPPwocky commented on Feb 17, 2015

    @XMPPwocky
    ContributorAuthor

    rust-lang/llvm#37 has been merged.

  13. dotdash commented on Feb 18, 2015

    @dotdash
    Contributor

    JFYI, I'll make a PR to update LLVM to 3.6 RC4 once it's tagged (probably tomorrow). That will include the patch from rust-lang/llvm#37, no need for a dedicated PR to update LLVM just for this.

  14. added a commit that references this issue on Feb 19, 2015
    d6d405e
  15. 1 remaining item

  16. added a commit that references this issue on Feb 21, 2015
    6957bb6
  17. added 9 commits that reference this issue on Feb 21, 2015
    1ce1596
    7394bd2
    c4fe7d6
  18. added a commit that references this issue on May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.I-slowIssue: Problems and improvements with respect to performance of generated code.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions