mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
This change integrates mimalloc as the default memory allocator for Regorus, delivering significant performance improvements across all evaluation modes and language bindings. Technical Implementation: - Build mimalloc in vendored mode from C sources (following QSharp approach) - Implement GlobalAlloc trait for seamless Rust integration - Add optional 'mimalloc' feature flag for conditional compilation - Add comprehensive ACI benchmarks to measure evaluation performance Performance Impact: Rust Engine Evaluation: - Single-threaded: ~29% improvement (423 vs 328 Kelem/s) - Multi-threaded: Better scaling with reduced thread contention - Fresh engines: ~24% improvement (56 vs 45 Kelem/s) Rust Compiled Policy Evaluation: - Single-threaded: ~41% improvement (426 vs 303 Kelem/s) - Multi-threaded: Improved allocation efficiency under contention - Fresh compilation: ~26% improvement (53 vs 42 Kelem/s) C# FFI Bindings: - Engine evaluation: ~27% improvement (279 vs 219 Kelem/s) - Compiled policies: ~29% improvement (273 vs 211 Kelem/s) - Better threading characteristics through improved underlying allocation Key Benefits: - Reduced allocation-related contention in multi-threaded scenarios - More consistent performance across different thread counts - Improved memory allocation efficiency for both native Rust and FFI workloads - Better scaling characteristics for production deployments The mimalloc integration provides substantial performance gains while maintaining full compatibility with existing code through feature flags. Reference: QSharp allocator implementation (https://github.com/microsoft/qsharp/tree/main/source/allocator) Fixes #297 Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
50 lines
1.9 KiB
Rust
50 lines
1.9 KiB
Rust
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
use core::ffi::c_void;
|
|
pub static MI_ALIGNMENT_MAX: usize = 1024 * 1024; // 1 MiB
|
|
|
|
// Define core functions from mimalloc needed for the allocator
|
|
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>()) };
|
|
}
|
|
}
|