Skip to content

Commit

Permalink
Merge ed83a4a into e2e601d
Browse files Browse the repository at this point in the history
  • Loading branch information
idavis authored Mar 12, 2024
2 parents e2e601d + ed83a4a commit fc1ff57
Show file tree
Hide file tree
Showing 20 changed files with 338 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ __pycache__/
/fuzz/artifacts
/fuzz/coverage
/fuzz/Cargo.lock
.mypy_cache/
.pytest_cache/
27 changes: 27 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[workspace]
members = [
"allocator",
"allocator/mimalloc-sys",
"compiler/qsc",
"compiler/qsc_ast",
"compiler/qsc_codegen",
Expand Down
15 changes: 15 additions & 0 deletions allocator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "allocator"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
license.workspace = true
version.workspace = true

[dependencies]
mimalloc-sys = { path = "./mimalloc-sys" }

[lints]
workspace = true

23 changes: 23 additions & 0 deletions allocator/mimalloc-sys/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

cmake_minimum_required(VERSION 3.10.0)


project(allocator_external)
include(ExternalProject)

ExternalProject_Add(mimalloc
GIT_REPOSITORY https://github.com/microsoft/mimalloc.git
GIT_TAG $ENV{ALLOCATOR_MIMALLOC_TAG}
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
USES_TERMINAL_DOWNLOAD TRUE
USES_TERMINAL_CONFIGURE TRUE
USES_TERMINAL_BUILD TRUE
USES_TERMINAL_INSTALL TRUE
)
20 changes: 20 additions & 0 deletions allocator/mimalloc-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "mimalloc-sys"
build = "build.rs"
links = "mimalloc"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
license.workspace = true
version.workspace = true

[dependencies]

[lints]
workspace = true

[build-dependencies]
cmake = "0.1"
cc = "1.0"

84 changes: 84 additions & 0 deletions allocator/mimalloc-sys/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use std::boxed::Box;
use std::env;
use std::error::Error;
use std::fs;
use std::path::{Path, PathBuf};

use cmake::Config;

// 1.8.2
//static ALLOCATOR_MIMALLOC_TAG: &str = "b66e3214d8a104669c2ec05ae91ebc26a8f5ab78";
// 2.1.2
static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";

fn main() -> Result<(), Box<dyn Error>> {
let dst = download_mimalloc()?;
compile_mimalloc(&dst);
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=CMakeLists.txt");
Ok(())
}

// Compile mimalloc source code and link it to the crate.
// The cc crate is used to compile the source code into a static library.
// The cmake crate is used to download the source code and stage it in the build directory.
// We don't use the cmake crate to compile the source code because the mimalloc build system
// loads extra libraries, changes the name and path around, and does other things that are
// difficult to handle. The cc crate is much simpler and more predictable.
fn compile_mimalloc(dst: &Path) {
let src_dir = dst
.join("build")
.join("mimalloc-prefix")
.join("src")
.join("mimalloc");

let mut build = cc::Build::new();

build.include(src_dir.join("include"));
build.include(src_dir.join("src"));
build.file(src_dir.join("src/static.c"));

if build.get_compiler().is_like_msvc() {
build.cpp(true);
build.static_crt(true);
}
// turn off debug mode
build.define("MI_DEBUG", "0");

// turning on optimizations doesn't seem to make a difference
//build.opt_level(3);

build.compile("mimalloc");

println!(
"cargo:rustc-link-search=native={}",
dst.join("lib").display()
);
println!("cargo:rustc-link-lib=static=mimalloc");
}

// Use cmake to download mimallloc source code and stage
// it in the build directory.
fn download_mimalloc() -> Result<PathBuf, Box<dyn Error>> {
let build_dir = get_build_dir()?;
let mut config = Config::new(build_dir);

config
.no_build_target(true)
.env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG)
.very_verbose(true);

let dst = config.build();

Ok(dst)
}

fn get_build_dir() -> Result<PathBuf, Box<dyn Error>> {
let manifest_dir = env::var("CARGO_MANIFEST_DIR")?;
let build_dir = PathBuf::from(manifest_dir.as_str());
let normalized_build_dir = fs::canonicalize(build_dir)?;
Ok(normalized_build_dir)
}
48 changes: 48 additions & 0 deletions allocator/mimalloc-sys/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use core::ffi::c_void;
pub static MI_ALIGNMENT_MAX: usize = 1024 * 1024; // 1 MiB

