perf(cmaf): enable AES-NI + zero-alloc decrypt loop

CMAF decrypt was the bottleneck for offline-cache gapless. Live
testing showed a 208 MB HiRes bundle took ~22 seconds to decrypt end-
to-end, which made gapless for anything longer than a 3-minute track
impossible (the gapless pre-emptive window is ~5s before track end,
so a 22s decrypt can't land in time regardless of how early we start).

Two changes, complementary:

1. `.cargo/config.toml` with `target-cpu=x86-64-v3` (Haswell baseline).
   The `aes` crate ships both a software implementation and an AES-NI
   hardware path, runtime-dispatched via `cpufeatures` — but the
   AES-NI path is only compiled in when the appropriate target-feature
   is enabled at build time. Default dev builds compile ONLY the
   software path, which hits ~10 MB/s on a modern CPU. Haswell+ (2013
   and up, every realistic QBZ user) supports AES-NI and clears
   400 MB/s+. For prebuilt distribution binaries we'll want runtime-
   dispatch via subfunction build or dynamic linking, but for self-
   built and release-source-from-tag scenarios this is the right
   default.

2. `decrypt_segments_into` no longer allocates a Vec per frame. Was:
     frame = seg_data[..].to_vec();  // alloc
     decrypt_frame(&mut frame);      // in-place
     output.extend_from_slice(&frame); // copy back
   Now:
     let start = output.len();
     output.extend_from_slice(&seg_data[..]);  // single copy
     decrypt_frame(&mut output[start..]);      // in-place
   For a HiRes FLAC with ~50K frames this saves 50K small allocs +
   50K double-copies. Output Vec is already pre-sized via
   with_capacity(total), so no reallocation growth during extend.

Combined expected impact: 22s decrypt on a 208 MB track → under 500ms,
which fits inside the 5s gapless window with headroom to spare.

cc
This commit is contained in:
vicrodh committed 2026-04-17 12:45:42 -06:00
1 parent 6d2d69d903
commit aae685e701
2 files changed
+29 -3

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
# Enable CPU intrinsics for AES-NI + SSSE3.
#
# The qbz-cmaf crate does AES-128-CTR decrypt on every offline-cached
# audio frame. Without AES-NI the decrypt falls back to a software
# implementation that hits ~10 MB/s on a modern CPU; with AES-NI it
# clears 400+ MB/s. For HiRes (200 MB+ tracks) this is the difference
# between a 20-second gap and a sub-second one.
#
# `target-cpu=x86-64-v3` = Haswell baseline (2013+). Every CPU that
# QBZ realistically runs on supports it. If we later ship prebuilt
# binaries for older CPUs we can switch to a runtime-dispatch path,
# but for self-built and workstation-compiled binaries this is the
# right default.
[build]
rustflags = ["-C", "target-cpu=x86-64-v3"]