mirror of
https://github.com/apple/swift-nio-extras.git
synced 2025-05-14 00:42:41 +08:00
Strict concurrency for NIOExtrasPerformanceTester (#263)
This commit is contained in:
parent
1a16877a1b
commit
cf3de22478
@ -91,7 +91,8 @@ var targets: [PackageDescription.Target] = [
|
||||
.product(name: "NIOPosix", package: "swift-nio"),
|
||||
.product(name: "NIOEmbedded", package: "swift-nio"),
|
||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||
]
|
||||
],
|
||||
swiftSettings: strictConcurrencySettings
|
||||
),
|
||||
.target(
|
||||
name: "NIOSOCKS",
|
||||
|
@ -13,56 +13,69 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
import NIOConcurrencyHelpers
|
||||
import NIOCore
|
||||
import NIOExtras
|
||||
|
||||
class HTTP1ThreadedPCapPerformanceTest: HTTP1ThreadedPerformanceTest {
|
||||
private class SinkHolder {
|
||||
var fileSink: NIOWritePCAPHandler.SynchronizedFileSink!
|
||||
private final class SinkHolder: Sendable {
|
||||
let fileSink: NIOLoopBound<NIOWritePCAPHandler.SynchronizedFileSink>
|
||||
let eventLoop: any EventLoop
|
||||
|
||||
init(eventLoop: any EventLoop) {
|
||||
self.eventLoop = eventLoop
|
||||
|
||||
func setUp() throws {
|
||||
let outputFile = NSTemporaryDirectory() + "/" + UUID().uuidString
|
||||
self.fileSink = try NIOWritePCAPHandler.SynchronizedFileSink.fileSinkWritingToFile(path: outputFile) {
|
||||
let fileSink = try! NIOWritePCAPHandler.SynchronizedFileSink.fileSinkWritingToFile(path: outputFile) {
|
||||
error in
|
||||
print("ERROR: \(error)")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
self.fileSink = NIOLoopBound(fileSink, eventLoop: eventLoop)
|
||||
}
|
||||
|
||||
func tearDown() {
|
||||
try! self.fileSink.syncClose()
|
||||
func tearDown() -> EventLoopFuture<Void> {
|
||||
self.eventLoop.submit {
|
||||
try self.fileSink.value.syncClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
let sinkHolder = SinkHolder()
|
||||
func addPCap(channel: Channel) -> EventLoopFuture<Void> {
|
||||
channel.eventLoop.submit {
|
||||
let pcapHandler = NIOWritePCAPHandler(
|
||||
mode: .client,
|
||||
fileSink: sinkHolder.fileSink.write
|
||||
)
|
||||
return try channel.pipeline.syncOperations.addHandler(pcapHandler, position: .first)
|
||||
}
|
||||
}
|
||||
|
||||
self.sinkHolder = sinkHolder
|
||||
let sinkHolders = NIOLockedValueBox<[SinkHolder]>([])
|
||||
self.sinkHolders = sinkHolders
|
||||
super.init(
|
||||
numberOfRepeats: 50,
|
||||
numberOfClients: System.coreCount,
|
||||
requestsPerClient: 500,
|
||||
extraInitialiser: { channel in addPCap(channel: channel) }
|
||||
extraInitialiser: { channel in
|
||||
channel.eventLoop.makeCompletedFuture {
|
||||
let sinkHolder = SinkHolder(eventLoop: channel.eventLoop)
|
||||
sinkHolders.withLockedValue { $0.append(sinkHolder) }
|
||||
|
||||
let pcapHandler = NIOWritePCAPHandler(
|
||||
mode: .client,
|
||||
fileSink: sinkHolder.fileSink.value.write(buffer:)
|
||||
)
|
||||
return try channel.pipeline.syncOperations.addHandler(pcapHandler, position: .first)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private let sinkHolder: SinkHolder
|
||||
private let sinkHolders: NIOLockedValueBox<[SinkHolder]>
|
||||
|
||||
override func run() throws -> Int {
|
||||
// Opening and closing the file included here as flushing data to disk is not known to complete until closed.
|
||||
try sinkHolder.setUp()
|
||||
defer {
|
||||
sinkHolder.tearDown()
|
||||
let result = Result {
|
||||
try super.run()
|
||||
}
|
||||
return try super.run()
|
||||
|
||||
let holders = self.sinkHolders.withLockedValue { $0 }
|
||||
for holder in holders {
|
||||
try holder.tearDown().wait()
|
||||
}
|
||||
|
||||
return try result.get()
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import NIOConcurrencyHelpers
|
||||
import NIOCore
|
||||
import NIOHTTP1
|
||||
import NIOPosix
|
||||
@ -107,7 +108,9 @@ final class RepeatedRequests: ChannelInboundHandler {
|
||||
let reqPart = self.unwrapInboundIn(data)
|
||||
if case .end(nil) = reqPart {
|
||||
if self.remainingNumberOfRequests <= 0 {
|
||||
context.channel.close().map { self.doneRequests }.cascade(to: self.isDonePromise)
|
||||
context.channel.close().assumeIsolated().map { self.doneRequests }.nonisolated().cascade(
|
||||
to: self.isDonePromise
|
||||
)
|
||||
} else {
|
||||
self.doneRequests += 1
|
||||
self.remainingNumberOfRequests -= 1
|
||||
@ -124,7 +127,7 @@ class HTTP1ThreadedPerformanceTest: Benchmark {
|
||||
let numberOfRepeats: Int
|
||||
let numberOfClients: Int
|
||||
let requestsPerClient: Int
|
||||
let extraInitialiser: (Channel) -> EventLoopFuture<Void>
|
||||
let extraInitialiser: @Sendable (Channel) -> EventLoopFuture<Void>
|
||||
|
||||
let head: HTTPRequestHead
|
||||
|
||||
@ -135,7 +138,7 @@ class HTTP1ThreadedPerformanceTest: Benchmark {
|
||||
numberOfRepeats: Int,
|
||||
numberOfClients: Int,
|
||||
requestsPerClient: Int,
|
||||
extraInitialiser: @escaping (Channel) -> EventLoopFuture<Void>
|
||||
extraInitialiser: @escaping @Sendable (Channel) -> EventLoopFuture<Void>
|
||||
) {
|
||||
self.numberOfRepeats = numberOfRepeats
|
||||
self.numberOfClients = numberOfClients
|
||||
@ -152,8 +155,10 @@ class HTTP1ThreadedPerformanceTest: Benchmark {
|
||||
self.serverChannel = try ServerBootstrap(group: self.group)
|
||||
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
|
||||
.childChannelInitializer { channel in
|
||||
channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: true).flatMap {
|
||||
channel.pipeline.addHandler(SimpleHTTPServer())
|
||||
channel.eventLoop.makeCompletedFuture {
|
||||
let sync = channel.pipeline.syncOperations
|
||||
try sync.configureHTTPServerPipeline(withPipeliningAssistance: true)
|
||||
try sync.addHandler(SimpleHTTPServer())
|
||||
}
|
||||
}.bind(host: "127.0.0.1", port: 0).wait()
|
||||
}
|
||||
@ -167,23 +172,31 @@ class HTTP1ThreadedPerformanceTest: Benchmark {
|
||||
var reqs: [Int] = []
|
||||
reqs.reserveCapacity(self.numberOfRepeats)
|
||||
for _ in 0..<self.numberOfRepeats {
|
||||
var requestHandlers: [RepeatedRequests] = []
|
||||
requestHandlers.reserveCapacity(self.numberOfClients)
|
||||
let requestsCompletedFutures = NIOLockedValueBox<[EventLoopFuture<Int>]>([])
|
||||
requestsCompletedFutures.withLockedValue({ $0.reserveCapacity(self.numberOfClients) })
|
||||
|
||||
var clientChannels: [Channel] = []
|
||||
clientChannels.reserveCapacity(self.numberOfClients)
|
||||
for _ in 0..<self.numberOfClients {
|
||||
let clientChannel = try! ClientBootstrap(group: self.group)
|
||||
.channelInitializer { channel in
|
||||
channel.pipeline.addHTTPClientHandlers().flatMap {
|
||||
.channelInitializer { [head, requestsPerClient, extraInitialiser] channel in
|
||||
channel.eventLoop.makeCompletedFuture {
|
||||
let sync = channel.pipeline.syncOperations
|
||||
try sync.addHTTPClientHandlers()
|
||||
|
||||
let repeatedRequestsHandler = RepeatedRequests(
|
||||
numberOfRequests: self.requestsPerClient,
|
||||
numberOfRequests: requestsPerClient,
|
||||
eventLoop: channel.eventLoop,
|
||||
head: self.head
|
||||
head: head
|
||||
)
|
||||
requestHandlers.append(repeatedRequestsHandler)
|
||||
return channel.pipeline.addHandler(repeatedRequestsHandler)
|
||||
|
||||
requestsCompletedFutures.withLockedValue {
|
||||
$0.append(repeatedRequestsHandler.completedFuture)
|
||||
}
|
||||
|
||||
try sync.addHandler(repeatedRequestsHandler)
|
||||
}.flatMap {
|
||||
self.extraInitialiser(channel)
|
||||
extraInitialiser(channel)
|
||||
}
|
||||
}
|
||||
.connect(to: self.serverChannel.localAddress!)
|
||||
@ -199,13 +212,12 @@ class HTTP1ThreadedPerformanceTest: Benchmark {
|
||||
let allWrites = EventLoopFuture<Void>.andAllComplete(writeFutures, on: writeFutures.first!.eventLoop)
|
||||
try! allWrites.wait()
|
||||
|
||||
let streamCompletedFutures = requestHandlers.map { rh in rh.completedFuture }
|
||||
let futures = requestsCompletedFutures.withLockedValue { $0 }
|
||||
let requestsServed = EventLoopFuture<Int>.reduce(
|
||||
0,
|
||||
streamCompletedFutures,
|
||||
on: streamCompletedFutures.first!.eventLoop,
|
||||
+
|
||||
)
|
||||
futures,
|
||||
on: futures.first!.eventLoop
|
||||
) { $0 + $1 }
|
||||
reqs.append(try! requestsServed.wait())
|
||||
}
|
||||
return reqs.reduce(0, +) / self.numberOfRepeats
|
||||
|
@ -17,6 +17,7 @@ import NIOExtras
|
||||
|
||||
class HTTP1ThreadedRollingPCapPerformanceTest: HTTP1ThreadedPerformanceTest {
|
||||
init() {
|
||||
@Sendable
|
||||
func addRollingPCap(channel: Channel) -> EventLoopFuture<Void> {
|
||||
channel.eventLoop.submit {
|
||||
let pcapRingBuffer = NIOPCAPRingBuffer(
|
||||
|
Loading…
x
Reference in New Issue
Block a user