@@ -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,35 @@ 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+ (
752+ metricsDelegate: any NIOEventLoopMetricsDelegate ,
753+ tickStartTime: NIODeadline ,
754+ sleepTime: TimeAmount
755+ ) ? = self . metricsDelegateState. map { metricsDelegateState in
756+ let tickStartTime = NIODeadline . now ( ) // Potentially expensive, only if delegate set.
757+ return (
758+ metricsDelegate: metricsDelegateState. metricsDelegate,
759+ tickStartTime: tickStartTime,
760+ sleepTime: tickStartTime - metricsDelegateState. lastTickEndime
761+ )
762+ }
763+
753764 var tasksProcessedInTick = 0
754765 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
766+ if let tickStartInfo = tickStartInfo {
767+ let tickEndTime = NIODeadline . now ( ) // Potentially expensive, only if delegate set.
768+ let tickInfo = NIOEventLoopTickInfo (
769+ eventLoopID: selfIdentifier,
770+ numberOfTasks: tasksProcessedInTick,
771+ sleepTime: tickStartInfo. sleepTime,
772+ startTime: tickStartInfo. tickStartTime,
773+ endTime: tickEndTime
774+ )
775+ tickStartInfo. metricsDelegate. processedTick ( info: tickInfo)
776+ self . metricsDelegateState? . lastTickEndime = tickEndTime
777+ }
765778 }
766779 while true {
767780 let nextReadyDeadline = self . _tasksLock. withLock { ( ) -> NIODeadline ? in
@@ -905,7 +918,7 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
905918 }
906919 }
907920 }
908- nextReadyDeadline = runLoop ( selfIdentifier: selfIdentifier)
921+ nextReadyDeadline = self . runOneLoopTick ( selfIdentifier: selfIdentifier)
909922 }
910923
911924 // This EventLoop was closed so also close the underlying selector.
@@ -1036,6 +1049,11 @@ internal final class SelectableEventLoop: EventLoop, @unchecked Sendable {
10361049 }
10371050}
10381051
1052+ struct MetricsDelegateState {
1053+ var metricsDelegate : any NIOEventLoopMetricsDelegate
1054+ var lastTickEndime : NIODeadline
1055+ }
1056+
10391057extension SelectableEventLoop : CustomStringConvertible , CustomDebugStringConvertible {
10401058 @usableFromInline
10411059 var description : String {
0 commit comments