Skip to content

perf: skip builders for single-spec formats#833

Merged
stephenamar-db merged 1 commit intodatabricks:masterfrom
He-Pin:split/pr776-single-spec-format
May 11, 2026
Merged

perf: skip builders for single-spec formats#833
stephenamar-db merged 1 commit intodatabricks:masterfrom
He-Pin:split/pr776-single-spec-format

Conversation

@He-Pin
Copy link
Copy Markdown
Contributor

@He-Pin He-Pin commented May 10, 2026

Motivation:

PR #776 showed that format-heavy workloads benefit when the format path avoids unnecessary intermediate assembly. This split keeps only the smallest safe idea: short format strings with exactly one specifier and no static literal text (for example %08d, %010x, %-20s, %20s) do not need a StringBuilder after the formatted value has already been computed.

Key Design Decision:

Keep the existing generic formatting implementation and all validation/arity checks. The optimization only bypasses appending to StringBuilder after the single formatted value is known, so format semantics and error behavior stay unchanged.

Modification:

  • Detect specBits.length == 1 && parsed.staticChars == 0 in Format.format.
  • Avoid allocating/appending a StringBuilder for that case.
  • Return the computed formatted value directly after the existing too-many/too-few value checks.

Benchmark Results:

JMH (./mill -j 1 bench.runRegressions ..., ms/op lower is better; ops/ms higher is better):

Case master ms/op PR ms/op master ops/ms PR ops/ms Delta
repeat_format 0.190 0.133 5.263 7.519 +42.9%
large_string_template guard 1.155 1.160 0.866 0.862 -0.4% noisy/neutral

Scala Native hyperfine (hyperfine --warmup 10 --min-runs 50 -N, ms lower is better):

Case master native PR native jrsonnet Result
repeat_format 6.4 ± 0.9 ms 6.4 ± 0.7 ms 5.6 ± 1.0 ms Native neutral; JMH target positive
large_string_template guard 12.6 ± 7.4 ms 11.4 ± 0.8 ms 5.4 ± 0.9 ms No Native regression observed

Analysis:

The target case is dominated by many short format expressions. Returning the already computed formatted string removes a redundant builder allocation/append path on the JVM. The guard case does not use this single-spec/no-static-literal path and remains effectively unchanged within benchmark noise.

References:

Result:

Motivation:
Short format strings such as %08d or %20s have exactly one dynamic value and no static literal text, so the generic format path was allocating and appending through a StringBuilder only to return that single formatted value.

Modification:
Detect the single-spec/no-static-literal case in Format.format and return the computed formatted value directly after preserving all existing arity checks.

Result:
The repeat_format regression improves from 0.190 ms/op on upstream master to 0.133 ms/op locally, while large_string_template remains effectively neutral and the full Mill test matrix passes.

References:
Source idea: databricks#776
@He-Pin He-Pin marked this pull request as ready for review May 10, 2026 08:57
@stephenamar-db stephenamar-db merged commit 1679892 into databricks:master May 11, 2026
5 checks passed
@He-Pin He-Pin deleted the split/pr776-single-spec-format branch May 11, 2026 04:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants