Re: [PATCH 09/20] alpha: add EV6/EV7 assembly memcmp
Magnus Lindholm <[email protected]>
| Newsgroups | gmane.comp.lib.glibc.alpha |
|---|---|
| Message-ID | <CA+=Fv5Sq7P0AqJe19fe844y3z4Axhth_77VbyOqL1ZJP_SFVNg@mail.gmail.com> |
On Wed, Aug 12, 2026 at 3:20 AM Matt Turner <[email protected]> wrote: > > Alpha had no assembly memcmp and fell back to the generic C implementation. > Add one for the alphaev6 directory (shared by the 21264 and 21364). > > When both operands share alignment, byte-align to a quadword and then compare > 64 bytes per iteration, OR-accumulating the per-quad xors; a non-zero > accumulator means the difference is somewhere in the block, which a byte scan > from the block base pinpoints to return the correct sign. Operands of > differing alignment use a byte compare. > > The loop issues a plain read prefetch (LDL to R31) on both streams eight cache > lines ahead. On the 21364 (EV7), whose on-chip memory controller has a long > memory latency, this hides the Bcache misses that otherwise stall the compare; > on the 21264 it is at worst a dropped hint, so no IMPLVER dispatch is needed. > A read prefetch -- rather than the modify-intent LDS/LDT used by memset/memcpy > -- is deliberate: memcmp never writes its operands, so requesting the lines for > ownership would only add coherence traffic on a multiprocessor. > > The 1 to 7 bytes left after the loops are compared with a single masked > quadword rather than a byte at a time, which would cost about eight issue > slots per byte and dominate any length that is not a multiple of eight. Both > operands are 0mod8 by then, since the head aligned them and everything since > has advanced by whole quadwords, and an aligned quadword cannot cross a page > boundary, so a whole one can be loaded at either pointer even though only some > of it belongs to the compare; masking the difference discards the rest. > Nothing is stored, so reading past the end of the operands is not observable. > A mismatch still falls into the byte loop, which is what determines which byte > differed and in which direction. > > Measured on an AlphaServer ES47 (EV7, 1.3GHz), cold cyc/call vs the generic C: > size generic asm > 1024 3617 1502 2.35x > 4096 14527 6423 2.24x > 65536 231362 96424 2.40x > 262144 916913 386234 2.37x > > Hi, The mismatched-alignment fallback is a large regression against the generic C it replaces. Hot, one operand at offset 3, whole series against baseline: size generic(C) asm ratio 128 89.1 401.3 4.50x slower 512 268.7 1569.4 5.84x slower 2048 950.8 6235.3 6.56x slower 16384 7376.3 50163.0 6.80x slower 65536 53170.0 237889.3 4.47x slower 0.45 cycles/byte for the C against 3.06 for the byte loop, widening with length. The generic C does a shifted word-wise compare for unaligned operands; this gives that up entirely. Co-aligned is a clear win (1.3-2.5x, ~1.7x at 4KB+), so the patch is worth having -- but the mismatched path needs to keep a word-wise compare, or defer to the generic implementation, rather than byte-comparing. Method: both operands filled identically so the compare runs the full length, one at offset 0 and one at offset 3 from an 8192-aligned base. rpcc timing, minimum of 7 trials, call overhead measured as a size-0 call and subtracted, each build measured twice and the runs used as the tolerance. As a check that does not involve the baseline at all, within the patched build alone at 16KB: 3714 cycles co-aligned against 50163 mismatched, 13.5x for the same library and the same buffers, which is the two code paths rather than a measurement artefact. I ran this on my ES40. Were the quoted 2.2-2.4x numbers all co-aligned? Magnus