Skip to content
Closed
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
19 changes: 19 additions & 0 deletions baml_language/Cargo.lock

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

1 change: 1 addition & 0 deletions baml_language/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ bytecount = "0.6"
reqwest = { version = "0.13.1", default-features = false, features = [
"stream",
] }
mimalloc = { version = "0.1.52" }
rowan = { version = "0.16" }
rustls = { version = "0.23.37", default-features = false }
rustls-pemfile = "2"
Expand Down
1 change: 1 addition & 0 deletions baml_language/crates/baml_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ hex = { workspace = true }
indexmap = { workspace = true }
indicatif = { workspace = true }
libsui = { workspace = true }
mimalloc = { workspace = true }
object = { workspace = true }
regex = { workspace = true }
reqwest = { workspace = true, features = [ "blocking", "json", "rustls" ] }
Expand Down
7 changes: 7 additions & 0 deletions baml_language/crates/baml_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

use std::io::Write as _;

/// The compiler workload is dominated by small short-lived allocations
/// (`Ty` trees, `Vec`s, `SmolStr`s): system malloc measured ~35% of
/// remaining single-threaded CPU in the cold-compile audit. mimalloc
/// substantially cuts cold `baml check` / `baml build` wall time.
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;

fn main() {
// TODO: baml_log is disabled for now
// baml_log::init()?;
Expand Down
36 changes: 23 additions & 13 deletions baml_language/crates/baml_compiler_diagnostics/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,10 @@ pub fn render_diagnostic(
config: &RenderConfig,
) -> String {
match config.format {
DiagnosticFormat::Ariadne => render_ariadne(diagnostic, sources, file_paths, config.color),
DiagnosticFormat::Ariadne => {
let mut cache = SourceCache::new(sources.clone(), file_paths.clone());
render_ariadne(diagnostic, sources, &mut cache, config.color)
}
DiagnosticFormat::Concise => render_concise(diagnostic, sources, file_paths),
}
}
Expand All @@ -223,9 +226,20 @@ pub fn render_diagnostics(
file_paths: &HashMap<FileId, PathBuf>,
config: &RenderConfig,
) -> String {
// Build the ariadne source cache ONCE for the whole batch. Constructing
// it per diagnostic (each `Source::from` computes a line index for every
// file in the project) is quadratic in practice and measurably slows
// `baml check` on warning-heavy projects.
let mut ariadne_cache = matches!(config.format, DiagnosticFormat::Ariadne)
.then(|| SourceCache::new(sources.clone(), file_paths.clone()));
diagnostics
.iter()
.map(|d| render_diagnostic(d, sources, file_paths, config))
.map(|d| match (&config.format, &mut ariadne_cache) {
(DiagnosticFormat::Ariadne, Some(cache)) => {
render_ariadne(d, sources, cache, config.color)
}
_ => render_concise(d, sources, file_paths),
})
.collect::<Vec<_>>()
.join("\n")
}
Expand Down Expand Up @@ -259,10 +273,13 @@ fn translate_span(span: Span, sources: &HashMap<FileId, String>) -> Span {
}

/// Render a diagnostic using Ariadne (pretty CLI output).
///
/// Takes a pre-built [`SourceCache`] so batch rendering shares one line-index
/// computation across all diagnostics.
fn render_ariadne(
diagnostic: &Diagnostic,
sources: &HashMap<FileId, String>,
file_paths: &HashMap<FileId, PathBuf>,
cache: &mut SourceCache,
color: bool,
) -> String {
// BAML CLI uses lowercase `error:` / `warning:` everywhere (matching
Expand Down Expand Up @@ -321,7 +338,7 @@ fn render_ariadne(
.finish();

// Render to string using SourceCache for proper filename display.
let rendered = render_report_to_string(&report, sources, file_paths);
let rendered = render_report_to_string(&report, cache);

// See the rant above the `report_kind` match — ariadne paints the
// `Custom` keyword unconditionally, so `with_color(false)` doesn't
Expand Down Expand Up @@ -427,17 +444,10 @@ fn render_concise(
}

/// Render an ariadne Report to a String using `SourceCache` for proper filename display.
fn render_report_to_string(
report: &Report<'_, Span>,
sources: &HashMap<FileId, String>,
file_paths: &HashMap<FileId, PathBuf>,
) -> String {
fn render_report_to_string(report: &Report<'_, Span>, cache: &mut SourceCache) -> String {
let mut output = Vec::new();

// Use SourceCache for proper filename display
let mut cache = SourceCache::new(sources.clone(), file_paths.clone());

report.write(&mut cache, &mut output).unwrap_or_else(|_| {
report.write(cache, &mut output).unwrap_or_else(|_| {
output.clear();
output.extend_from_slice(b"<error rendering diagnostic>");
});
Expand Down
Loading