@@ -187,9 +187,7 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
187187 private let promiseCreationStoreLock = NIOLock ( )
188188 private var _promiseCreationStore : [ _NIOEventLoopFutureIdentifier : ( file: StaticString , line: UInt ) ] = [ : ]
189189
190- private let metricsDelegate : ( any NIOEventLoopMetricsDelegate ) ?
191-
192- private var lastTickEndTime : NIODeadline
190+ private var metricsDelegateState : MetricsDelegateState ?
193191
194192 @usableFromInline
195193 internal func _promiseCreated( futureIdentifier: _NIOEventLoopFutureIdentifier , file: StaticString , line: UInt ) {
@@ -261,7 +259,9 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
261259 canBeShutdownIndividually: Bool ,
262260 metricsDelegate: NIOEventLoopMetricsDelegate ?
263261 ) {
264- self . metricsDelegate = metricsDelegate
262+ self . metricsDelegateState = metricsDelegate. map { delegate in
263+ MetricsDelegateState ( metricsDelegate: delegate, lastTickEndime: . now( ) )
264+ }
265265 self . _uniqueID = uniqueID
266266 self . _parentGroup = parentGroup
267267 self . _selector = selector
@@ -270,7 +270,6 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
270270 self . msgBufferPool = Pool < PooledMsgBuffer > ( maxSize: 16 )
271271 self . tasksCopy. reserveCapacity ( Self . tasksCopyBatchSize)
272272 self . canBeShutdownIndividually = canBeShutdownIndividually
273- self . lastTickEndTime = . now( )
274273 // note: We are creating a reference cycle here that we'll break when shutting the SelectableEventLoop down.
275274 // note: We have to create the promise and complete it because otherwise we'll hit a loop in `makeSucceededFuture`. This is
276275 // fairly dumb, but it's the only option we have.
@@ -747,21 +746,34 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
747746 return nextDeadline
748747 }
749748
750- private func runLoop( selfIdentifier: ObjectIdentifier ) -> NIODeadline ? {
751- let tickStartTime : NIODeadline = . now( )
752- let sleepTime : TimeAmount = tickStartTime - self . lastTickEndTime
749+ private func runOneLoopTick( selfIdentifier: ObjectIdentifier ) -> NIODeadline ? {
750+ let tickStartInfo : (
751+ metricsDelegate: any NIOEventLoopMetricsDelegate ,
752+ tickStartTime: NIODeadline ,
753+ sleepTime: TimeAmount
754+ ) ? = self . metricsDelegateState. map { metricsDelegateState in
755+ let tickStartTime = NIODeadline . now ( ) // Potentially expensive, only if delegate set.
756+ return (
757+ metricsDelegate: metricsDelegateState. metricsDelegate,
758+ tickStartTime: tickStartTime,
759+ sleepTime: tickStartTime - metricsDelegateState. lastTickEndime
760+ )
761+ }
762+
753763 var tasksProcessedInTick = 0
754764 defer {
755- let tickEndTime : NIODeadline = . now( )
756- let tickInfo = NIOEventLoopTickInfo (
757- eventLoopID: selfIdentifier,
758- numberOfTasks: tasksProcessedInTick,
759- sleepTime: sleepTime,
760- startTime: tickStartTime,
761- endTime: tickEndTime
762- )
763- self . metricsDelegate? . processedTick ( info: tickInfo)
764- self . lastTickEndTime = tickEndTime
765+ if let tickStartInfo = tickStartInfo {
766+ let tickEndTime = NIODeadline . now ( ) // Potentially expensive, only if delegate set.
767+ let tickInfo = NIOEventLoopTickInfo (
768+ eventLoopID: selfIdentifier,
769+ numberOfTasks: tasksProcessedInTick,
770+ sleepTime: tickStartInfo. sleepTime,
771+ startTime: tickStartInfo. tickStartTime,
772+ endTime: tickEndTime
773+ )
774+ tickStartInfo. metricsDelegate. processedTick ( info: tickInfo)
775+ self . metricsDelegateState? . lastTickEndime = tickEndTime
776+ }
765777 }
766778 while true {
767779 let nextReadyDeadline = self . _tasksLock. withLock { ( ) -> NIODeadline ? in
@@ -905,7 +917,7 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
905917 }
906918 }
907919 }
908- nextReadyDeadline = runLoop ( selfIdentifier: selfIdentifier)
920+ nextReadyDeadline = self . runOneLoopTick ( selfIdentifier: selfIdentifier)
909921 }
910922
911923 // This EventLoop was closed so also close the underlying selector.
@@ -1036,6 +1048,11 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
10361048 }
10371049}
10381050
1051+ struct MetricsDelegateState {
1052+ var metricsDelegate : any NIOEventLoopMetricsDelegate
1053+ var lastTickEndime : NIODeadline
1054+ }
1055+
10391056extension SelectableEventLoop : CustomStringConvertible , CustomDebugStringConvertible {
10401057 @usableFromInline
10411058 var description : String {
0 commit comments