Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update mpsc padding #100

Merged
merged 2 commits into from
Jan 18, 2020
Merged

Update mpsc padding #100

merged 2 commits into from
Jan 18, 2020

Conversation

mratsim
Copy link
Owner

@mratsim mratsim commented Jan 18, 2020

This updates the MPSC channel padding after the fix of nim-lang/Nim#13122

There is a tricky compromise for the pledges data structure size:

PledgeKind = enum
Single
Iteration
PledgePtr = ptr object
refCount: Atomic[int32]
case kind: PledgeKind
of Single:
impl: PledgeImpl
of Iteration:
numBuckets: int32
start, stop, stride: int32
impls: ptr UncheckedArray[PledgeImpl]
PledgeImpl = object
# Issue: https://github.com/mratsim/weave/issues/93
# TODO, the current MPSC channel always use a "count" field.
# Contrary to StealRequest and the remote freed memory in the memory pool,
# this is not needed, and atomics are expensive.
# It can be made optional with a useCount static bool.
# The MPSC Channel is intrusive to the PledgeImpl.
# The end fields in the channel should be the consumer
# to avoid cache-line conflicts with producer threads.
chan: ChannelMpscUnboundedBatch[TaskNode]
deferredIn: Atomic[int32]
deferredOut: Atomic[int32]
fulfilled: Atomic[bool]

The kind field (1 byte) has to be the first field of PledgePtr, so when the ChannelMPSCunbounded[TaskNode] is made intrusive, the cacheline alignment requirements automatically mades it take over 64 bytes.
Also even if the back/count/front are tagged with 64 bytes alignment each (total 192 bytes)

ChannelMpscUnboundedBatch*[T: Enqueueable] = object
## Lockless multi-producer single-consumer channel
##
## Properties:
## - Lockless
## - Wait-free for producers
## - Consumer can be blocked by producers when they swap
## the tail, the tail can grow but the consumer sees it as nil
## until it's published all at once.
## - Unbounded
## - Intrusive List based
## - Keep an approximate count on enqueued
## - Support batching on both the producers and consumer side
# TODO: pass this through Relacy and Valgrind/Helgrind
# to make sure there are no bugs
# on arch with relaxed memory models
# Producers and consumer slow-path
back{.align: MpscPadding.}: Atomic[pointer] # Workaround generic atomics bug: https://github.com/nim-lang/Nim/issues/12695
# Accessed by all
count: Atomic[int]
# Consumer only - front is a dummy node
front{.align: MpscPadding.}: derefMPSC(T)
# back and front order is chosen so that the data structure can be
# made intrusive to consumer data-structures
# like the memory-pool and the pledges so that
# producer accesses don't invalidate consumer cache-lines
#
# The padding is a compromise to keep back and front 1 cache line apart
# but still have a reasonable MPSC Channel size of 2xCacheLine (instead of 3x)

the extra deferredIn, deferredOut, fulfilled fields are not using the extra space after the front field:

PledgeImpl = object
# Issue: https://github.com/mratsim/weave/issues/93
# TODO, the current MPSC channel always use a "count" field.
# Contrary to StealRequest and the remote freed memory in the memory pool,
# this is not needed, and atomics are expensive.
# It can be made optional with a useCount static bool.
# The MPSC Channel is intrusive to the PledgeImpl.
# The end fields in the channel should be the consumer
# to avoid cache-line conflicts with producer threads.
chan: ChannelMpscUnboundedBatch[TaskNode]
deferredIn: Atomic[int32]
deferredOut: Atomic[int32]
fulfilled: Atomic[bool]

probably because the data structures are distinct.

This makes it impossible to have PledgePtr[] be under 256 bytes. The 3 workarounds are:

  1. Increase WV_MemBlockSize to 512 bytes
  2. Don't have PledgeImpl intrusive to PledgePtr. This requires an extra allocation/pointer indirection
  3. Reduce the size taken by MPSC channels

Given that before nim-lang/Nim#13122, there was no padding and the MPSC channel could reasonably handle cache line invalidation and that in most MPSC channels implementations there is no padding at all, solution 3 is chosen in this PR

@mratsim mratsim force-pushed the update-mpsc-padding branch from 71cf681 to b4514e3 Compare January 18, 2020 18:51
@mratsim mratsim merged commit 61aad0a into master Jan 18, 2020
@mratsim mratsim deleted the update-mpsc-padding branch February 10, 2020 08:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant