Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Force the WASM bundle back to size-optimized codegen.
#
# `[profile.release]` (in the workspace Cargo.toml) is `opt-level = 3` so native
# binaries (CLI, server, MCP, pysimlin's libsimlin, C FFI) optimize for speed.
# The browser WASM bundle is dominated by download size, not CPU, so we override
# the opt-level for the wasm32 target here. Keying this on the *target* (rather
# than passing a flag in each build script) means every wasm build path -- the
# `cargo build --target wasm32-unknown-unknown` in src/engine/build.sh, any
# future wasm-pack invocation, etc. -- stays size-optimized automatically.
#
# Caveat: a `RUSTFLAGS` *environment variable* takes precedence over and replaces
# these target rustflags (Cargo does not merge the two). Today only the asan test
# scripts set RUSTFLAGS, and they build for the host, so the wasm bundle is
# unaffected. Do not set RUSTFLAGS during a wasm release build or it will pick up
# opt-level 3.
[target.wasm32-unknown-unknown]
rustflags = ["-C", "opt-level=z"]
21 changes: 21 additions & 0 deletions Cargo.lock

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

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ members = [
"src/xmutil",
]

# Native release builds optimize for speed (opt-level = 3). The WASM bundle,
# where download size dominates, is forced back to opt-level = "z" via
# `.cargo/config.toml` ([target.wasm32-unknown-unknown] rustflags), which is
# keyed on the target rather than the build invocation so every wasm build path
# stays size-optimized. Measured on C-LEARN: opt-level 3 vs "z" is ~-30% compile
# and ~-41% simulate on native (see docs/design/engine-performance.md).
[profile.release]
opt-level = "z"
opt-level = 3
lto = true
panic = "abort"
strip = true
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- [architecture.md](architecture.md) -- Component descriptions, dependency graph, project structure
- [design/2026-02-21-incremental-compilation.md](design/2026-02-21-incremental-compilation.md) -- Incremental compilation via salsa: symbolic bytecode, per-variable tracking, LTM integration
- [design/engine-performance.md](design/engine-performance.md) -- Engine compile/simulate profile (C-LEARN), implemented optimizations, and remaining proposals
- [design/ltm--loops-that-matter.md](design/ltm--loops-that-matter.md) -- LTM implementation design: data structures, synthetic variables, module handling
- [design/mdl-parser.md](design/mdl-parser.md) -- Vensim MDL parser design history and implementation notes
- [design/vdf.md](design/vdf.md) -- VDF binary format specification and parser design
Expand Down
314 changes: 314 additions & 0 deletions docs/design/engine-performance.md

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/libsimlin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ default = []
debug-derive = ["simlin-engine/debug-derive"]
file_io = ["simlin-engine/file_io"]
ext_data = ["simlin-engine/ext_data"]
# Use mimalloc as the global allocator. Off by default; enabled by native
# consumers of the cdylib/staticlib (pysimlin via cffi, C/C++ FFI) where the
# allocation-heavy engine compile path benefits. Never enabled for the wasm32
# bundle (the wasm build uses --no-default-features), and the global_allocator
# is additionally cfg'd off for wasm32 in lib.rs as belt-and-suspenders.
mimalloc = ["dep:mimalloc"]

[dependencies]
simlin-engine = { version = "0.1", path = "../simlin-engine", default-features = false, features = ["png_render"] }
prost = "0.14"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
anyhow = "1.0"
mimalloc = { version = "0.1", optional = true }

[dev-dependencies]

Expand Down
11 changes: 11 additions & 0 deletions src/libsimlin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@
//! Shared types (enums, structs, helpers) live here in `lib.rs` and are
//! imported by the modules via `crate::`.

// Native consumers of this cdylib/staticlib (pysimlin via cffi, C/C++ FFI) opt
// into mimalloc with the `mimalloc` feature: the engine compile path is
// allocation-heavy (millions of small, short-lived allocations) and mimalloc
// roughly halves allocator time vs the system malloc. Never enabled for the
// wasm32 bundle. See docs/design/engine-performance.md. This is the Rust global
// allocator and is independent of the `simlin_malloc`/`simlin_free`
// cross-boundary helpers in `memory`.
#[cfg(all(feature = "mimalloc", not(target_arch = "wasm32")))]
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;

use anyhow::{Error as AnyError, Result};
use simlin_engine::{self as engine};
use std::collections::HashMap;
Expand Down
6 changes: 4 additions & 2 deletions src/pysimlin/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
.PHONY: all build test clean install dev lint type-check

# Build the libsimlin library
# Build the libsimlin library. mimalloc: the engine compile path is
# allocation-heavy and mimalloc roughly halves allocator time on native builds
# (see docs/design/engine-performance.md).
build-lib:
cd ../libsimlin && cargo build --release
cd ../libsimlin && cargo build --release --features mimalloc

# Build the Python package
build: build-lib
Expand Down
6 changes: 4 additions & 2 deletions src/pysimlin/scripts/build_wheels.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ def build_libsimlin() -> Path:
project_root = Path(__file__).parent.parent.parent.parent
libsimlin_dir = project_root / "libsimlin"

# Build the library
# Build the library. The mimalloc feature swaps in mimalloc as the global
# allocator: the engine compile path is allocation-heavy and mimalloc roughly
# halves allocator time on native builds (docs/design/engine-performance.md).
subprocess.run(
["cargo", "build", "--release"],
["cargo", "build", "--release", "--features", "mimalloc"],
cwd=libsimlin_dir,
check=True
)
Expand Down
6 changes: 5 additions & 1 deletion src/simlin-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ clap = { version = "4", features = ["derive"] }
stringreader = "0.1"
sha2 = "0.10"
simlin-engine = { version = "0.1", path = "../simlin-engine", features = ["file_io"] }
simlin = { version = "0.1", path = "../libsimlin" }
# `mimalloc` installs mimalloc as the process global allocator (this binary runs
# the allocation-heavy engine compile path). Routed through libsimlin rather than
# a direct dep + local `#[global_allocator]` so there is exactly one global
# allocator in this artifact even under `cargo clippy --all-features`.
simlin = { version = "0.1", path = "../libsimlin", features = ["mimalloc"] }
8 changes: 8 additions & 0 deletions src/simlin-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
// Use of this source code is governed by the Apache License,
// Version 2.0, that can be found in the LICENSE file.

// mimalloc on native builds (the engine compile path is allocation-heavy;
// mimalloc roughly halves allocator time -- see docs/design/engine-performance.md)
// comes via the `simlin/mimalloc` feature on the libsimlin dependency, which
// installs the global allocator. We deliberately do NOT declare a second
// `#[global_allocator]` here: this binary links libsimlin, and two global
// allocators in one artifact is a compile error (notably under
// `cargo clippy --all-features`, which enables libsimlin's feature).

use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::path::PathBuf;
Expand Down
Loading
Loading