bits: replace per-probe multiplies with one division in lc3_get_symbol - #89
parthvelobyte wants to merge 1 commit into
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
28b572b to
37c97c2
Compare
|
@googlebot I signed it! |
303c2f6 to
c979716
Compare
|
Thanks for the analysis and PR! While replacing the 4 dependent multiplications with 1 runtime integer division (
Could we guard this optimization behind an architecture/compiler macro check (e.g., only enabling it on |
2cdeae9 to
e10c3fb
Compare
|
Agreed, thanks.
|
The binary search in lc3_get_symbol() chains up to five dependent
multiplies, range * symbols[s].low, on the critical path of every
decoded symbol. For unsigned values with range >= 1,
low < range * L <=> low / range < L
so one division before the search turns each probe into a plain
table compare.
Enabled only on cores with a fast hardware divider (x86-64, AArch64)
via LC3_FAST_UDIV in common.h; MCUs and audio DSPs keep the
multiply-based search unchanged. Override with -DLC3_FAST_UDIV=0/1.
Encoded and decoded outputs are byte-identical to the unpatched
build under both settings. Decoder 3-5% faster on Apple M2 Pro.
e10c3fb to
ce5c669
Compare
lc3_get_symbol()comparesac->lowagainstrange * symbols[s].lowat every probe of its binary search. Each probe'ssdepends on the previous compare, so that is up to five dependent multiplies on the critical path of every decoded symbol.For unsigned values with
range >= 1:(let
q = low / range, sorange*q <= low < range*(q+1); ifq < Lthenlow < range*(q+1) <= range*L, and iflow < range*Lthenrange*q <= low < range*L, soq < L.)So one division before the search turns each probe into a plain table compare.
ac->rangeis initialized to0xffffffand renormalization keeps it>= 0x10000, sorangeis in[0x40, 0x3fff]and the division is always defined.Where it is enabled: only on cores with a fast hardware divider, via
LC3_FAST_UDIVincommon.h(1 on x86-64 / AArch64, 0 otherwise, overridable with-DLC3_FAST_UDIV=0/1). MCUs, 32-bit ARM and audio DSPs compile the original multiply-based search unchanged.Correctness: encoded and decoded outputs are byte-identical to the unpatched build (SHA-256 on every artifact) over a deterministic 180 s 48 kHz corpus at 32 and 96 kbps, 7.5 and 10 ms frames, with
LC3_FAST_UDIVboth on and off.Performance: decoder wall time 3–5% faster on Apple M2 Pro (Apple clang 15, release flags), interleaved A/B, median of 6–10 rounds. Encoder and
lc3_put_symboluntouched.