Skip to content

Commit 5c3e644

Browse files
authored
Merge 8e8849c into e2e601d
2 parents e2e601d + 8e8849c commit 5c3e644

File tree

20 files changed

+329
-0
lines changed

20 files changed

+329
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ __pycache__/
1515
/fuzz/artifacts
1616
/fuzz/coverage
1717
/fuzz/Cargo.lock
18+
.mypy_cache/
19+
.pytest_cache/

Cargo.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[workspace]
22
members = [
3+
"allocator",
4+
"allocator/mimalloc-sys",
35
"compiler/qsc",
46
"compiler/qsc_ast",
57
"compiler/qsc_codegen",

allocator/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "allocator"
3+
authors.workspace = true
4+
homepage.workspace = true
5+
repository.workspace = true
6+
edition.workspace = true
7+
license.workspace = true
8+
version.workspace = true
9+
10+
[dependencies]
11+
mimalloc-sys = { path = "./mimalloc-sys" }
12+
13+
[lints]
14+
workspace = true
15+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
cmake_minimum_required(VERSION 3.10.0)
5+
6+
# Copy the command line arguments to a cache variable so that they can be used
7+
# with the inner project. This is needed because the inner project
8+
# needs to use the same configuration and the command line arguments are not
9+
# passed to the inner project.
10+
# This also manifests itself in apple silicon systems where the inner project
11+
# defaults to x86_64 even if the outer project is arm64.
12+
# This needs to be done before the project command is called.
13+
if (NOT ALLOCATOR_CMAKE_CL_ARGS)
14+
# get all cache variables
15+
get_cmake_property(vars CACHE_VARIABLES)
16+
foreach(var ${vars})
17+
get_property(currentHelpString CACHE "${var}" PROPERTY HELPSTRING)
18+
# only add the cache variable to the list if it is set on the command line
19+
if("${currentHelpString}" MATCHES "No help, variable specified on the command line." OR "${currentHelpString}" STREQUAL "")
20+
message ("${var} = [${${var}}] -- ${currentHelpString}")
21+
list(APPEND ALLOCATOR_CMAKE_CL_ARGS "-D${var}=${${var}}")
22+
endif()
23+
endforeach()
24+
# cache the command line arguments
25+
set(ALLOCATOR_CMAKE_CL_ARGS ${ALLOCATOR_CMAKE_CL_ARGS} CACHE STRING "comment")
26+
endif ()
27+
28+
project(allocator_external)
29+
include(ExternalProject)
30+
31+
ExternalProject_Add(mimalloc
32+
GIT_REPOSITORY https://github.com/microsoft/mimalloc.git
33+
GIT_TAG $ENV{ALLOCATOR_MIMALLOC_TAG}
34+
GIT_SHALLOW TRUE
35+
GIT_PROGRESS TRUE
36+
CMAKE_ARGS ${ALLOCATOR_CMAKE_CL_ARGS}
37+
USES_TERMINAL_DOWNLOAD TRUE
38+
USES_TERMINAL_CONFIGURE TRUE
39+
USES_TERMINAL_BUILD TRUE
40+
USES_TERMINAL_INSTALL TRUE
41+
)

allocator/mimalloc-sys/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "mimalloc-sys"
3+
build = "build.rs"
4+
links = "mimalloc"
5+
authors.workspace = true
6+
homepage.workspace = true
7+
repository.workspace = true
8+
edition.workspace = true
9+
license.workspace = true
10+
version.workspace = true
11+
12+
[dependencies]
13+
14+
[lints]
15+
workspace = true
16+
17+
[build-dependencies]
18+
cmake = "0.1"
19+
cc = "1.0"
20+

allocator/mimalloc-sys/build.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use std::boxed::Box;
5+
use std::env;
6+
use std::error::Error;
7+
use std::fs;
8+
use std::path::PathBuf;
9+
10+
use cmake::Config;
11+
12+
// 1.8.2
13+
static ALLOCATOR_MIMALLOC_TAG: &str = "b66e3214d8a104669c2ec05ae91ebc26a8f5ab78";
14+
// 2.1.2
15+
//static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";
16+
17+
fn main() -> Result<(), Box<dyn Error>> {
18+
println!("cargo:rerun-if-changed=build.rs");
19+
println!("cargo:rerun-if-changed=CMakeLists.txt");
20+
21+
compile_mimalloc()?;
22+
23+
Ok(())
24+
}
25+
26+
fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
27+
let build_dir = get_build_dir()?;
28+
let mut config = Config::new(build_dir);
29+
30+
config
31+
.build_target("mimalloc")
32+
.define("CMAKE_BUILD_TYPE", "MinSizeRel")
33+
.define("MI_INSTALL_TOPLEVEL", "ON")
34+
.env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG)
35+
.static_crt(true)
36+
.very_verbose(true);
37+
38+
let dst = config.build();
39+
println!(
40+
"cargo:rustc-link-search=native={}",
41+
dst.join("lib").display()
42+
);
43+
println!(
44+
"cargo:rustc-link-search=static={}",
45+
dst.join("lib").display()
46+
);
47+
println!("cargo:rustc-link-lib=static=mimalloc");
48+
49+
Ok(())
50+
}
51+
52+
fn get_build_dir() -> Result<PathBuf, Box<dyn Error>> {
53+
let manifest_dir = env::var("CARGO_MANIFEST_DIR")?;
54+
let build_dir = PathBuf::from(manifest_dir.as_str());
55+
let normalized_build_dir = fs::canonicalize(build_dir)?;
56+
Ok(normalized_build_dir)
57+
}

