Skip to content

perf(path): write StringView components via write_view instead of copying to_owned#244

Merged
peter-jerry-ye merged 1 commit into
moonbitlang:mainfrom
mizchi:pr-path-show-write-view
May 26, 2026
Merged

perf(path): write StringView components via write_view instead of copying to_owned#244
peter-jerry-ye merged 1 commit into
moonbitlang:mainfrom
mizchi:pr-path-show-write-view

Conversation

@mizchi
Copy link
Copy Markdown
Contributor

@mizchi mizchi commented May 23, 2026

Summary

UnixPath's Show::output writes each path component via:

logger.write_string(x.to_owned())

where x is a StringView. The to_owned() step copies the StringView into a newly allocated String, which write_string then immediately copies into the underlying builder. That's one allocation + two copies per component, where one copy would suffice.

Logger already has a write_view(StringView) method that targets exactly this case — no intermediate String.

logger.write_view(x)

The same pattern appears in path/win32/win_path.mbt's WinPath::output (writes each component as write_string(component.to_owned())); fixed identically in this patch.

Why this is hot

Path::normalize(p) is UnixPath::parse(p.0).to_string() — so every normalize call goes through Show::output and pays the per-component copy cost. On a realistic path with ~5–10 components the redundant work adds up fast.

Benchmark

Scenario: bench-x/cmd/path_normalize/main.mbtPath::normalize + dirname + basename + extname on a 10-segment path with .. / ., × 200 000 iters. Native release, Linux x86_64, 3-run median wall time.

baseline patched delta
path_normalize 282 ms 209 ms -25.9%

Callgrind total instructions: 3.73 G → 2.71 G (-27.4%). FixedArray::blit_from_string falls from 15.19% of the profile to 8.99% (and to a much smaller absolute number).

Tests

moonbitlang/x/path/posix    38 / 38 pass
moonbitlang/x/path/win32    50 / 50 pass

…ying to_owned

UnixPath::Show::output and WinPath::Show::output wrote each
path component as logger.write_string(x.to_owned()) where x is a
StringView. to_owned() copies the view into a newly allocated String,
which write_string then copies again into the builder -- one
allocation + two copies per component, where Logger already exposes
write_view(StringView) doing the job in a single step.

Path::normalize(p) is UnixPath::parse(p.0).to_string(), so every
normalize goes through Show::output and pays the per-component copy.

path_normalize bench (native, 3-run median, 10-segment path with ..
and . x 200k iters):
  baseline: 282 ms
  patched : 209 ms  (-25.9%)
@peter-jerry-ye peter-jerry-ye force-pushed the pr-path-show-write-view branch from ee69f7d to 53f5566 Compare May 26, 2026 03:19
@peter-jerry-ye peter-jerry-ye enabled auto-merge (rebase) May 26, 2026 03:19
Copy link
Copy Markdown
Collaborator

@peter-jerry-ye peter-jerry-ye left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@peter-jerry-ye peter-jerry-ye merged commit 135d141 into moonbitlang:main May 26, 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