]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
OPTIM: ring: avoid reloading the tail_ofs value before the CAS in ring_write()
authorWilly Tarreau <w@1wt.eu>
Thu, 18 Sep 2025 13:23:53 +0000 (15:23 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 18 Sep 2025 13:27:32 +0000 (15:27 +0200)
The load followed by the CAS seem to cause two bus cycles, one to
retrieve the cache line in shared state and a second one to get
exclusive ownership of it. Tests show that on x86 it's much better
to just rely on the previous value and preset it to zero before
entering the loop. We just mask the ring lock in case of failure
so as to challenge it on next iteration and that's done.

This little change brings 2.3% extra performance (11.34M msg/s) on
a 64-core AMD.

src/ring.c

index 79f023aa1b8c8b0e76ebc695bb2f4d89c34f790f..ebe3b042cd5c034a15b4945d88e3224f8f51bf2c 100644 (file)
@@ -274,6 +274,7 @@ ssize_t ring_write(struct ring *ring, size_t maxlen, const struct ist pfx[], siz
         * threads check the tail.
         */
 
+       tail_ofs = 0;
        while (1) {
 #if defined(__x86_64__)
                /* read using a CAS on x86, as it will keep the cache line
@@ -300,11 +301,9 @@ ssize_t ring_write(struct ring *ring, size_t maxlen, const struct ist pfx[], siz
                if (!(tail_ofs & RING_TAIL_LOCK))
                        break;
 #else
-               tail_ofs = HA_ATOMIC_LOAD(tail_ptr);
-               if (likely(!(tail_ofs & RING_TAIL_LOCK))) {
-                       if (HA_ATOMIC_CAS(tail_ptr, &tail_ofs, tail_ofs | RING_TAIL_LOCK))
-                               break;
-               }
+               if (HA_ATOMIC_CAS(tail_ptr, &tail_ofs, tail_ofs | RING_TAIL_LOCK))
+                       break;
+               tail_ofs &= ~RING_TAIL_LOCK;
 #endif
                __ha_cpu_relax();
        }