From c82e4078cd2959970d38091be6c86f3c9f9fd94a Mon Sep 17 00:00:00 2001 From: Guoye Zhang Date: Sun, 27 Oct 2024 23:38:18 -0700 Subject: [PATCH 1/3] Adopt Mutex where available --- Sources/HTTPTypes/HTTPFields.swift | 57 ++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/Sources/HTTPTypes/HTTPFields.swift b/Sources/HTTPTypes/HTTPFields.swift index c5319b4..df8a141 100644 --- a/Sources/HTTPTypes/HTTPFields.swift +++ b/Sources/HTTPTypes/HTTPFields.swift @@ -12,6 +12,10 @@ // //===----------------------------------------------------------------------===// +#if canImport(Synchronization) +import Synchronization +#endif // canImport(Synchronization) + /// A collection of HTTP fields. It is used in `HTTPRequest` and `HTTPResponse`, and can also be /// used as HTTP trailer fields. /// @@ -21,13 +25,19 @@ /// `HTTPFields` adheres to modern HTTP semantics. In particular, the "Cookie" request header field /// is split into separate header fields by default. public struct HTTPFields: Sendable, Hashable { - private final class _Storage: @unchecked Sendable, Hashable { + private class _Storage: @unchecked Sendable, Hashable { var fields: [(field: HTTPField, next: UInt16)] = [] var index: [String: (first: UInt16, last: UInt16)]? = [:] - let lock = LockStorage.create(value: ()) + + required init() { + } + + func withLock(_ body: () throws -> Result) rethrows -> Result { + fatalError() + } var ensureIndex: [String: (first: UInt16, last: UInt16)] { - self.lock.withLockedValue { _ in + self.withLock { if let index = self.index { return index } @@ -45,10 +55,10 @@ public struct HTTPFields: Sendable, Hashable { } } - func copy() -> _Storage { - let newStorage = _Storage() + func copy() -> Self { + let newStorage = Self() newStorage.fields = self.fields - self.lock.withLockedValue { _ in + self.withLock { newStorage.index = self.index } return newStorage @@ -99,7 +109,40 @@ public struct HTTPFields: Sendable, Hashable { } } - private var _storage = _Storage() + #if canImport(Synchronization) + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) + private final class _StorageWithMutex: _Storage, @unchecked Sendable { + let mutex = Mutex(()) + + override func withLock(_ body: () throws -> Result) rethrows -> Result { + try self.mutex.withLock { _ in + try body() + } + } + } + #endif // canImport(Synchronization) + + private final class _StorageWithNIOLock: _Storage, @unchecked Sendable { + let lock = LockStorage.create(value: ()) + + override func withLock(_ body: () throws -> Result) rethrows -> Result { + try self.lock.withLockedValue { _ in + try body() + } + } + } + + private var _storage = { + #if canImport(Synchronization) + if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) { + _StorageWithMutex() + } else { + _StorageWithNIOLock() + } + #else // canImport(Synchronization) + _StorageWithNIOLock() + #endif // canImport(Synchronization) + }() /// Create an empty list of HTTP fields public init() {} From 06a234b69b66bbfc184360425c154a32dbdfec0c Mon Sep 17 00:00:00 2001 From: Guoye Zhang Date: Mon, 28 Oct 2024 18:00:33 -0700 Subject: [PATCH 2/3] Update baseline --- .../6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json | 2 +- .../Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json | 2 +- .../Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Benchmarks/Thresholds/6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json b/Benchmarks/Thresholds/6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json index bc880db..d30466d 100644 --- a/Benchmarks/Thresholds/6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json +++ b/Benchmarks/Thresholds/6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json @@ -1,3 +1,3 @@ { - "mallocCountTotal" : 14 + "mallocCountTotal" : 13 } \ No newline at end of file diff --git a/Benchmarks/Thresholds/nightly-6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json b/Benchmarks/Thresholds/nightly-6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json index bc880db..d30466d 100644 --- a/Benchmarks/Thresholds/nightly-6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json +++ b/Benchmarks/Thresholds/nightly-6.0/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json @@ -1,3 +1,3 @@ { - "mallocCountTotal" : 14 + "mallocCountTotal" : 13 } \ No newline at end of file diff --git a/Benchmarks/Thresholds/nightly-main/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json b/Benchmarks/Thresholds/nightly-main/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json index bc880db..d30466d 100644 --- a/Benchmarks/Thresholds/nightly-main/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json +++ b/Benchmarks/Thresholds/nightly-main/Benchmarks.HTTPFields.init(dictionaryLiteral).p90.json @@ -1,3 +1,3 @@ { - "mallocCountTotal" : 14 + "mallocCountTotal" : 13 } \ No newline at end of file From 32a95f29c1ae594471dc4b1e517974a952ae8543 Mon Sep 17 00:00:00 2001 From: Guoye Zhang Date: Mon, 28 Oct 2024 18:34:49 -0700 Subject: [PATCH 3/3] Check the compiler version instead --- Sources/HTTPTypes/HTTPFields.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/HTTPTypes/HTTPFields.swift b/Sources/HTTPTypes/HTTPFields.swift index df8a141..5b63be5 100644 --- a/Sources/HTTPTypes/HTTPFields.swift +++ b/Sources/HTTPTypes/HTTPFields.swift @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#if canImport(Synchronization) +#if compiler(>=6.0) import Synchronization -#endif // canImport(Synchronization) +#endif // compiler(>=6.0) /// A collection of HTTP fields. It is used in `HTTPRequest` and `HTTPResponse`, and can also be /// used as HTTP trailer fields. @@ -109,7 +109,7 @@ public struct HTTPFields: Sendable, Hashable { } } - #if canImport(Synchronization) + #if compiler(>=6.0) @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) private final class _StorageWithMutex: _Storage, @unchecked Sendable { let mutex = Mutex(()) @@ -120,7 +120,7 @@ public struct HTTPFields: Sendable, Hashable { } } } - #endif // canImport(Synchronization) + #endif // compiler(>=6.0) private final class _StorageWithNIOLock: _Storage, @unchecked Sendable { let lock = LockStorage.create(value: ()) @@ -133,15 +133,15 @@ public struct HTTPFields: Sendable, Hashable { } private var _storage = { - #if canImport(Synchronization) + #if compiler(>=6.0) if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) { _StorageWithMutex() } else { _StorageWithNIOLock() } - #else // canImport(Synchronization) + #else // compiler(>=6.0) _StorageWithNIOLock() - #endif // canImport(Synchronization) + #endif // compiler(>=6.0) }() /// Create an empty list of HTTP fields