allocator/mimalloc-sys/src/lib.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use core::ffi::c_void;
5+
pub static MI_ALIGNMENT_MAX: usize = 1024 * 1024; // 1 MiB
6+
7+
extern "C" {
8+
/// Allocate size bytes aligned by alignment.
9+
/// size: the number of bytes to allocate
10+
/// alignment: the minimal alignment of the allocated memory. Must be less than MI_ALIGNMENT_MAX
11+
/// returns: a pointer to the allocated memory, or null if out of memory. The returned pointer is aligned by alignment
12+
pub fn mi_malloc_aligned(size: usize, alignment: usize) -> *mut c_void;
13+
pub fn mi_zalloc_aligned(size: usize, alignment: usize) -> *mut c_void;
14+
15+
/// Free previously allocated memory.
16+
/// The pointer p must have been allocated before (or be nullptr).
17+
/// p: the pointer to the memory to free or nullptr
18+
pub fn mi_free(p: *mut c_void);
19+
pub fn mi_realloc_aligned(p: *mut c_void, newsize: usize, alignment: usize) -> *mut c_void;
20+
}
21+
22+
#[cfg(test)]
23+
mod tests {
24+
use super::*;
25+
26+
#[test]
27+
fn memory_can_be_allocated_and_freed() {
28+
let ptr = unsafe { mi_malloc_aligned(8, 8) }.cast::<u8>();
29+
assert!(!ptr.cast::<c_void>().is_null());
30+
unsafe { mi_free(ptr.cast::<c_void>()) };
31+
}
32+
33+
#[test]
34+
fn memory_can_be_allocated_zeroed_and_freed() {
35+
let ptr = unsafe { mi_zalloc_aligned(8, 8) }.cast::<u8>();
36+
assert!(!ptr.cast::<c_void>().is_null());
37+
unsafe { mi_free(ptr.cast::<c_void>()) };
38+
}
39+
40+
#[test]
41+
fn memory_can_be_reallocated_and_freed() {
42+
let ptr = unsafe { mi_malloc_aligned(8, 8) }.cast::<u8>();
43+
assert!(!ptr.cast::<c_void>().is_null());
44+
let realloc_ptr = unsafe { mi_realloc_aligned(ptr.cast::<c_void>(), 8, 8) }.cast::<u8>();
45+
assert!(!realloc_ptr.cast::<c_void>().is_null());
46+
unsafe { mi_free(ptr.cast::<c_void>()) };
47+
}
48+
}

allocator/src/lib.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use core::alloc::{GlobalAlloc, Layout};
5+
use core::ffi::c_void;
6+
7+
use mimalloc_sys::{mi_free, mi_malloc_aligned, mi_realloc_aligned, mi_zalloc_aligned};
8+
9+
pub struct Mimalloc;
10+
11+
unsafe impl GlobalAlloc for Mimalloc {
12+
#[inline]
13+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
14+
debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
15+
mi_malloc_aligned(layout.size(), layout.align()).cast::<u8>()
16+
}
17+
18+
#[inline]
19+
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
20+
mi_free(ptr.cast::<c_void>());
21+
}
22+
23+
#[inline]
24+
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
25+
debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
26+
mi_zalloc_aligned(layout.size(), layout.align()).cast::<u8>()
27+
}
28+
29+
#[inline]
30+
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
31+
debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
32+
mi_realloc_aligned(ptr.cast::<c_void>(), new_size, layout.align()).cast::<u8>()
33+
}
34+
}
35+
36+
#[cfg(test)]
37+
mod tests {
38+
use super::*;
39+
use std::error::Error;
40+
41+
#[test]
42+
fn memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
43+
let layout = Layout::from_size_align(8, 8)?;
44+
let alloc = Mimalloc;
45+
46+
unsafe {
47+
let ptr = alloc.alloc(layout);
48+
assert!(!ptr.cast::<c_void>().is_null());
49+
alloc.dealloc(ptr, layout);
50+
}
51+
Ok(())
52+
}
53+
54+
#[test]
55+
fn memory_can_be_alloc_zeroed_and_freed() -> Result<(), Box<dyn Error>> {
56+
let layout = Layout::from_size_align(8, 8)?;
57+
let alloc = Mimalloc;
58+
59+
unsafe {
60+
let ptr = alloc.alloc_zeroed(layout);
61+
assert!(!ptr.cast::<c_void>().is_null());
62+
alloc.dealloc(ptr, layout);
63+
}
64+
Ok(())
65+
}
66+
67+
#[test]
68+
fn large_chunks_of_memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
69+
let layout = Layout::from_size_align(2 * 1024 * 1024 * 1024, 8)?;
70+
let alloc = Mimalloc;
71+
72+
unsafe {
73+
let ptr = alloc.alloc(layout);
74+
assert!(!ptr.cast::<c_void>().is_null());
75+
alloc.dealloc(ptr, layout);
76+
}
77+
Ok(())
78+
}
79+
}

build.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ def use_python_env(folder):
403403
"-m",
404404
"pip",
405405
"wheel",
406+
"--verbose",
406407
"--wheel-dir",
407408
wheels_dir,
408409
jupyterlab_src,

0 commit comments

Comments
 (0)