Skip to content

Commit 73c7489

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

File tree

2 files changed

+38
-21
lines changed

2 files changed

+38
-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: 36 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,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+
10391056
extension SelectableEventLoop: CustomStringConvertible, CustomDebugStringConvertible {
10401057
@usableFromInline
10411058
var description: String {

0 commit comments

Comments
 (0)