From abbb144f6678d0d830899b8bda5eea5924a61c0d Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 9 Jul 2024 13:27:35 +0100 Subject: [PATCH] Avoid creating a yield ID counter per async writer (#2768) 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 --- Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift b/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift index f0fc90378d..fe7e6af235 100644 --- a/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift +++ b/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift @@ -17,6 +17,9 @@ import DequeModule import NIOConcurrencyHelpers import _NIODataStructures +@usableFromInline +let _asyncWriterYieldIDCounter = ManagedAtomic(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. /// @@ -434,14 +437,11 @@ extension NIOAsyncWriter { } } - @usableFromInline - /* private */ internal let _yieldIDCounter = ManagedAtomic(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)) } }