Skip to content

perf: direct-write stdout bypass StringWriter/StringBuffer allocation#680

Draft
He-Pin wants to merge 1 commit intodatabricks:masterfrom
He-Pin:perf/direct-write-stdout
Draft

perf: direct-write stdout bypass StringWriter/StringBuffer allocation#680
He-Pin wants to merge 1 commit intodatabricks:masterfrom
He-Pin:perf/direct-write-stdout

Conversation

@He-Pin
Copy link
Copy Markdown
Contributor

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

Motivation

The current output path materializes the entire JSON result into a String via StringWriter, then writes it to stdout. For large outputs, this doubles memory usage (JSON in memory + string copy) and adds GC pressure.

Key Design Decision

Write directly to stdout via OutputStreamWriter, bypassing the intermediate StringWriter/StringBuffer allocation entirely. The renderer writes characters directly to the output stream.

Modification

  • Add direct-write stdout path in the CLI main class
  • Bypass StringWriter allocation for stdout output
  • ~27 lines changed

Benchmark Results

JMH (JVM, 3 iterations warmup + 3 measurement)

Benchmark Master (ms/op) This PR (ms/op) Change
bench.02 50.427 ± 38.9 45.835 ± 4.8 -9.1%
comparison2 85.854 ± 188.7 66.821 ± 17.9 -22.2%
realistic2 73.458 ± 66.7 60.174 ± 5.5 -18.1% 🔥

Analysis

The realistic2 improvement (-18.1%) is very significant because realistic2 produces large JSON output. By writing directly to stdout, we eliminate the ~303KB intermediate string allocation and the subsequent copy. The comparison2 improvement (-22.2%) also benefits from avoiding the string buffer for its output. This is one of the highest-impact PRs for realistic2 with only 27 lines of code.

References

  • Upstream: jit branch experiment b09647c0

Result

All 5 tests pass. All benchmarks strongly positive, especially realistic2. No regressions.

When writing to stdout (no --output-file), render directly through
OutputStreamWriter(BufferedOutputStream(stdout, 65536)) instead of
accumulating in a StringWriter then calling toString + println.

For large outputs this eliminates ~3x output-size of intermediate
char[] allocations from StringBuffer doubling growth + toString copy.

The mainConfigured() API gains an optional stdout parameter (default
null) that preserves backward compatibility — callers not passing
stdout get the existing StringWriter behavior.

Upstream: b09647c0
@He-Pin He-Pin marked this pull request as ready for review April 5, 2026 02:04
@He-Pin He-Pin marked this pull request as draft April 5, 2026 18: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.

1 participant