Skip to content

Commit 93ac3b5

Browse files
committed
feat: Upstream NIOAsyncRuntime from PassiveLogic to swift-nio. NIOAsyncRuntime is a new module that provides MTELG and NIOThreadPool using Swift Concurrency. It compiles to wasm and runs in the browser.
1 parent 5bf0267 commit 93ac3b5

9 files changed

Lines changed: 1718 additions & 3 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftNIO open source project
4+
//
5+
// Copyright (c) 2026 Apple Inc. and the SwiftNIO project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
// NOTE: By and large the benchmarks here were ported from swift-nio
16+
// to allow side-by-side performance comparison
17+
//
18+
// See https://github.com/apple/swift-nio/blob/main/Benchmarks/Benchmarks/NIOPosixBenchmarks/Benchmarks.swift
19+
20+
import Benchmark
21+
import NIOAsyncRuntime
22+
import NIOCore
23+
24+
let benchmarks = {
25+
if #available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) {
26+
let eventLoop = AsyncEventLoopGroup.singleton.next()
27+
28+
let defaultMetrics: [BenchmarkMetric] = [
29+
.mallocCountTotal,
30+
.contextSwitches,
31+
.wallClock,
32+
]
33+
34+
Benchmark(
35+
"MTELG.immediateTasksThroughput",
36+
configuration: Benchmark.Configuration(
37+
metrics: defaultMetrics,
38+
scalingFactor: .mega,
39+
maxDuration: .seconds(10_000_000),
40+
maxIterations: 5
41+
)
42+
) { benchmark in
43+
func noOp() {}
44+
for _ in benchmark.scaledIterations {
45+
eventLoop.execute { noOp() }
46+
}
47+
}
48+
49+
Benchmark(
50+
"MTELG.scheduleTask(in:_:)",
51+
configuration: Benchmark.Configuration(
52+
metrics: defaultMetrics,
53+
scalingFactor: .mega,
54+
maxDuration: .seconds(10_000_000),
55+
maxIterations: 5
56+
)
57+
) { benchmark in
58+
for _ in benchmark.scaledIterations {
59+
eventLoop.scheduleTask(in: .hours(1), {})
60+
}
61+
}
62+
63+
Benchmark(
64+
"MTELG.scheduleCallback(in:_:)",
65+
configuration: Benchmark.Configuration(
66+
metrics: defaultMetrics,
67+
scalingFactor: .mega,
68+
maxDuration: .seconds(10_000_000),
69+
maxIterations: 5
70+
)
71+
) { benchmark in
72+
final class Timer: NIOScheduledCallbackHandler {
73+
func handleScheduledCallback(eventLoop: some EventLoop) {}
74+
}
75+
let timer = Timer()
76+
77+
benchmark.startMeasurement()
78+
for _ in benchmark.scaledIterations {
79+
let handle = try! eventLoop.scheduleCallback(in: .hours(1), handler: timer)
80+
}
81+
}
82+
83+
Benchmark(
84+
"Jump to EL and back using execute and unsafecontinuation",
85+
configuration: .init(
86+
metrics: defaultMetrics,
87+
scalingFactor: .kilo
88+
)
89+
) { benchmark in
90+
for _ in benchmark.scaledIterations {
91+
await withUnsafeContinuation { (continuation: UnsafeContinuation<Void, Never>) in
92+
eventLoop.execute {
93+
continuation.resume()
94+
}
95+
}
96+
}
97+
}
98+
99+
final actor Foo {
100+
nonisolated public let unownedExecutor: UnownedSerialExecutor
101+
102+
init(eventLoop: any EventLoop) {
103+
self.unownedExecutor = eventLoop.executor.asUnownedSerialExecutor()
104+
}
105+
106+
func foo() {
107+
blackHole(Void())
108+
}
109+
}
110+
111+
Benchmark(
112+
"Jump to EL and back using actor with EL executor",
113+
configuration: .init(
114+
metrics: defaultMetrics,
115+
scalingFactor: .kilo
116+
)
117+
) { benchmark in
118+
let actor = Foo(eventLoop: eventLoop)
119+
for _ in benchmark.scaledIterations {
120+
await actor.foo()
121+
}
122+
}
123+
}
124+
}

Benchmarks/Package.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,17 @@ let package = Package(
3636
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
3737
]
3838
),
39+
.executableTarget(
40+
name: "NIOAsyncRuntimeBenchmarks",
41+
dependencies: [
42+
.product(name: "Benchmark", package: "package-benchmark"),
43+
.product(name: "NIOCore", package: "swift-nio"),
44+
.product(name: "NIOAsyncRuntime", package: "swift-nio"),
45+
],
46+
path: "Benchmarks/NIOAsyncRuntimeBenchmarks",
47+
plugins: [
48+
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
49+
]
50+
),
3951
]
4052
)

Package.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ let package = Package(
4747
.library(name: "NIO", targets: ["NIO"]),
4848
.library(name: "NIOEmbedded", targets: ["NIOEmbedded"]),
4949
.library(name: "NIOPosix", targets: ["NIOPosix"]),
50+
.library(name: "NIOAsyncRuntime", targets: ["NIOAsyncRuntime"]),
5051
.library(name: "_NIOConcurrency", targets: ["_NIOConcurrency"]),
5152
.library(name: "NIOTLS", targets: ["NIOTLS"]),
5253
.library(name: "NIOHTTP1", targets: ["NIOHTTP1"]),
@@ -112,6 +113,14 @@ let package = Package(
112113
resources: includePrivacyManifest ? [.copy("PrivacyInfo.xcprivacy")] : [],
113114
swiftSettings: swiftSettings
114115
),
116+
.target(
117+
name: "NIOAsyncRuntime",
118+
dependencies: [
119+
"NIOCore",
120+
],
121+
exclude: ["README.md"],
122+
swiftSettings: swiftSettings
123+
),
115124
.target(
116125
name: "NIO",
117126
dependencies: [

0 commit comments

Comments
 (0)