Skip to content

Commit 115dc40

Browse files
committed
Playing around with Perf
1 parent a5a087a commit 115dc40

File tree

5 files changed

+166
-6
lines changed

5 files changed

+166
-6
lines changed

Benchmarks/Package.swift

+11-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ let package = Package(
1010
dependencies: [
1111
.package(path: "../"),
1212
.package(url: "https://github.com/ordo-one/package-benchmark.git", from: "1.29.0"),
13-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.82.0"),
13+
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.14.0"),
14+
.package(name: "swift-nio", path: "../../../apple/swift-nio"),
1415
],
1516
targets: [
1617
.executableTarget(
@@ -27,5 +28,14 @@ let package = Package(
2728
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
2829
]
2930
),
31+
.executableTarget(
32+
name: "PostgresPerf",
33+
dependencies: [
34+
.product(name: "PostgresNIO", package: "postgres-nio"),
35+
.product(name: "PostgresKit", package: "postgres-kit"),
36+
.product(name: "NIOCore", package: "swift-nio"),
37+
.product(name: "NIOPosix", package: "swift-nio"),
38+
],
39+
)
3040
]
3141
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// PostgresPerf.swift
3+
// benchmarks
4+
//
5+
// Created by Fabian Fett on 12.05.25.
6+
//
7+
8+
import Synchronization
9+
import PostgresNIO
10+
@preconcurrency import PostgresKit
11+
@preconcurrency import AsyncKit
12+
13+
@main
14+
@available(macOS 15.0, *)
15+
enum PostgresPerf {
16+
17+
static let maxConnections: Int = 400
18+
static let tasks: Int = 400
19+
static let iterationsPerTask: Int = 1000
20+
static let logger = Logger(label: "TestLogger")
21+
static let clock = ContinuousClock()
22+
23+
static let eventLoopCount = {
24+
NIOSingletons.posixEventLoopGroup.makeIterator().reduce(0, { (res, _) in res + 1 })
25+
}()
26+
27+
static func main() async throws {
28+
// if CommandLine.arguments.first == "kit" {
29+
try await Self.runPostgresKit()
30+
// } else {
31+
try await self.runPostgresNIO()
32+
// }
33+
}
34+
35+
static func runPostgresKit() async throws {
36+
let configuration = SQLPostgresConfiguration(
37+
hostname: "localhost", port: 5432,
38+
username: "test_username",
39+
password: "test_password",
40+
database: "test_database",
41+
tls: .disable
42+
)
43+
44+
let pools = EventLoopGroupConnectionPool(
45+
source: PostgresConnectionSource(sqlConfiguration: configuration),
46+
maxConnectionsPerEventLoop: Self.maxConnections / Self.eventLoopCount,
47+
on: NIOSingletons.posixEventLoopGroup
48+
)
49+
50+
let start = self.clock.now
51+
await withThrowingTaskGroup(of: Void.self) { taskGroup in
52+
for _ in 0..<Self.tasks {
53+
taskGroup.addTask {
54+
for _ in 0..<Self.iterationsPerTask {
55+
_ = try await pools.withConnection { connection in
56+
connection.query("SELECT 1;", logger: Self.logger) { row in
57+
let foo = try row.decode(Int.self)
58+
}
59+
}.get()
60+
}
61+
}
62+
}
63+
64+
for _ in 0..<Self.tasks {
65+
_ = await taskGroup.nextResult()!
66+
}
67+
68+
taskGroup.cancelAll()
69+
}
70+
71+
try await pools.shutdownAsync()
72+
let end = self.clock.now
73+
74+
self.logger.info("PostgresKit completed", metadata: ["Took": "\(end - start)"])
75+
}
76+
77+
static func runPostgresNIO() async throws {
78+
var tlsConfiguration = TLSConfiguration.makeClientConfiguration()
79+
tlsConfiguration.certificateVerification = .none
80+
var clientConfig = PostgresClient.Configuration(
81+
host: env("POSTGRES_HOSTNAME") ?? "localhost",
82+
port: env("POSTGRES_PORT").flatMap({ Int($0) }) ?? 5432,
83+
username: env("POSTGRES_USER") ?? "test_username",
84+
password: env("POSTGRES_PASSWORD") ?? "test_password",
85+
database: env("POSTGRES_DB") ?? "test_database",
86+
tls: .prefer(tlsConfiguration)
87+
)
88+
clientConfig.options.minimumConnections = 0
89+
clientConfig.options.maximumConnections = Self.maxConnections
90+
clientConfig.options.keepAliveBehavior = .init(frequency: .seconds(5))
91+
clientConfig.options.connectionIdleTimeout = .seconds(15)
92+
93+
94+
let client = PostgresClient(
95+
configuration: clientConfig,
96+
eventLoopGroup: NIOSingletons.posixEventLoopGroup
97+
)
98+
99+
let start = self.clock.now
100+
await withThrowingTaskGroup(of: Void.self) { taskGroup in
101+
taskGroup.addTask {
102+
await client.run()
103+
}
104+
105+
// let atomic = Atomic(0)
106+
for _ in 0..<Self.tasks {
107+
taskGroup.addTask {
108+
for _ in 0..<Self.iterationsPerTask {
109+
let rows = try await client.query("SELECT 1;")
110+
for try await row in rows.decode(Int.self) {
111+
// atomic.add(row, ordering: .relaxed)
112+
}
113+
}
114+
}
115+
}
116+
117+
for _ in 0..<Self.tasks {
118+
_ = await taskGroup.nextResult()!
119+
}
120+
121+
taskGroup.cancelAll()
122+
}
123+
let end = self.clock.now
124+
125+
self.logger.info("PostgresNIO completed", metadata: ["Took": "\(end - start)"])
126+
}
127+
}
128+
129+
func env(_ name: String) -> String? {
130+
getenv(name).flatMap { String(cString: $0) }
131+
}

Sources/ConnectionPoolModule/ConnectionPool.swift

-1
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,6 @@ public final class ConnectionPool<
524524

525525
@inlinable
526526
/*private*/ func runTimer(_ timer: StateMachine.Timer, in taskGroup: inout some TaskGroupProtocol) {
527-
print("timer: \(timer.connectionID), underlying: \(timer.underlying.usecase)")
528527
self.addTask(into: &taskGroup) { () async -> () in
529528
await withTaskGroup(of: TimerRunResult.self, returning: Void.self) { taskGroup in
530529
taskGroup.addTask {

Sources/PostgresNIO/Pool/PostgresClient.swift

+23-4
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,19 @@ public final class PostgresClient: Sendable, ServiceLifecycle.Service {
233233
}
234234
}
235235

236+
typealias PoolManager = ConnectionPoolManager<
237+
PostgresConnection,
238+
PostgresConnection.ID,
239+
ConnectionIDGenerator,
240+
Foo,
241+
ConnectionRequest<PostgresConnection>,
242+
ConnectionRequest.ID,
243+
PostgresKeepAliveBehavor,
244+
NothingConnectionPoolExecutor,
245+
PostgresClientMetrics,
246+
ContinuousClock
247+
>
248+
236249
typealias Pool = ConnectionPool<
237250
PostgresConnection,
238251
PostgresConnection.ID,
@@ -246,7 +259,7 @@ public final class PostgresClient: Sendable, ServiceLifecycle.Service {
246259
ContinuousClock
247260
>
248261

249-
let pool: Pool
262+
let pool: PoolManager
250263
let factory: ConnectionFactory
251264
let runningAtomic = ManagedAtomic(false)
252265
let backgroundLogger: Logger
@@ -282,13 +295,19 @@ public final class PostgresClient: Sendable, ServiceLifecycle.Service {
282295
self.factory = factory
283296
self.backgroundLogger = backgroundLogger
284297

285-
self.pool = ConnectionPool(
286-
configuration: .init(configuration),
298+
let executors = (0..<10).map { _ in NothingConnectionPoolExecutor() }
299+
var poolManagerConfiguration = ConnectionPoolManagerConfiguration()
300+
poolManagerConfiguration.minimumConnectionPerExecutorCount = configuration.options.minimumConnections / executors.count
301+
poolManagerConfiguration.maximumConnectionPerExecutorSoftLimit = configuration.options.maximumConnections / executors.count
302+
poolManagerConfiguration.maximumConnectionPerExecutorHardLimit = configuration.options.maximumConnections / executors.count
303+
304+
self.pool = ConnectionPoolManager(
305+
configuration: poolManagerConfiguration,
287306
connectionConfiguration: Foo(),
288307
idGenerator: ConnectionIDGenerator(),
289308
requestType: ConnectionRequest<PostgresConnection>.self,
290309
keepAliveBehavior: .init(configuration.options.keepAliveBehavior, logger: backgroundLogger),
291-
executor: NothingConnectionPoolExecutor(),
310+
executors: executors,
292311
observabilityDelegate: .init(logger: backgroundLogger),
293312
clock: ContinuousClock()
294313
) { (connectionID, connectionConfiguration, pool) in

docker-compose.yml

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
version: '3.7'
22

33
x-shared-config: &shared_config
4+
command: -c 'max_connections=500'
45
environment:
56
POSTGRES_HOST_AUTH_METHOD: "${POSTGRES_HOST_AUTH_METHOD:-scram-sha-256}"
67
POSTGRES_USER: test_username

0 commit comments

Comments
 (0)