Avoid curried thunks (workaround SR-12115) (#1374)
Motivation: Calling `function(otherFunction)` allocates, but `function({ otherFunction($0) }` does not. See: SR-12115 and SR-12116. Modifications: Avoid passing functions directly; pass them in new closures instead. Result: Fewer allocations.
This commit is contained in:
parent
2bf296958b
commit
b4483e5c49
|
@ -398,13 +398,13 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
switch address {
|
||||
case .v4(let address):
|
||||
var addr = address.address
|
||||
try addr.withSockAddr(doBind)
|
||||
try addr.withSockAddr({ try doBind(ptr: $0, bytes: $1) })
|
||||
case .v6(let address):
|
||||
var addr = address.address
|
||||
try addr.withSockAddr(doBind)
|
||||
try addr.withSockAddr({ try doBind(ptr: $0, bytes: $1) })
|
||||
case .unixDomainSocket(let address):
|
||||
var addr = address.address
|
||||
try addr.withSockAddr(doBind)
|
||||
try addr.withSockAddr({ try doBind(ptr: $0, bytes: $1) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ class BaseStreamSocketChannel<Socket: SocketProtocol>: BaseSocketChannel<Socket>
|
|||
// Reset reader and writerIndex and so allow to have the buffer filled again. This is better here than at
|
||||
// the end of the loop to not do an allocation when the loop exits.
|
||||
buffer.clear()
|
||||
switch try buffer.withMutableWritePointer(body: self.socket.read(pointer:)) {
|
||||
switch try buffer.withMutableWritePointer(body: { try self.socket.read(pointer: $0) }) {
|
||||
case .processed(let bytesRead):
|
||||
if bytesRead > 0 {
|
||||
let mayGrow = recvAllocator.record(actualReadBytes: bytesRead)
|
||||
|
|
|
@ -258,7 +258,7 @@ extension ByteBuffer {
|
|||
@discardableResult
|
||||
@inlinable
|
||||
public mutating func readWithUnsafeReadableBytes(_ body: (UnsafeRawBufferPointer) throws -> Int) rethrows -> Int {
|
||||
let bytesRead = try self.withUnsafeReadableBytes(body)
|
||||
let bytesRead = try self.withUnsafeReadableBytes({ try body($0) })
|
||||
self._moveReaderIndex(forwardBy: bytesRead)
|
||||
return bytesRead
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ extension ByteBuffer {
|
|||
/// - returns: The value `body` returned in the second tuple component.
|
||||
@inlinable
|
||||
public mutating func readWithUnsafeReadableBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> (Int, T)) rethrows -> T {
|
||||
let (bytesRead, ret) = try self.withUnsafeReadableBytes(body)
|
||||
let (bytesRead, ret) = try self.withUnsafeReadableBytes({ try body($0) })
|
||||
self._moveReaderIndex(forwardBy: bytesRead)
|
||||
return ret
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ extension ByteBuffer {
|
|||
@discardableResult
|
||||
@inlinable
|
||||
public mutating func readWithUnsafeMutableReadableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> Int) rethrows -> Int {
|
||||
let bytesRead = try self.withUnsafeMutableReadableBytes(body)
|
||||
let bytesRead = try self.withUnsafeMutableReadableBytes({ try body($0) })
|
||||
self._moveReaderIndex(forwardBy: bytesRead)
|
||||
return bytesRead
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ extension ByteBuffer {
|
|||
/// - returns: The value `body` returned in the second tuple component.
|
||||
@inlinable
|
||||
public mutating func readWithUnsafeMutableReadableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> (Int, T)) rethrows -> T {
|
||||
let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes(body)
|
||||
let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes({ try body($0) })
|
||||
self._moveReaderIndex(forwardBy: bytesRead)
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -515,7 +515,7 @@ public struct ByteBuffer {
|
|||
if minimumWritableBytes > 0 {
|
||||
self.reserveCapacity(self.writerIndex + minimumWritableBytes)
|
||||
}
|
||||
let bytesWritten = try self.withUnsafeMutableWritableBytes(body)
|
||||
let bytesWritten = try self.withUnsafeMutableWritableBytes({ try body($0) })
|
||||
self._moveWriterIndex(to: self._writerIndex + _toIndex(bytesWritten))
|
||||
return bytesWritten
|
||||
}
|
||||
|
@ -524,7 +524,7 @@ public struct ByteBuffer {
|
|||
@discardableResult
|
||||
@inlinable
|
||||
public mutating func writeWithUnsafeMutableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> Int) rethrows -> Int {
|
||||
return try self.writeWithUnsafeMutableBytes(minimumWritableBytes: 0, body)
|
||||
return try self.writeWithUnsafeMutableBytes(minimumWritableBytes: 0, { try body($0) })
|
||||
}
|
||||
|
||||
/// This vends a pointer to the storage of the `ByteBuffer`. It's marked as _very unsafe_ because it might contain
|
||||
|
|
|
@ -433,10 +433,10 @@ final class PendingDatagramWritesManager: PendingWritesManager {
|
|||
return try self.triggerWriteOperations { writeMechanism in
|
||||
switch writeMechanism {
|
||||
case .scalarBufferWrite:
|
||||
return try triggerScalarBufferWrite(scalarWriteOperation: scalarWriteOperation)
|
||||
return try triggerScalarBufferWrite(scalarWriteOperation: { try scalarWriteOperation($0, $1, $2) })
|
||||
case .vectorBufferWrite:
|
||||
do {
|
||||
return try triggerVectorBufferWrite(vectorWriteOperation: vectorWriteOperation)
|
||||
return try triggerVectorBufferWrite(vectorWriteOperation: { try vectorWriteOperation($0) })
|
||||
} catch {
|
||||
// If the error we just hit is recoverable, we fall back to single write mode to
|
||||
// isolate exactly which write triggered the problem.
|
||||
|
@ -444,7 +444,7 @@ final class PendingDatagramWritesManager: PendingWritesManager {
|
|||
throw error
|
||||
}
|
||||
|
||||
return try triggerScalarBufferWrite(scalarWriteOperation: scalarWriteOperation)
|
||||
return try triggerScalarBufferWrite(scalarWriteOperation: { try scalarWriteOperation($0, $1, $2) })
|
||||
}
|
||||
case .scalarFileWrite:
|
||||
preconditionFailure("PendingDatagramWritesManager was handed a file write")
|
||||
|
@ -524,7 +524,7 @@ final class PendingDatagramWritesManager: PendingWritesManager {
|
|||
msgs: self.msgs,
|
||||
addresses: self.addresses,
|
||||
storageRefs: self.storageRefs,
|
||||
vectorWriteOperation),
|
||||
{ try vectorWriteOperation($0) }),
|
||||
messages: self.msgs)
|
||||
}
|
||||
|
||||
|
|
|
@ -339,11 +339,11 @@ final class PendingStreamWritesManager: PendingWritesManager {
|
|||
return try self.triggerWriteOperations { writeMechanism in
|
||||
switch writeMechanism {
|
||||
case .scalarBufferWrite:
|
||||
return try triggerScalarBufferWrite(scalarBufferWriteOperation)
|
||||
return try triggerScalarBufferWrite({ try scalarBufferWriteOperation($0) })
|
||||
case .vectorBufferWrite:
|
||||
return try triggerVectorBufferWrite(vectorBufferWriteOperation)
|
||||
return try triggerVectorBufferWrite({ try vectorBufferWriteOperation($0) })
|
||||
case .scalarFileWrite:
|
||||
return try triggerScalarFileWrite(scalarFileWriteOperation)
|
||||
return try triggerScalarFileWrite({ try scalarFileWriteOperation($0, $1, $2) })
|
||||
case .nothingToBeWritten:
|
||||
assertionFailure("called \(#function) with nothing available to be written")
|
||||
return .writtenCompletely
|
||||
|
@ -378,7 +378,7 @@ final class PendingStreamWritesManager: PendingWritesManager {
|
|||
|
||||
switch self.state[0].data {
|
||||
case .byteBuffer(let buffer):
|
||||
return self.didWrite(itemCount: 1, result: try buffer.withUnsafeReadableBytes(operation))
|
||||
return self.didWrite(itemCount: 1, result: try buffer.withUnsafeReadableBytes({ try operation($0) }))
|
||||
case .fileRegion:
|
||||
preconditionFailure("called \(#function) but first item to write was a FileRegion")
|
||||
}
|
||||
|
@ -414,7 +414,7 @@ final class PendingStreamWritesManager: PendingWritesManager {
|
|||
let result = try doPendingWriteVectorOperation(pending: self.state,
|
||||
iovecs: self.iovecs,
|
||||
storageRefs: self.storageRefs,
|
||||
operation)
|
||||
{ try operation($0) })
|
||||
return self.didWrite(itemCount: result.itemCount, result: result.writeResult)
|
||||
}
|
||||
|
||||
|
|
|
@ -185,13 +185,13 @@ public enum SocketAddress: CustomStringConvertible {
|
|||
switch self {
|
||||
case .v4(let addr):
|
||||
var address = addr.address
|
||||
return try address.withSockAddr(body)
|
||||
return try address.withSockAddr({ try body($0, $1) })
|
||||
case .v6(let addr):
|
||||
var address = addr.address
|
||||
return try address.withSockAddr(body)
|
||||
return try address.withSockAddr({ try body($0, $1) })
|
||||
case .unixDomainSocket(let addr):
|
||||
var address = addr.address
|
||||
return try address.withSockAddr(body)
|
||||
return try address.withSockAddr({ try body($0, $1) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ services:
|
|||
test:
|
||||
image: swift-nio:18.04-5.0
|
||||
environment:
|
||||
- MAX_ALLOCS_ALLOWED_1000_reqs_1_conn=30990
|
||||
- MAX_ALLOCS_ALLOWED_1_reqs_1000_conn=962050
|
||||
- MAX_ALLOCS_ALLOWED_1000_reqs_1_conn=31990
|
||||
- MAX_ALLOCS_ALLOWED_1_reqs_1000_conn=965050
|
||||
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4500
|
||||
- MAX_ALLOCS_ALLOWED_bytebuffer_lots_of_rw=2100
|
||||
- MAX_ALLOCS_ALLOWED_future_lots_of_callbacks=75010
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# Workarounds
|
||||
|
||||
The following list of PRs and commits were applied in order to work around bugs
|
||||
or cases where the Swift compiler was unable to sufficiently optimize the code:
|
||||
|
||||
- https://github.com/apple/swift-nio/pull/1374
|
||||
- https://github.com/apple/swift-nio-ssl/pull/176
|
||||
- https://github.com/apple/swift-nio/pull/1325
|
||||
- https://github.com/apple/swift-nio/pull/1299
|
||||
- https://github.com/apple/swift-nio/pull/1252
|
||||
- https://github.com/apple/swift-nio/pull/494
|
||||
- https://github.com/apple/swift-nio/pull/420
|
||||
- https://github.com/apple/swift-nio/commit/abc963cfe1e1d4856c41421c9d53ea778102e9e8
|
Loading…
Reference in New Issue