Performance Notes

v1.0 Audio Path

KeyEcho 1.0 makes key playback more predictable by moving expensive work out of the key-press path.

When a sound pack is selected, KeyEcho now:

  • validates the archive and sound-pack budget,
  • deduplicates identical [start_ms, duration_ms] slices,
  • decodes each unique OGG slice once,
  • stores decoded samples in shared Arc<[f32]> buffers.

When a key is pressed, playback now:

  • sends one event to a bounded audio queue,
  • loads the current sound without a global sound-pack mutex,
  • clones an Arc<[f32]> handle instead of a sample buffer,
  • reads volume through an atomic value.

The key-press path no longer performs:

  • OGG seek/decode,
  • sample-buffer copies,
  • global sound-pack mutex locks,
  • key-release playback messages,
  • unbounded queue growth.

Tradeoff: selected packs use more memory up front. Downloaded and custom packs are rejected before predecode if their estimated decoded size exceeds 10 MiB at 48 kHz stereo f32.

Reference Pack

The numbers below use the bundled cherrymx-black-abs pack.

Metric Value
Defined keys 104
Unique audio slices after dedupe 86
Duplicate key slices removed from sample store 18
Decoded sample storage saved by dedupe 17.82%

These pack counts come from the sound-pack config. The timings below are release microbenchmarks, not end-to-end speaker latency measurements.

Reference Timings

Measured with release builds on the same machine:

cargo test --release --manifest-path src-tauri\Cargo.toml reference_timing -- --ignored --nocapture

Baseline: local v0.0.5 release tag fee5596925a6403b2bf84cd60cc271534c2d674c.

Measurement v0.0.5 release v1.0 branch Change
Cached lookup, average-size slice (194 ms) 1184.07 ns/op, 66.84 KiB copied 43.50 ns/op, 0 sample bytes copied 27.2x faster
Cached lookup, largest slice (287 ms) 1638.57 ns/op, 98.88 KiB copied 43.10 ns/op, 0 sample bytes copied 38.0x faster
Press/release gate, CPU only 58.82 ns/tap, 2 playback messages 54.69 ns/tap, 1 playback message similar CPU, half the messages

The lookup benchmark compares the old cached model's mutex-protected owned sample-buffer clone with the v1.0 shared-buffer path. It intentionally excludes audio device I/O, which depends on OS scheduling and hardware.

Memory Budget

cherrymx-black-abs decoded sample storage after slice dedupe:

Format Before dedupe After dedupe Saved
44.1 kHz mono 3.385 MiB 2.782 MiB 0.603 MiB
44.1 kHz stereo 6.771 MiB 5.564 MiB 1.207 MiB
48 kHz mono 3.685 MiB 3.028 MiB 0.657 MiB
48 kHz stereo 7.370 MiB 6.056 MiB 1.313 MiB

Bundled and downloaded packs are checked against these limits before predecode:

Budget Limit
Defined keys <= 104
Unique [start_ms, duration_ms] slices <= 104
Unique predecoded duration <= 18.5s
Estimated decoded memory, 48 kHz stereo f32 <= 10 MiB
Estimated largest single-key buffer <= 512 KiB

Current maximums across bundled packs:

Metric Current max
Defined keys 104
Unique slices 103 (eg-oreo)
Unique predecoded duration 17.884s (nk-cream)
Decoded memory, 48 kHz stereo f32 6.55 MiB (nk-cream)
Largest single-key buffer, 48 kHz stereo f32 447.75 KiB (cherrymx-red-pbt)

Compared with v0.0.5, v1.0 uses more memory immediately after selecting a pack because it predecodes unique slices up front. That tradeoff removes decode and sample-copy work from key playback.

Audio Device Routing

Default output-device following is delegated to cpal 0.18.1 through the rodio Git dependency. Key playback does not poll devices on the hot path.

Verification

Last full verification for the v1.0 branch:

  • rtk pnpm test
    • Rust unit tests: 25 passed
    • Vitest unit tests: 11 passed
    • frontend typecheck and production build: passed
  • rtk pnpm run bench:audio: 2 ignored-by-default reference benchmarks passed
  • rtk cargo check --manifest-path src-tauri\Cargo.toml: passed

The Rust tests cover shared sample storage, bounded queue capacity, press/release gating, runtime sound-pack memory limits, slice dedupe, lock-free playback state updates, and bundled sound-pack budgets.