The mfence was not in the SPSC queue implementation, but in the code that allows wakes a potentially sleeping MPSC consumer.

  producer_idx.store(..., memory_order_release)

  if (consumer_is_sleeping) wake_it_up()


an mfence (or a clever trick) is required between these two lines.


On 03/19/2018 04:41 PM, Dan Eloff wrote:
We're getting a little confused on the terminology. That's a compiler barrier, as it prevents the compiler from reordering certain instructions beyond it (I don't think relaxed prevents any reordering, but release and acquire do.) I know you understand this stuff given your background, I just want to clarify the terminology for the sake of the discussion.

The original post and article discuss real memory barriers like mfence. These prevent the CPU from reordering loads and stores. Which should be unnecessary for SPSC queues on x86 because it gives strong enough guarantees about reordering, in this case, without that.


On Mon, Mar 19, 2018, 1:19 AM Avi Kivity <[email protected] <mailto:[email protected]>> wrote:

    The release write is a memory barrier. It's not an SFENCE or
    another fancy instruction, but it is a memory barrier from the
    application writer's point of view.


    The C++ code


        x.store(5, std::memory_order_relaxed)


    has two effects on x86:

      1. generate a write to x that is a single instruction (e.g. mov
    $5, x)
      2. prevent preceding writes from being reordered by the compiler
    (they are implicitly ordered by the processor on x86).



    On 03/18/2018 08:16 PM, Dan Eloff wrote:
    You don't need memory barriers to implement an SPSC queue for
    x86. You can do a relaxed store to the queue followed by a
    release write to producer_idx. As long as consumer begins with an
    acquire load from producer_idx it is guaranteed to see all stores
    to the queue memory before producer_idx, according to the happens
    before ordering. There are no memory barriers on x86 for
    acquire/release semantics.

    The release/acquire semantics have no meaning when used with
    different memory locations, but if used on producer_idx when
    synchronizing the consumer, and consumer_idx when synchronizing
    the producer, it should work.



    On Thu, Feb 15, 2018 at 8:29 AM, Avi Kivity <[email protected]
    <mailto:[email protected]>> wrote:

        Ever see mfence (aka full memory barrier, or
        std::memory_order_seq_cst) taking the top row in a profile?
        Here's the complicated story of how we took it down:


        https://www.scylladb.com/2018/02/15/memory-barriers-seastar-linux/

-- You received this message because you are subscribed to the
        Google Groups "mechanical-sympathy" group.
        To unsubscribe from this group and stop receiving emails from
        it, send an email to
        [email protected]
        <mailto:mechanical-sympathy%[email protected]>.
        For more options, visit https://groups.google.com/d/optout.


-- You received this message because you are subscribed to the
    Google Groups "mechanical-sympathy" group.
    To unsubscribe from this group and stop receiving emails from it,
    send an email to [email protected]
    <mailto:[email protected]>.
    For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected] <mailto:[email protected]>.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups 
"mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to