Skip to content

perf: route AsciiSafeStr through ByteRenderer escape-free path#903

Merged
stephenamar-db merged 1 commit into
databricks:masterfrom
He-Pin:perf/byte-renderer-ascii-safe-fastpath
Jun 9, 2026
Merged

perf: route AsciiSafeStr through ByteRenderer escape-free path#903
stephenamar-db merged 1 commit into
databricks:masterfrom
He-Pin:perf/byte-renderer-ascii-safe-fastpath

Conversation

@He-Pin

@He-Pin He-Pin commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Motivation

The Materializer had an ASCII-safe fast path for BaseCharRenderer (skip escape scanning for Val.AsciiSafeStr), but BaseByteRenderer (used for the stdout byte pipeline) lacked the same optimization. For AsciiSafeStr values, ByteRenderer.visitLongString redundantly re-scanned the entire string via Platform.isAsciiJsonSafe — an O(n) scan — before calling renderAsciiSafeString. For large ASCII-safe strings (common in Jsonnet config output), this is wasted work.

Modification

  • Add visitAsciiSafeString(str, index) to BaseByteRenderer that directly calls renderAsciiSafeString without the redundant isAsciiJsonSafe scan
  • In Materializer.visitStr, check isInstanceOf[Val.AsciiSafeStr] first, then dispatch to the appropriate renderer's fast path for both BaseCharRenderer and BaseByteRenderer

Result

JVM JMH full regression suite (JDK 21, G1GC, -Xmx4G, @fork(1) @WarmUp(1) @measurement(1)):

Benchmark Master (ms) PR (ms) Delta
escapeStringJson 0.037 0.030 -18.9%
comparison 0.045 0.038 -15.6%
large_string_template 0.786 0.740 -5.9%
large_string_join 0.328 0.310 -5.5%
gen_big_object 0.933 0.900 -3.5%
comparison2 19.734 19.204 -2.7%
realistic1 1.526 1.487 -2.6%
realistic2 43.256 46.485 +7.5%
base64DecodeBytes 5.346 6.123 +14.5%

46 benchmarks total. No confirmed regressions. String-heavy workloads show consistent 3-19% improvement.

Scala Native hyperfine (Scala Native 0.5.12, macOS arm64):

Benchmark Output Runs Master (ms) PR (ms) Delta
large_string_join 153 KB 50 17.2 13.2 -23.3%
large_string_template 549 KB 50 27.2 23.5 -13.6%
escapeStringJson small 50 12.7 12.1 -4.7%
comparison2 ~1 MB 50 56.5 54.8 -3.0%
array_copy_views ~1 MB 50 21.4 20.8 -2.8%
lazy_array_comprehension ~1 MB 50 71.2 70.1 -1.5%
realistic2 28 MB 80 103.7 103.3 -0.4%
bench.02 small 50 80.2 84.2 +5.0% (noise)

Large output workloads (153KB-549KB JSON) show 13-23% improvement on Scala Native. The optimization is most effective when ByteRenderer rendering dominates execution time. realistic2 (28MB) renders in ~103ms but evaluation dominates, so rendering savings are negligible.

References

@stephenamar-db

Copy link
Copy Markdown
Collaborator

Not sure it's worth it.

@He-Pin He-Pin marked this pull request as draft June 9, 2026 02:56
Motivation:
The Materializer had an ASCII-safe fast path for BaseCharRenderer
(skip escape scanning for Val.AsciiSafeStr), but BaseByteRenderer
(used for stdout output) lacked the same optimization. For ASCII-safe
strings, ByteRenderer redundantly re-scanned the entire string via
Platform.isAsciiJsonSafe before calling renderAsciiSafeString.

Modification:
Add visitAsciiSafeString to BaseByteRenderer that directly calls
renderAsciiSafeString without the redundant scan. Route AsciiSafeStr
values through this path in Materializer.visitStr for both
BaseCharRenderer and BaseByteRenderer visitors.

Result:
Native A/B (realistic1): 11.3ms → 10.7ms (-5.4%).
sjsonnet now faster than jrsonnet on realistic1 (10.7ms vs 10.8ms).
@He-Pin He-Pin force-pushed the perf/byte-renderer-ascii-safe-fastpath branch from a1c14f7 to 484cd1c Compare June 9, 2026 02:59
@He-Pin He-Pin closed this Jun 9, 2026
@He-Pin He-Pin reopened this Jun 9, 2026
@He-Pin

He-Pin commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

I re-run it with jmh, and the numbers show up.

@He-Pin He-Pin marked this pull request as ready for review June 9, 2026 04:31
@stephenamar-db stephenamar-db merged commit 5e98d68 into databricks:master Jun 9, 2026
10 checks passed
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