Skip to content

Commit

Permalink
Avoid creating a yield ID counter per async writer (#2768)
Browse files Browse the repository at this point in the history
Motivation:

The NIOAsyncWriter uses an atomic to generate yield IDs. Each writer has
its own atomic. We can save an allocatiuon per writer but using a shared
atomic.

Each load then wrapping increment operation with relaxed ordering takes
approx 3ns on my machine. For a UInt64 this would take approx 188 years
to wrap around if run in a tight loop.

Modification:

- Share a single yield ID counter for NIOAsyncWriter

Result:

Fewer allocations
  • Loading branch information
glbrntt authored Jul 9, 2024
1 parent 5cc0549 commit abbb144
Showing 1 changed file with 4 additions and 4 deletions.
8 changes: 4 additions & 4 deletions Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import DequeModule
import NIOConcurrencyHelpers
import _NIODataStructures

@usableFromInline
let _asyncWriterYieldIDCounter = ManagedAtomic<UInt64>(0)

/// The delegate of the ``NIOAsyncWriter``. It is the consumer of the yielded writes to the ``NIOAsyncWriter``.
/// Furthermore, the delegate gets informed when the ``NIOAsyncWriter`` terminated.
///
Expand Down Expand Up @@ -434,14 +437,11 @@ extension NIOAsyncWriter {
}
}

@usableFromInline
/* private */ internal let _yieldIDCounter = ManagedAtomic<UInt64>(0)

@inlinable
func generateUniqueYieldID() -> YieldID {
// Using relaxed is fine here since we do not need any strict ordering just a
// unique ID for every yield.
.init(value: self._yieldIDCounter.loadThenWrappingIncrement(ordering: .relaxed))
.init(value: _asyncWriterYieldIDCounter.loadThenWrappingIncrement(ordering: .relaxed))
}
}

Expand Down

0 comments on commit abbb144

Please sign in to comment.