Skip to content

Commit b775835

Browse files
authored
Add Benchmarks for ConnectionPool (#545)
1 parent 59c0215 commit b775835

13 files changed

+110
-13
lines changed

Diff for: Benchmarks/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.build
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import _ConnectionPoolModule
2+
import _ConnectionPoolTestUtils
3+
import Benchmark
4+
5+
let benchmarks: @Sendable () -> Void = {
6+
Benchmark("Minimal benchmark", configuration: .init(scalingFactor: .kilo)) { benchmark in
7+
let clock = MockClock()
8+
let factory = MockConnectionFactory<MockClock>(autoMaxStreams: 1)
9+
var configuration = ConnectionPoolConfiguration()
10+
configuration.maximumConnectionSoftLimit = 50
11+
configuration.maximumConnectionHardLimit = 50
12+
13+
let pool = ConnectionPool(
14+
configuration: configuration,
15+
idGenerator: ConnectionIDGenerator(),
16+
keepAliveBehavior: MockPingPongBehavior(keepAliveFrequency: nil, connectionType: MockConnection.self),
17+
observabilityDelegate: NoOpConnectionPoolMetrics(connectionIDType: MockConnection.ID.self),
18+
clock: clock
19+
) {
20+
try await factory.makeConnection(id: $0, for: $1)
21+
}
22+
23+
await withTaskGroup { taskGroup in
24+
25+
taskGroup.addTask {
26+
await pool.run()
27+
}
28+
29+
let sequential = benchmark.scaledIterations.upperBound / configuration.maximumConnectionSoftLimit
30+
31+
for parallel in 0..<configuration.maximumConnectionSoftLimit {
32+
taskGroup.addTask {
33+
for _ in 0..<sequential {
34+
do {
35+
try await pool.withConnection { connection in
36+
blackHole(connection)
37+
}
38+
} catch {
39+
fatalError()
40+
}
41+
}
42+
}
43+
}
44+
45+
for i in 0..<configuration.maximumConnectionSoftLimit {
46+
await taskGroup.next()
47+
}
48+
taskGroup.cancelAll()
49+
}
50+
}
51+
}

Diff for: Benchmarks/Package.swift

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// swift-tools-version: 6.0
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "benchmarks",
7+
platforms: [
8+
.macOS("14")
9+
],
10+
dependencies: [
11+
.package(path: "../"),
12+
.package(url: "https://github.com/ordo-one/package-benchmark.git", from: "1.29.0"),
13+
],
14+
targets: [
15+
.executableTarget(
16+
name: "ConnectionPoolBenchmarks",
17+
dependencies: [
18+
.product(name: "_ConnectionPoolModule", package: "postgres-nio"),
19+
.product(name: "_ConnectionPoolTestUtils", package: "postgres-nio"),
20+
.product(name: "Benchmark", package: "package-benchmark"),
21+
],
22+
path: "Benchmarks/ConnectionPoolBenchmarks",
23+
plugins: [
24+
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
25+
]
26+
),
27+
]
28+
)

Diff for: Package.swift

