From 921a1ad0c16908b7a5bcf538aca7a48766a6ad82 Mon Sep 17 00:00:00 2001 From: George Barnett Date: Fri, 5 Jul 2024 10:54:57 +0100 Subject: [PATCH] Avoid creating a yield ID counter per async writer 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..93679b5a3b 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 yieldIDCounter = 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: yieldIDCounter.loadThenWrappingIncrement(ordering: .relaxed)) } }