Skip to content

perf: fast-path Num stringify in OP_+ string concatenation#684

Open
He-Pin wants to merge 1 commit intodatabricks:masterfrom
He-Pin:perf/num-stringify-fastpath
Open

perf: fast-path Num stringify in OP_+ string concatenation#684
He-Pin wants to merge 1 commit intodatabricks:masterfrom
He-Pin:perf/num-stringify-fastpath

Conversation

@He-Pin
Copy link
Copy Markdown
Contributor

@He-Pin He-Pin commented Apr 5, 2026

Motivation

When concatenating strings with +, if one operand is a number, it must be converted to string. The current path goes through Materializer.stringify which has overhead from format dispatching and intermediate string creation.

Key Design Decision

Add a fast path in OP_+ that detects Val.Num operands and converts them directly using the existing renderDouble utility, bypassing the full Materializer.stringify chain.

Modification

  • Evaluator.scala: Added 2-line fast path check in OP_+ string concatenation for Val.Num operands

Benchmark Results

JMH (JVM, 3 iterations)

Benchmark Master (ms/op) This PR (ms/op) Change
bench.02 50.427 ± 38.906 45.106 ± 1.454 -10.6%
comparison2 85.854 ± 188.657 69.783 ± 19.053 -18.7% 🔥
realistic2 73.458 ± 66.747 68.648 ± 36.435 -6.5%

Analysis

  • Just 2 lines of code for -10% to -19% improvement
  • Particularly effective for workloads that format numbers into strings (very common in Jsonnet templates)
  • No regressions

References

  • Upstream exploration: he-pin/sjsonnet jit branch commit 4b1cd032

Result

Massive ROI optimization: 2 lines of code for -10% to -19% JVM improvement on number-to-string concatenation paths.

Add direct RenderUtils.renderDouble() call for Num+Str and Str+Num
cases in binary OP_+ to avoid Materializer.stringify() dispatch overhead.

stringify() performs a full pattern match on Val type just to extract
the double for rendering. The direct call skips this dispatch entirely,
which is significant for string template operations that concatenate
many numbers with strings.

Uses n.asDouble (not raw destructured double) to preserve the NaN guard
that exists in Val.Num.asDouble — this ensures consistency with
Materializer.stringify() error behavior for not-a-number values.

Upstream: jit branch commit 4b1cd03
@He-Pin He-Pin marked this pull request as ready for review April 5, 2026 10:33
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.

1 participant