Skip to content

Commit f66497b

Browse files
committed
do not waste time when metrics delegate is not set
1 parent 5741df9 commit f66497b

File tree

2 files changed

+39
-21
lines changed

2 files changed

+39
-21
lines changed

Sources/NIOPosix/MultiThreadedEventLoopGroup.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ public final class MultiThreadedEventLoopGroup: EventLoopGroup {
107107
canBeShutdownIndividually: canEventLoopBeShutdownIndividually,
108108
metricsDelegate: metricsDelegate
109109
)
110-
threadSpecificEventLoop.currentValue = loop
110+
Self.threadSpecificEventLoop.currentValue = loop
111111
defer {
112-
threadSpecificEventLoop.currentValue = nil
112+
Self.threadSpecificEventLoop.currentValue = nil
113113
}
114114
callback(loop)
115115
try loop.run()

Sources/NIOPosix/SelectableEventLoop.swift

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
10391057
extension SelectableEventLoop: CustomStringConvertible, CustomDebugStringConvertible {
10401058
@usableFromInline
10411059
var description: String {

0 commit comments

Comments
 (0)