Skip to content

Commit f04675d

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 3f80264 commit f04675d

8 files changed

Lines changed: 1615 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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+
private let eventLoop = MultiThreadedEventLoopGroup.singleton.next()
25+
26+
let benchmarks = {
27+
let defaultMetrics: [BenchmarkMetric] = [
28+
.mallocCountTotal,
29+
.contextSwitches,
30+
.wallClock,
31+
]
32+
33+
Benchmark(
34+
"MTELG.immediateTasksThroughput",
35+
configuration: Benchmark.Configuration(
36+
metrics: defaultMetrics,
37+
scalingFactor: .mega,
38+
maxDuration: .seconds(10_000_000),
39+
maxIterations: 5
40+
)
41+
) { benchmark in
42+
func noOp() {}
43+
for _ in benchmark.scaledIterations {
44+
eventLoop.execute { noOp() }
45+
}
46+
}
47+
48+
Benchmark(
49+
"MTELG.scheduleTask(in:_:)",
50+
configuration: Benchmark.Configuration(
51+
metrics: defaultMetrics,
52+
scalingFactor: .mega,
53+
maxDuration: .seconds(10_000_000),
54+
maxIterations: 5
55+
)
56+
) { benchmark in
57+
for _ in benchmark.scaledIterations {
58+
eventLoop.scheduleTask(in: .hours(1), {})
59+
}
60+
}
61+
62+
Benchmark(
63+
"MTELG.scheduleCallback(in:_:)",
64+
configuration: Benchmark.Configuration(
65+
metrics: defaultMetrics,
66+
scalingFactor: .mega,
67+
maxDuration: .seconds(10_000_000),
68+
maxIterations: 5
69+
)
70+
) { benchmark in
71+
final class Timer: NIOScheduledCallbackHandler {
72+
func handleScheduledCallback(eventLoop: some EventLoop) {}
73+
}
74+
let timer = Timer()
75+
76+
benchmark.startMeasurement()
77+
for _ in benchmark.scaledIterations {
78+
let handle = try! eventLoop.scheduleCallback(in: .hours(1), handler: timer)
79+
}
80+
}
81+
82+
Benchmark(
83+
"Jump to EL and back using execute and unsafecontinuation",
84+
configuration: .init(
85+
metrics: defaultMetrics,
86+
scalingFactor: .kilo
87+
)
88+
) { benchmark in
89+
for _ in benchmark.scaledIterations {
90+
await withUnsafeContinuation { (continuation: UnsafeContinuation<Void, Never>) in
91+
eventLoop.execute {
92+
continuation.resume()
93+
}
94+
}
95+
}
96+
}
97+
98+
final actor Foo {
99+
nonisolated public let unownedExecutor: UnownedSerialExecutor
100+
101+
init(eventLoop: any EventLoop) {
102+
self.unownedExecutor = eventLoop.executor.asUnownedSerialExecutor()
103+
}
104+
105+
func foo() {
106+
blackHole(Void())
107+
}
108+
}
109+
110+
Benchmark(
111+
"Jump to EL and back using actor with EL executor",
112+
configuration: .init(
113+
metrics: defaultMetrics,
114+
scalingFactor: .kilo
115+
)
116+
) { benchmark in
117+
let actor = Foo(eventLoop: eventLoop)
118+
for _ in benchmark.scaledIterations {
119+
await actor.foo()
120+
}
121+
}
122+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
#if canImport(Darwin)
21+
import Darwin.C
22+
#elseif canImport(Glibc)
23+
import Glibc
24+
#else
25+
#error("Unsupported platform.")
26+
#endif
27+
28+
// This file allows us to hook the global executor which
29+
// we can use to mimic task executors for now.
30+
typealias EnqueueGlobalHook =
31+
@convention(thin) (UnownedJob, @convention(thin) (UnownedJob) -> Void) -> Void
32+
33+
var swiftTaskEnqueueGlobalHook: EnqueueGlobalHook? {
34+
get { _swiftTaskEnqueueGlobalHook.pointee }
35+
set { _swiftTaskEnqueueGlobalHook.pointee = newValue }
36+
}
37+
38+
private let _swiftTaskEnqueueGlobalHook: UnsafeMutablePointer<EnqueueGlobalHook?> =
39+
dlsym(dlopen(nil, RTLD_LAZY), "swift_task_enqueueGlobal_hook").assumingMemoryBound(
40+
to: EnqueueGlobalHook?.self
41+
)

Package.swift

Lines changed: 10 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,15 @@ let package = Package(
112113
resources: includePrivacyManifest ? [.copy("PrivacyInfo.xcprivacy")] : [],
113114
swiftSettings: swiftSettings
114115
),
116+
.target(
117+
name: "NIOAsyncRuntime",
118+
dependencies: [
119+
"NIOCore",
120+
swiftAtomics,
121+
],
122+
exclude: ["README.md"],
123+
swiftSettings: swiftSettings
124+
),
115125
.target(
116126
name: "NIO",
117127
dependencies: [

0 commit comments

Comments
 (0)