Skip to content

error: 3-4% faster builds via macro instead of trivial '?'#529

Open
exrok wants to merge 3 commits intoBurntSushi:masterfrom
exrok:master
Open

error: 3-4% faster builds via macro instead of trivial '?'#529
exrok wants to merge 3 commits intoBurntSushi:masterfrom
exrok:master

Conversation

@exrok
Copy link

@exrok exrok commented Mar 11, 2026

I'm not sure if for code quality reasons, we actually want to do this for the relatively small gain but
thought I put it up just in case, feel free to close.

I've only done trivial try transforms in this PR, but I think there is more savings that could be had with a similar macro to avoid many of the map_err( instances.

This commit introduces the rtry! macro and uses it throughout the codebase instead of ? for forwarding result types whose error types are already same. This is a trick that serde uses: https://github.com/serde-rs/serde/blob/fa7da4a93567ed347ad0735c28e439fca688ef26/serde/src/lib.rs#L236-L248

The de-sugared try operator ('?') invokes the Try and From trait but for most of the error forwarding sites we need neither.

For rustc 1.94.0 (4a4ef493e 2026-03-02):

The total debug build cargo llvm-lines of jiff, reduced from 174096 to 168315 LLVM lines.

Then measured from 5 samples of perf stat on a direct rustc invocation to build the jiff rlib (non incremental), shows the following:

Before (using the try operator)

    10,889,052,814      cycles:u        ( +-  0.08% )
    15,171,370,701      instructions:u  ( +-  0.01% )
     2,671,428,910      branch:u        ( +-  0.01% )

    1.60105 +- 0.00152 seconds time elapsed  ( +-  0.09% )

After (using the macro)

    10,454,390,370      cycles:u        ( +-  0.12% )
    14,591,413,777      instructions:u  ( +-  0.01% )
     2,567,871,039      branch:u        ( +-  0.01% )

    1.55956 +- 0.00335 seconds time elapsed  ( +-  0.21% )

The above perf results show an improvement of 3-4% percent.

System Specs if Needed
rustc:   rustc 1.94.0 (4a4ef493e 2026-03-02) (LLVM 21.1.8)
os:      Arch Linux (kernel 6.18.13-arch1-1)
cpu:     AMD Ryzen 9 5950X 16-Core Processor (32 threads)
memory:  63 GB
caches:  L1d: 512 KiB (16 instances), L1i: 512 KiB (16 instances), L2: 8 MiB (16 instances), L3: 64 MiB (2 instances)
Exact perf stat rustc command I used
env CARGO_PKG_HOMEPAGE='' CARGO_PKG_LICENSE='Unlicense OR MIT' CARGO_PKG_LICENSE_FILE='' CARGO_PKG_NAME=jiff CARGO_PKG_README=README.md CARGO_PKG_REPOSITORY='https://github.com/BurntSushi/jiff' CARGO_PKG_RUST_VERSION=1.70 CARGO_PKG_VERSION=0.2.23 CARGO_PKG_VERSION_MAJOR=0 CARGO_PKG_VERSION_MINOR=2 CARGO_PKG_VERSION_PATCH=23 CARGO_PKG_VERSION_PRE='' CARGO_PRIMARY_PACKAGE=1 LD_LIBRARY_PATH='/tmp/rust-target/debug/deps:/home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib' perf stat -r 5 -e cycles,instructions,branch /home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name jiff --edition=2021 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=191 --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 --allow=unexpected_cfgs --check-cfg 'cfg(docsrs_jiff)' --cfg 'feature="alloc"' --cfg 'feature="default"' --cfg 'feature="perf-inline"' --cfg 'feature="std"' --cfg 'feature="tz-fat"' --cfg 'feature="tz-system"' --cfg 'feature="tzdb-bundle-platform"' --cfg 'feature="tzdb-concatenated"' --cfg 'feature="tzdb-zoneinfo"' --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values("alloc", "default", "js", "logging", "perf-inline", "serde", "static", "static-tz", "std", "tz-fat", "tz-system", "tzdb-bundle-always", "tzdb-bundle-platform", "tzdb-concatenated", "tzdb-zoneinfo"))' -C metadata=6b7754662bf2080e -C extra-filename=-c5cdb0b61b123153 --out-dir /tmp/rust-target/debug/deps -C linker=/usr/bin/clang -L dependency=/tmp/rust-target/debug/deps -Clink-arg=--ld-path=/bin/wild

Replacement Process:
Initially I tried to use debug info to find trivial From invocations of error types, on the same line as a try operators to constrain the replacements but I ended up just doing aggressive replacements using tree-sitter then reverting the cases that failed...

As you can see from the initial CI failures and patch commits the process has been a bit iterative. I am trusting that CI type checks all code paths, I don't know if I should be. If the premise of this PR is something that could be accepted, I could spend the time to auditing each replacement, just say the word.

exrok added 3 commits March 11, 2026 16:43
This commit introduces the `rtry!` macro and uses it throughout the
codebase instead of `?` for forwarding result types whose error types
are already same.

The de-sugared try operator ('?') invokes but the Try trait and
From trait, but for most of are error forwarding sites we need neither.

For rustc 1.94.0 (4a4ef493e 2026-03-02).

The total debug build `cargo llvm-lines` of the jiff,
reduced from 174096 to 168315 LLVM lines.

Measure the from 5 samples of `perf stat` on a direct rustc invocation to build
the jiff rlib, shows the following:

Before (using the try operator)
    10,889,052,814      cycles:u        ( +-  0.08% )
    15,171,370,701      instructions:u  ( +-  0.01% )
     2,671,428,910      branch:u        ( +-  0.01% )

    1.60105 +- 0.00152 seconds time elapsed  ( +-  0.09% )

After (using the macro)
    10,454,390,370      cycles:u        ( +-  0.12% )
    14,591,413,777      instructions:u  ( +-  0.01% )
     2,567,871,039      branch:u        ( +-  0.01% )

    1.55956 +- 0.00335 seconds time elapsed  ( +-  0.21% )

The above perf results show an improvement of 3-4% percent.
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