Skip to content

perf: use static strings for static error messages and avoid needless clones#27

Open
DXist wants to merge 5 commits into
junkurihara:developfrom
DXist:perf/cow_error_strings
Open

perf: use static strings for static error messages and avoid needless clones#27
DXist wants to merge 5 commits into
junkurihara:developfrom
DXist:perf/cow_error_strings

Conversation

@DXist
Copy link
Copy Markdown

@DXist DXist commented May 20, 2026

This PR made perf-related changes:

  • switches to static string slices and Cow<'static, str> for static error messages
  • avoids clones of intermediate results in extract_signatures_inner helper
  • avoids intermediate alg clone when only reference is used downstream
  • uses owned field_values to avoid intermediate to_vec clone
  • takes signatures from the dictionary via swap_remove instead of get + clone
  • SignatureBase::try_new avoids a clone of component_lines.
  • changes output type of as_field_value to Cow<'static, str> to avoid intermediate allocation for HttpMessageComponentValueInner::String variant.

Stylistic change: as_field_value is renamed to to_field_value because conversion is potentially not cheap due to allocation for KeyValue case.

To measure the effect of the clone-related changes, I also added noncrypto.rs benches module with two benches related to

  • signer side SignatureBase construction and
  • verifier side header parsing/SignatureBase construction.

I ran the benches before the perf changes and saved the results as my baseline.

Then I ran the benches after the perf changes and got ~8% improvement.
cargo bench -p httpsig --bench noncrypto --  --baseline=baseline
   Compiling httpsig v0.0.24 (/Users/rinatshigapov/workspace/httpsig-rs/httpsig)
    Finished `bench` profile [optimized] target(s) in 17.12s
     Running benches/noncrypto.rs (target/release/deps/noncrypto-33899b8172d49ef8)
Gnuplot not found, using plotters backend
sig base try_new        time:   [2.1496 µs 2.1759 µs 2.2058 µs]
                        change: [−9.1410% −8.5174% −7.8754%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  4 (4.00%) high severe

sig base try_parse time: [2.5472 µs 2.5860 µs 2.6457 µs]
change: [−8.4396% −7.5125% −6.3287%] (p = 0.00 < 0.05)
Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
3 (3.00%) high mild
3 (3.00%) high severe

It's also possible to avoid cloning of signature_params: &HttpSignatureParam in HttpSignatureBase::try_new and accept owned params in set_message_signatures. If the signer uses a template value for HttpSignatureParam, the cloning cost could be decreased by using compact_str::CompactString.

I tried locally to accept the owned signature_params and swap_remove them from the parsed HeadersMap.

The improvement over the baseline became ~14-15%.
cargo bench -p httpsig --bench noncrypto --  --baseline=baseline
   Compiling httpsig v0.0.24 (/Users/rinatshigapov/workspace/httpsig-rs/httpsig)
    Finished `bench` profile [optimized] target(s) in 17.10s
     Running benches/noncrypto.rs (target/release/deps/noncrypto-33899b8172d49ef8)
Gnuplot not found, using plotters backend
sig base try_new        time:   [1.9997 µs 2.0062 µs 2.0133 µs]
                        change: [−15.587% −15.071% −14.630%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) high mild
  1 (1.00%) high severe

sig base try_parse time: [2.3689 µs 2.3805 µs 2.3924 µs]
change: [−14.595% −13.957% −13.337%] (p = 0.00 < 0.05)
Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
3 (3.00%) high mild
3 (3.00%) high severe

@DXist
Copy link
Copy Markdown
Author

DXist commented May 22, 2026

@junkurihara , I rewrote the interface to pass owned signature_params to avoid clones, got ~12% improvement over the baseline code:

cargo bench -p httpsig --bench noncrypto --  --baseline=baseline
   Compiling httpsig v0.0.24 (/Users/rinatshigapov/workspace/httpsig-rs/httpsig)
    Finished `bench` profile [optimized] target(s) in 15.36s
     Running benches/noncrypto.rs (target/release/deps/noncrypto-33899b8172d49ef8)
Gnuplot not found, using plotters backend
sig base try_new        time:   [2.0824 µs 2.0887 µs 2.0949 µs]
                        change: [−12.797% −12.276% −11.820%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  6 (6.00%) high mild

sig base try_parse      time:   [2.3976 µs 2.4088 µs 2.4205 µs]
                        change: [−13.093% −12.309% −11.449%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe

@DXist
Copy link
Copy Markdown
Author

DXist commented May 22, 2026

I removed intermediate allocations in fmt::Display implementations and reserved a typical capacity for signature base and header value buffers - it gave ~0.5% more improvement.

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