【发布时间】:2019-03-17 22:23:22
【问题描述】:
我一直在研究 Swift 中 UnsafePointer 和相关 UnsafeX 的潜在用例,我想知道我 Swift 的用例是什么。听起来主要用例是性能,但同时类型应该提供编译器优化和性能,所以我不确定它们什么时候真正有用。我想知道是否可以重构所有东西以不以相同或更好的性能使用它们,或者如果不是,那么带有代码描述的具体示例以及可能演示它如何提供性能优势的一些代码或伪代码。我基本上想参考一个特定示例来演示不安全指针和不安全内容的性能优势。
我发现的一些与 Swift 相关的东西:
不过,UnsafePointer 是用于互操作性和构建高性能数据结构的重要 API。 - http://atrick.github.io/proposal/voidpointer.html
但是打字允许编译器优化。我想知道使用 Unsafe 功能会给您带来什么好处。
- True Unsafe Code Performance
- https://nbsoftsolutions.com/blog/high-performance-unsafe-c-code-is-a-lie
- https://www.reddit.com/r/csharp/comments/67oi9p/can_anyone_enlighten_me_on_why_unsafe_code_is/
- https://medium.com/@vCabbage/go-are-pointers-a-performance-optimization-a95840d3ef85
你在Metal代码中看到使用this的一些地方,比如here:
// Create buffers used in the shader
guard let uniformBuffer = device.makeBuffer(length: MemoryLayout<Uniforms>.stride) else { throw Error.failedToCreateMetalBuffer(device: device) }
uniformBuffer.label = "me.dehesa.metal.buffers.uniform"
uniformBuffer.contents().bindMemory(to: Uniforms.self, capacity: 1)
// or here
let ptr = uniformsBuffer.contents().assumingMemoryBound(to: Uniforms.self)
ptr.pointee = Uniforms(modelViewProjectionMatrix: modelViewProjectionMatrix, modelViewMatrix: modelViewMatrix, normalMatrix: normalMatrix)
我还不太了解指针发生了什么,但我想看看这些用例是否提供了性能增强,或者是否可以重构它们以使用具有相似甚至更好的安全版本性能。
也看到here:
func setBit(_ index: Int, value: Bool, pointer: UnsafeMutablePointer<UInt8>) {
let bit: UInt8 = value ? 0xFF : 0
pointer.pointee ^= (bit ^ pointer.pointee) & (1 << UInt8(index))
}
uniforms = UnsafeMutableRawPointer(uniformBuffer.contents()).bindMemory(to:GUniforms.self, capacity:1)
vertexBuffer = device?.makeBuffer(length: 3 * MemoryLayout<GVertex>.stride * 6, options: .cpuCacheModeWriteCombined)
vertices = UnsafeMutableRawPointer(vertexBuffer!.contents()).bindMemory(to:GVertex.self, capacity:3)
vertexBuffer1 = device?.makeBuffer(length: maxCount * maxCount * MemoryLayout<GVertex>.stride * 4, options: .cpuCacheModeWriteCombined)
vertices1 = UnsafeMutableRawPointer(vertexBuffer1!.contents()).bindMemory(to:GVertex.self, capacity: maxCount * maxCount * 4)
Stuff 关于图片:
func mapIndicesRgba(_ imageIndices: Data, size: Size2<Int>) -> Data {
let palette = self
var pixelData = Data(count: size.area * 4)
pixelData.withUnsafeMutableBytes() { (pixels: UnsafeMutablePointer<UInt8>) in
imageIndices.withUnsafeBytes { (indices: UnsafePointer<UInt8>) in
var pixel = pixels
var raw = indices
for _ in 0..<(size.width * size.height) {
let colorIndex = raw.pointee
pixel[0] = palette[colorIndex].red
pixel[1] = palette[colorIndex].green
pixel[2] = palette[colorIndex].blue
pixel[3] = palette[colorIndex].alpha
pixel += 4
raw += 1
}
}
}
return pixelData
}
Stuff 关于输入流:
fileprivate extension InputStream {
fileprivate func loadData(sizeHint: UInt) throws -> Data {
let hint = sizeHint == 0 ? BUFFER_SIZE : Int(sizeHint)
var buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: hint)
var totalBytesRead = read(buffer, maxLength: hint)
while hasBytesAvailable {
let newSize = totalBytesRead * 3 / 2
// Ehhhh, Swift Foundation's Data doesnt have `increaseLength(by:)` method anymore
// That is why we have to go the `realloc` way... :(
buffer = unsafeBitCast(realloc(buffer, MemoryLayout<UInt8>.size * newSize), to: UnsafeMutablePointer<UInt8>.self)
totalBytesRead += read(buffer.advanced(by: totalBytesRead), maxLength: newSize - totalBytesRead)
}
if streamStatus == .error {
throw streamError!
}
// FIXME: Probably should use Data(bytesNoCopy: .. ) instead, but will it deallocate the tail of not used buffer?
// leak check must be done
let retVal = Data(bytes: buffer, count: totalBytesRead)
free(buffer)
return retVal
}
}
【问题讨论】:
-
我正在编写使用 C pcap 库从网络捕获数据包的 Swift 代码。访问这些 C API 需要使用 UnsafeMutablePointer。还有很多其他需要 UnsafePointers 的 C API 示例。 C 中的每个指针都可以被认为是不安全的。他们只是没有那样标记;-)
标签: swift performance unsafe-pointers