extern "C" {
/// Allocate size bytes aligned by alignment.
/// size: the number of bytes to allocate
/// alignment: the minimal alignment of the allocated memory. Must be less than MI_ALIGNMENT_MAX
/// returns: a pointer to the allocated memory, or null if out of memory. The returned pointer is aligned by alignment
pub fn mi_malloc_aligned(size: usize, alignment: usize) -> *mut c_void;
pub fn mi_zalloc_aligned(size: usize, alignment: usize) -> *mut c_void;

/// Free previously allocated memory.
/// The pointer p must have been allocated before (or be nullptr).
/// p: the pointer to the memory to free or nullptr
pub fn mi_free(p: *mut c_void);
pub fn mi_realloc_aligned(p: *mut c_void, newsize: usize, alignment: usize) -> *mut c_void;
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn memory_can_be_allocated_and_freed() {
let ptr = unsafe { mi_malloc_aligned(8, 8) }.cast::<u8>();
assert!(!ptr.cast::<c_void>().is_null());
unsafe { mi_free(ptr.cast::<c_void>()) };
}

#[test]
fn memory_can_be_allocated_zeroed_and_freed() {
let ptr = unsafe { mi_zalloc_aligned(8, 8) }.cast::<u8>();
assert!(!ptr.cast::<c_void>().is_null());
unsafe { mi_free(ptr.cast::<c_void>()) };
}

#[test]
fn memory_can_be_reallocated_and_freed() {
let ptr = unsafe { mi_malloc_aligned(8, 8) }.cast::<u8>();
assert!(!ptr.cast::<c_void>().is_null());
let realloc_ptr = unsafe { mi_realloc_aligned(ptr.cast::<c_void>(), 8, 8) }.cast::<u8>();
assert!(!realloc_ptr.cast::<c_void>().is_null());
unsafe { mi_free(ptr.cast::<c_void>()) };
}
}
79 changes: 79 additions & 0 deletions allocator/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use core::alloc::{GlobalAlloc, Layout};
use core::ffi::c_void;

use mimalloc_sys::{mi_free, mi_malloc_aligned, mi_realloc_aligned, mi_zalloc_aligned};

pub struct Mimalloc;

unsafe impl GlobalAlloc for Mimalloc {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
mi_malloc_aligned(layout.size(), layout.align()).cast::<u8>()
}

#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
mi_free(ptr.cast::<c_void>());
}

#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
mi_zalloc_aligned(layout.size(), layout.align()).cast::<u8>()
}

#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
mi_realloc_aligned(ptr.cast::<c_void>(), new_size, layout.align()).cast::<u8>()
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;

#[test]
fn memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
let layout = Layout::from_size_align(8, 8)?;
let alloc = Mimalloc;

unsafe {
let ptr = alloc.alloc(layout);
assert!(!ptr.cast::<c_void>().is_null());
alloc.dealloc(ptr, layout);
}
Ok(())
}

#[test]
fn memory_can_be_alloc_zeroed_and_freed() -> Result<(), Box<dyn Error>> {
let layout = Layout::from_size_align(8, 8)?;
let alloc = Mimalloc;

unsafe {
let ptr = alloc.alloc_zeroed(layout);
assert!(!ptr.cast::<c_void>().is_null());
alloc.dealloc(ptr, layout);
}
Ok(())
}

#[test]
fn large_chunks_of_memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
let layout = Layout::from_size_align(2 * 1024 * 1024 * 1024, 8)?;
let alloc = Mimalloc;

unsafe {
let ptr = alloc.alloc(layout);
assert!(!ptr.cast::<c_void>().is_null());
alloc.dealloc(ptr, layout);
}
Ok(())
}
}
1 change: 1 addition & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ def use_python_env(folder):
"-m",
"pip",
"wheel",
"--verbose",
"--wheel-dir",
wheels_dir,
jupyterlab_src,
Expand Down
3 changes: 3 additions & 0 deletions compiler/qsc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ qsc_project = { path = "../qsc_project", features = ["fs"] }
rustc-hash = { workspace = true }
thiserror = { workspace = true }

[target.'cfg(not(any(target_family = "wasm")))'.dependencies]
allocator = { path = "../../allocator" }

[dev-dependencies]
criterion = { workspace = true, features = ["cargo_bench_support"] }
expect-test = { workspace = true }
Expand Down
4 changes: 4 additions & 0 deletions compiler/qsc/benches/eval.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#[cfg(not(target_family = "wasm"))]
#[global_allocator]
static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;

use criterion::{criterion_group, criterion_main, Criterion};
use indoc::indoc;
use qsc::{interpret::Interpreter, PackageType};
Expand Down
4 changes: 4 additions & 0 deletions compiler/qsc/benches/large.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#[cfg(not(target_family = "wasm"))]
#[global_allocator]
static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;

use criterion::{criterion_group, criterion_main, Criterion};
use qsc::compile::{self, compile};
use qsc_data_structures::language_features::LanguageFeatures;
Expand Down
Loading

0 comments on commit fc1ff57

Please sign in to comment.