arm64: the write-barrier memoize loops release with stlxr - #616
Conversation
The 16 EGC memoize loops in arm64-spentry.s end with a store-exclusive and
then a separate `dmb ish':
ldxr imm1, [temp0]
orr imm1, imm1, imm3
stxr w17, imm1, [temp0]
cbnz w17, 1b
dmb ish /* ppc:508 isync */
Make the store-exclusive itself a release and drop the barrier. A release
store-exclusive orders every prior access before the store becomes
observable, which is what the trailing `dmb ish' was providing, so this
encodes the same guarantee rather than a weaker one.
This is the change you already took for the LAP atomics in 76ed388, applied
to the kernel side of the same family.
ARM32 cannot do this and its barriers are untouched. ARMv7 has no
acquire/release load or store forms, so a standalone `dmb' is the only tool
there, and 539ed52 stands as written.
MEASURED on linuxarm64, Neoverse V3 (CPU part 0xd84), two cores, clock
measured at 3.29 GHz by the PMU cycle counter over a three-second spin, so
one cycle is 0.304 ns. Interleaved A/B, two cycles, medians of five reps,
one session, one box. The two kernels differ only by this patch and the
boot image is byte-identical across both:
memoized store, 1 thread 14.5 ns -> 12.8 ns (47.7 -> 42.1 cycles)
memoized store, 2 threads 13.9 ns -> 13.0 ns
Each memoized store updates TWO bitmaps, refbits then ephemeral_refidx, so
it runs two of these loops -- visible as two hunks per label in the diff.
The 5.6 cycles saved is therefore about 2.8 cycles per site.
Eight benches this patch cannot reach -- allocation, semaphores, locks,
uncontended atomic-incf, and the fixnum and old-object store paths that exit
before the memoize loop -- move by at most 0.2 ns, which is the timer's
resolution at those rates. Judged in absolute nanoseconds on purpose: a
barrier costs a fixed number of cycles, so a 0.2 ns quantum reads as 15 percent
on a 1.2 ns bench and 1.4 percent on a 14.5 ns one, and percentages invert the
comparison.
The conditional-store sites in egc_store_node_conditional and
egc_set_hash_key_conditional keep their barriers. Those order the CAS
itself, not the memoize bit-set, and this patch does not touch them.
VERIFIED: built and run on linuxarm64. ANSI 21679 tests, 0
failures. tests/ccl.lsp 243 tests, 0 failures. Kernel
assembly only, so no other target is affected, and not built on any other
target.
A caveat worth stating plainly: both suites are single-threaded, so they show
that nothing gross broke. They cannot certify a barrier-ordering change in
either direction.
|
The argument in this pull request is a measurement, so here is the harness that This is not a patch and I am not asking you to take it into CCL. It sits on
Three things about reading the output, because each one cost me time: Compare absolute nanoseconds, not percentages. A barrier costs a fixed Interleave the arms and repeat. A single A-then-B pass cannot separate an Check the two kernels really differ. Verify the binary's md5 changes between The rows that can move when the memoize loops change are My cell, for comparison: Neoverse V3, CPU part These are microbenchmarks. They answer "what does this instruction sequence |
|
I believe that it's true that we probably don't need a barrier here: we're interested in consistencty/atomicity rather than ordering. The only possible wrinkle I see is that we would have to be sure that thread suspend acts as a full barrier so that the stores are globally visible when we stop the world and read the bits. However, I think I'd prefer to leave the release ordering. (Which your change preserves, and which I intend to accept.) |
The 16 EGC memoize loops in
arm64-spentry.send with a store-exclusive andthen a separate
dmb ish:This makes the store-exclusive itself a release and drops the barrier. A
release store-exclusive orders every prior access before the store becomes
observable, which is what the trailing
dmb ishwas providing, so it encodesthe same guarantee rather than a weaker one.
It is the change you already took for the LAP atomics in
76ed388c, applied tothe kernel side of the same family.
ARM32 is untouched and cannot do this. ARMv7 has no acquire/release load or
store forms, so a standalone
dmbis the only tool there and539ed520standsas written. The asymmetry is an ISA fact, not a claim about your change.
Measured
linuxarm64, Neoverse V3 (CPU part
0xd84), two cores. Clock measured at3.29 GHz by the PMU cycle counter over a three-second spin, so one cycle is
0.304 ns and the nanoseconds below convert. Interleaved A/B, two cycles, medians
of five reps, one session, one box. The two kernels differ only by this patch
and the boot image is byte-identical across both.
Each memoized store updates two bitmaps,
refbitsthenephemeral_refidx, soit runs two of these loops -- two hunks per label in the diff. The 5.6 cycles
saved is therefore about 2.8 cycles per site.
Eight benches this patch cannot reach move by at most 0.2 ns: allocation,
semaphores, locks, uncontended
atomic-incf, and the fixnum and old-objectstore paths that exit before the memoize loop. 0.2 ns is the timer's resolution
at those rates.
Judged in absolute nanoseconds on purpose. A barrier costs a fixed number of
cycles, so one 0.2 ns quantum reads as 15 percent on a 1.2 ns bench and 1.4
percent on a 14.5 ns one. Percentages invert the comparison here.
Not in this patch
The conditional-store sites in
egc_store_node_conditionalandegc_set_hash_key_conditionalkeep their barriers. Those order the CAS itselfrather than the memoize bit-set.
VERIFIED:built and run on linuxarm64. ANSI 21679 tests, 0 failures.tests/ccl.lsp243 tests, 0 failures. Kernel assembly only, so no other targetis affected. Not built on any other target.
One caveat stated plainly: both suites are single-threaded, so they show that
nothing gross broke. They cannot certify a barrier-ordering change in either
direction.
A separate question, not part of this patch
I also measured dropping these 16 barriers outright, with
stxrleft alone.That reaches 11.2 ns, or 36.8 cycles, so a
dmb ishat these sites costsabout 5.4 cycles and roughly half of that is the release ordering this patch
keeps.
I am not proposing that. It would need these sites to require no ordering at
all, which is a question about the EGC rather than about the encoding: the
refbits and ephemeral_refidx bitmaps are read by the collector only after
suspend_other_threads(), andpc_luser_xpre-memoizes in C for a threadsuspended inside the window. If that reasoning is wrong the barriers belong
where they are. If it is right, there is another 1.6 ns per memoized
store available, about 5 cycles. Your call, and I am happy to leave it alone.