-
Notifications
You must be signed in to change notification settings - Fork 349
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
cbits: integrate mimalloc as a default memory allocator #2717
Open
thoughtpolice
wants to merge
5
commits into
main
Choose a base branch
from
aseipp/push-mupwvrwmxuvm
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
aa5bd00
cbits: initialize new `jj-cbits` library
thoughtpolice d177aa3
cbits: import and build mimalloc v2.1.2
thoughtpolice 5d5468f
cbits: implement `MiMalloc` for use with `#[global_allocator]`
thoughtpolice a55d004
cli: use mimalloc from `jj-cbits` as the default memory allocator
thoughtpolice 42e16ba
cli: global `--show-heap-stats` argument for EOL heap stats
thoughtpolice File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[package] | ||
name = "jj-cbits" | ||
description = "FFI code needed by Jujutsu - an experimental version control system" | ||
|
||
version = { workspace = true } | ||
edition = { workspace = true } | ||
rust-version = { workspace = true } | ||
license = { workspace = true } | ||
homepage = { workspace = true } | ||
repository = { workspace = true } | ||
documentation = { workspace = true } | ||
readme = { workspace = true } | ||
|
||
[dependencies] | ||
libc = { workspace = true } | ||
|
||
[build-dependencies] | ||
cc = { workspace = true } | ||
|
||
[features] | ||
default = [] | ||
mimalloc = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use std::env; | ||
|
||
#[allow(dead_code)] | ||
fn new_cc_builder() -> (String, bool) { | ||
let opt_level = env::var("OPT_LEVEL").unwrap_or_else(|_| String::from("1")); | ||
let is_debug = opt_level == "0"; | ||
|
||
// NOTE (aseipp): on Linux, many distros enable hardening options like | ||
// -D_FORTIFY_SOURCE=2 in their C toolchains by default, and so if compiling | ||
// with -O0, the standard header libraries throw ugly warnings about how | ||
// no-optimization causes _FORTIFY_SOURCE to not work. | ||
// | ||
// instead, just detect when the Rust toolchain sets OPT_LEVEL=0 (default | ||
// debug/test profile), and then set it to debug instead. | ||
let c_opt_level = if is_debug { "g" } else { opt_level.as_str() }; | ||
|
||
(c_opt_level.to_owned(), is_debug) | ||
} | ||
|
||
#[allow(dead_code)] | ||
fn build_mimalloc() { | ||
let (c_opt_level, is_debug) = new_cc_builder(); | ||
cc::Build::new() | ||
.include("cbits/mimalloc/include") | ||
.include("cbits/mimalloc/src") | ||
// Use the (convenient) amalgamation. | ||
.file("cbits/mimalloc/src/static.c") | ||
// In some configurations, there may be unused parameters. Suppress | ||
// them in cargo build output | ||
.flag_if_supported("-Wno-unused-parameter") | ||
// MI_SECURE implies four levels of hardening: | ||
// | ||
// - MI_SECURE=1: guard page around metadata | ||
// - MI_SECURE=2: guard page around each mimalloc page | ||
// - MI_SECURE=3: encoded freelists (corrupt freelist, invalid free) | ||
// - MI_SECURE=4: double free (may be more expensive) | ||
// | ||
// by default, against glibc 2.38, MI_SECURE=0 gives anywhere from 5-18% | ||
// performance uplift for free. MI_SECURE=1 gives about a 7% uplift, | ||
// while 2,3,4 all basically yield ~zero meaningful uplift in the ~1% | ||
// range, i.e. even the most secure version of mimalloc is still | ||
// baseline competitive. | ||
// | ||
// for jj, in non-debug configs, we set MI_SECURE=0. the goal is to | ||
// inevitably banish most C code to the shadow realm, and to the extent | ||
// we can't, it should be located here. since most Rust code will be | ||
// both int and buffer overflow-safe, that mitigates some of the need | ||
// for features like UAF and guard pages. on the other hand, we enable | ||
// those features in debug builds, since rust performance already takes | ||
// a massive hit in debug mode; with nextest these options have ~zero | ||
// visible impact on the test suite, it seems. and we want to make sure | ||
// we can catch as many bugs as possible. | ||
.define("MI_SECURE", if is_debug { "4" } else { "0" }) | ||
// Disable debug assertions. | ||
.define("MI_DEBUG", if is_debug { "1" } else { "0" }) | ||
// Enable statistics tracking. 0 is disabled, 1 is enabled, and 2 is | ||
// detailed info. 2 causes a ~5% performance hit. | ||
.define("MI_STAT", "2") | ||
// Enable the proper optimization level for the library | ||
.opt_level_str(&c_opt_level) | ||
// Build | ||
.compile("jj-mimalloc"); | ||
} | ||
|
||
fn main() { | ||
#[cfg(feature = "mimalloc")] | ||
build_mimalloc(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Vendored C code | ||
|
||
Put every separate project here under its own directory. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* ---------------------------------------------------------------------------- | ||
Copyright (c) 2018-2020 Microsoft Research, Daan Leijen | ||
This is free software; you can redistribute it and/or modify it under the | ||
terms of the MIT license. A copy of the license can be found in the file | ||
"LICENSE" at the root of this distribution. | ||
-----------------------------------------------------------------------------*/ | ||
#pragma once | ||
#ifndef MIMALLOC_NEW_DELETE_H | ||
#define MIMALLOC_NEW_DELETE_H | ||
|
||
// ---------------------------------------------------------------------------- | ||
// This header provides convenient overrides for the new and | ||
// delete operations in C++. | ||
// | ||
// This header should be included in only one source file! | ||
// | ||
// On Windows, or when linking dynamically with mimalloc, these | ||
// can be more performant than the standard new-delete operations. | ||
// See <https://en.cppreference.com/w/cpp/memory/new/operator_new> | ||
// --------------------------------------------------------------------------- | ||
#if defined(__cplusplus) | ||
#include <new> | ||
#include <mimalloc.h> | ||
|
||
#if defined(_MSC_VER) && defined(_Ret_notnull_) && defined(_Post_writable_byte_size_) | ||
// stay consistent with VCRT definitions | ||
#define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict _Ret_notnull_ _Post_writable_byte_size_(n) | ||
#define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(n) | ||
#else | ||
#define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict | ||
#define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict | ||
#endif | ||
|
||
void operator delete(void* p) noexcept { mi_free(p); }; | ||
void operator delete[](void* p) noexcept { mi_free(p); }; | ||
|
||
void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); } | ||
void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); } | ||
|
||
mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); } | ||
mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); } | ||
|
||
mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } | ||
mi_decl_new_nothrow(n) void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } | ||
|
||
#if (__cplusplus >= 201402L || _MSC_VER >= 1916) | ||
void operator delete (void* p, std::size_t n) noexcept { mi_free_size(p,n); }; | ||
void operator delete[](void* p, std::size_t n) noexcept { mi_free_size(p,n); }; | ||
#endif | ||
|
||
#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) | ||
void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); } | ||
void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); } | ||
void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); }; | ||
void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); }; | ||
void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); } | ||
void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); } | ||
|
||
void* operator new (std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); } | ||
void* operator new[](std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); } | ||
void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); } | ||
void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); } | ||
#endif | ||
#endif | ||
|
||
#endif // MIMALLOC_NEW_DELETE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* ---------------------------------------------------------------------------- | ||
Copyright (c) 2018-2020 Microsoft Research, Daan Leijen | ||
This is free software; you can redistribute it and/or modify it under the | ||
terms of the MIT license. A copy of the license can be found in the file | ||
"LICENSE" at the root of this distribution. | ||
-----------------------------------------------------------------------------*/ | ||
#pragma once | ||
#ifndef MIMALLOC_OVERRIDE_H | ||
#define MIMALLOC_OVERRIDE_H | ||
|
||
/* ---------------------------------------------------------------------------- | ||
This header can be used to statically redirect malloc/free and new/delete | ||
to the mimalloc variants. This can be useful if one can include this file on | ||
each source file in a project (but be careful when using external code to | ||
not accidentally mix pointers from different allocators). | ||
-----------------------------------------------------------------------------*/ | ||
|
||
#include <mimalloc.h> | ||
|
||
// Standard C allocation | ||
#define malloc(n) mi_malloc(n) | ||
#define calloc(n,c) mi_calloc(n,c) | ||
#define realloc(p,n) mi_realloc(p,n) | ||
#define free(p) mi_free(p) | ||
|
||
#define strdup(s) mi_strdup(s) | ||
#define strndup(s,n) mi_strndup(s,n) | ||
#define realpath(f,n) mi_realpath(f,n) | ||
|
||
// Microsoft extensions | ||
#define _expand(p,n) mi_expand(p,n) | ||
#define _msize(p) mi_usable_size(p) | ||
#define _recalloc(p,n,c) mi_recalloc(p,n,c) | ||
|
||
#define _strdup(s) mi_strdup(s) | ||
#define _strndup(s,n) mi_strndup(s,n) | ||
#define _wcsdup(s) (wchar_t*)mi_wcsdup((const unsigned short*)(s)) | ||
#define _mbsdup(s) mi_mbsdup(s) | ||
#define _dupenv_s(b,n,v) mi_dupenv_s(b,n,v) | ||
#define _wdupenv_s(b,n,v) mi_wdupenv_s((unsigned short*)(b),n,(const unsigned short*)(v)) | ||
|
||
// Various Posix and Unix variants | ||
#define reallocf(p,n) mi_reallocf(p,n) | ||
#define malloc_size(p) mi_usable_size(p) | ||
#define malloc_usable_size(p) mi_usable_size(p) | ||
#define cfree(p) mi_free(p) | ||
|
||
#define valloc(n) mi_valloc(n) | ||
#define pvalloc(n) mi_pvalloc(n) | ||
#define reallocarray(p,s,n) mi_reallocarray(p,s,n) | ||
#define reallocarr(p,s,n) mi_reallocarr(p,s,n) | ||
#define memalign(a,n) mi_memalign(a,n) | ||
#define aligned_alloc(a,n) mi_aligned_alloc(a,n) | ||
#define posix_memalign(p,a,n) mi_posix_memalign(p,a,n) | ||
#define _posix_memalign(p,a,n) mi_posix_memalign(p,a,n) | ||
|
||
// Microsoft aligned variants | ||
#define _aligned_malloc(n,a) mi_malloc_aligned(n,a) | ||
#define _aligned_realloc(p,n,a) mi_realloc_aligned(p,n,a) | ||
#define _aligned_recalloc(p,s,n,a) mi_aligned_recalloc(p,s,n,a) | ||
#define _aligned_msize(p,a,o) mi_usable_size(p) | ||
#define _aligned_free(p) mi_free(p) | ||
#define _aligned_offset_malloc(n,a,o) mi_malloc_aligned_at(n,a,o) | ||
#define _aligned_offset_realloc(p,n,a,o) mi_realloc_aligned_at(p,n,a,o) | ||
#define _aligned_offset_recalloc(p,s,n,a,o) mi_recalloc_aligned_at(p,s,n,a,o) | ||
|
||
#endif // MIMALLOC_OVERRIDE_H |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confusing name. This doesn't seem to have anything to do with a builder.