Skip to content

Commit 2a0b4ae

Browse files
authored
feat! Mimalloc as the default allocator (microsoft#434)
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 microsoft#297 Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
1 parent 6c53382 commit 2a0b4ae

59 files changed

Lines changed: 17039 additions & 328 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

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

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ http = []
3232
glob = ["dep:globset"]
3333
graph = []
3434
jsonschema = ["dep:jsonschema"]
35+
mimalloc = ["dep:mimalloc"]
3536
net = []
3637
no_std = ["lazy_static/spin_no_std"]
3738
opa-runtime = []
@@ -51,6 +52,7 @@ full-opa = [
5152
"hex",
5253
"http",
5354
"jsonschema",
55+
"mimalloc",
5456
"net",
5557
"opa-runtime",
5658
"regex",
@@ -114,6 +116,7 @@ rand = { version = "0.9.0", default-features = false, features = ["thread_rng"],
114116
# Causes the project to link with the Spectre-mitigated CRT and libs.
115117
msvc_spectre_libs = { version = "0.1", features = ["error"], optional = true }
116118
dashmap = { version = "6.1", default-features = false, optional = true }
119+
mimalloc = { path = "mimalloc", optional = true }
117120

118121
[dev-dependencies]
119122
anyhow = "1.0.45"
@@ -170,6 +173,10 @@ name = "compiled_policy_evaluation_benchmark"
170173
path = "benches/evaluation/compiled_policy_evaluation_benchmark.rs"
171174
harness = false
172175

176+
[[bench]]
177+
name = "aci_benchmark"
178+
harness = false
179+
173180
[[example]]
174181
name="regorus"
175182
harness=false

benches/aci_benchmark.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
use regorus::{Engine, Value};
4+
5+
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
6+
use serde::{Deserialize, Serialize};
7+
use walkdir::WalkDir;
8+
9+
use std::path::Path;
10+
11+
#[derive(Serialize, Deserialize, PartialEq, Debug)]
12+
struct TestCase {
13+
note: String,
14+
data: Value,
15+
input: Value,
16+
modules: Vec<String>,
17+
query: String,
18+
want_result: Value,
19+
}
20+
21+
#[derive(Serialize, Deserialize, PartialEq, Debug)]
22+
struct YamlTest {
23+
cases: Vec<TestCase>,
24+
}
25+
26+
fn aci_policy_eval(c: &mut Criterion) {
27+
let dir = Path::new("tests/aci");
28+
for entry in WalkDir::new(dir)
29+
.sort_by_file_name()
30+
.into_iter()
31+
.filter_map(|e| e.ok())
32+
{
33+
let path = entry.path();
34+
if !path.to_string_lossy().ends_with(".yaml") {
35+
continue;
36+
}
37+
38+
let yaml = std::fs::read(path).expect("failed to read yaml test");
39+
let yaml = String::from_utf8_lossy(&yaml);
40+
let test: YamlTest = serde_yaml::from_str(&yaml).expect("failed to deserialize yaml test");
41+
42+
for case in &test.cases {
43+
let rule = case.query.replace("=x", "");
44+
c.bench_with_input(
45+
BenchmarkId::new("case ", format!("{} {}", &case.note, &rule)),
46+
&case,
47+
|b, case| {
48+
let mut engine = Engine::new();
49+
engine.set_rego_v0(true);
50+
51+
engine
52+
.add_data(case.data.clone())
53+
.expect("failed to add data");
54+
engine.set_input(case.input.clone());
55+
56+
for (idx, rego) in case.modules.iter().enumerate() {
57+
if rego.ends_with(".rego") {
58+
let path = dir.join(rego);
59+
let path = path.to_str().expect("not a valid path");
60+
engine
61+
.add_policy_from_file(path)
62+
.expect("failed to add policy");
63+
} else {
64+
engine
65+
.add_policy(format!("rego{idx}.rego"), rego.clone())
66+
.expect("failed to add policy");
67+
}
68+
}
69+
70+
b.iter(|| {
71+
engine.eval_rule(rule.clone()).unwrap();
72+
})
73+
},
74+
);
75+
}
76+
}
77+
}
78+
79+
criterion_group!(aci_benches, aci_policy_eval);
80+
criterion_main!(aci_benches);

0 commit comments

Comments
 (0)