+6-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ let package = Package(
1616
products: [
1717
.library(name: "PostgresNIO", targets: ["PostgresNIO"]),
1818
.library(name: "_ConnectionPoolModule", targets: ["_ConnectionPoolModule"]),
19+
.library(name: "_ConnectionPoolTestUtils", targets: ["_ConnectionPoolTestUtils"]),
1920
],
2021
dependencies: [
2122
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.2.0"),
@@ -58,11 +59,13 @@ let package = Package(
5859
swiftSettings: swiftSettings
5960
),
6061
.target(
61-
name: "ConnectionPoolTestUtils",
62+
name: "_ConnectionPoolTestUtils",
6263
dependencies: [
6364
"_ConnectionPoolModule",
6465
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
65-
]
66+
],
67+
path: "Sources/ConnectionPoolTestUtils",
68+
swiftSettings: swiftSettings
6669
),
6770
.testTarget(
6871
name: "PostgresNIOTests",
@@ -77,7 +80,7 @@ let package = Package(
7780
name: "ConnectionPoolModuleTests",
7881
dependencies: [
7982
.target(name: "_ConnectionPoolModule"),
80-
.target(name: "ConnectionPoolTestUtils"),
83+
.target(name: "_ConnectionPoolTestUtils"),
8184
.product(name: "DequeModule", package: "swift-collections"),
8285
.product(name: "NIOCore", package: "swift-nio"),
8386
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),

Diff for: Sources/ConnectionPoolTestUtils/MockConnectionFactory.swift

+14-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ public final class MockConnectionFactory<Clock: _Concurrency.Clock>: Sendable wh
2121
var runningConnections = [ConnectionID: Connection]()
2222
}
2323

24-
public init() {}
24+
let autoMaxStreams: UInt16?
25+
26+
public init(autoMaxStreams: UInt16? = nil) {
27+
self.autoMaxStreams = autoMaxStreams
28+
}
2529

2630
public var pendingConnectionAttemptsCount: Int {
2731
self.stateBox.withLockedValue { $0.attempts.count }
@@ -35,6 +39,15 @@ public final class MockConnectionFactory<Clock: _Concurrency.Clock>: Sendable wh
3539
id: Int,
3640
for pool: ConnectionPool<MockConnection, Int, ConnectionIDGenerator, some ConnectionRequestProtocol, Int, MockPingPongBehavior<MockConnection>, NoOpConnectionPoolMetrics<Int>, Clock>
3741
) async throws -> ConnectionAndMetadata<MockConnection> {
42+
if let autoMaxStreams = self.autoMaxStreams {
43+
let connection = MockConnection(id: id)
44+
Task {
45+
try? await connection.signalToClose
46+
connection.closeIfClosing()
47+
}
48+
return .init(connection: connection, maximalStreamsOnConnection: autoMaxStreams)
49+
}
50+
3851
// we currently don't support cancellation when creating a connection
3952
let result = try await withCheckedThrowingContinuation { (checkedContinuation: CheckedContinuation<(MockConnection, UInt16), any Error>) in
4053
let waiter = self.stateBox.withLockedValue { state -> (CheckedContinuation<(ConnectionID, CheckedContinuation<(MockConnection, UInt16), any Error>), Never>)? in

Diff for: Sources/ConnectionPoolTestUtils/MockPingPongBehaviour.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
@testable import _ConnectionPoolModule
1+
import _ConnectionPoolModule
22
import DequeModule
3+
import NIOConcurrencyHelpers
34

45
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
56
public final class MockPingPongBehavior<Connection: PooledConnection>: ConnectionKeepAliveBehavior {

Diff for: Tests/ConnectionPoolModuleTests/ConnectionPoolTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@testable import _ConnectionPoolModule
2+
import _ConnectionPoolTestUtils
23
import Atomics
3-
import ConnectionPoolTestUtils
44
import NIOEmbedded
55
import XCTest
66

Diff for: Tests/ConnectionPoolModuleTests/ConnectionRequestTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@testable import _ConnectionPoolModule
2-
import ConnectionPoolTestUtils
2+
import _ConnectionPoolTestUtils
33
import XCTest
44

55
final class ConnectionRequestTests: XCTestCase {

Diff for: Tests/ConnectionPoolModuleTests/NoKeepAliveBehaviorTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _ConnectionPoolModule
2-
import ConnectionPoolTestUtils
2+
import _ConnectionPoolTestUtils
33
import XCTest
44

55
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)

Diff for: Tests/ConnectionPoolModuleTests/PoolStateMachine+ConnectionGroupTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@testable import _ConnectionPoolModule
2-
import ConnectionPoolTestUtils
2+
import _ConnectionPoolTestUtils
33
import XCTest
44

55
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)

Diff for: Tests/ConnectionPoolModuleTests/PoolStateMachine+ConnectionStateTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@testable import _ConnectionPoolModule
2-
import ConnectionPoolTestUtils
2+
import _ConnectionPoolTestUtils
33
import XCTest
44

55
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)

Diff for: Tests/ConnectionPoolModuleTests/PoolStateMachine+RequestQueueTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@testable import _ConnectionPoolModule
2-
import ConnectionPoolTestUtils
2+
import _ConnectionPoolTestUtils
33
import XCTest
44

55
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)

Diff for: Tests/ConnectionPoolModuleTests/PoolStateMachineTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import ConnectionPoolTestUtils
2-
import XCTest
31
@testable import _ConnectionPoolModule
2+
import _ConnectionPoolTestUtils
3+
import XCTest
44

55
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
66
typealias TestPoolStateMachine = PoolStateMachine<

0 commit comments

Comments
 (0)