Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

investigate ByteBufferView supporting fast String(decoding:as:) as a workaround for SR-12125 #1379

Closed
weissi opened this issue Feb 4, 2020 · 1 comment

Comments

@weissi
Copy link
Member

weissi commented Feb 4, 2020

The program below allocates for ByteBufferView:

              libsystem_malloc.dylib`malloc
              libswiftCore.dylib`swift_slowAlloc+0x19
              libswiftCore.dylib`_swift_allocObject_(swift::TargetHeapMetadata<swift::InProcess> const*, unsigned long, unsigned long)+0x14
              TestApp`specialized _ContiguousArrayBuffer.init(_uninitializedCount:minimumCapacity:)+0x53
              TestApp`specialized _copyCollectionToContiguousArray<A>(_:)+0x2d
              TestApp`specialized makeString<A>(_:)+0x1dc
              TestApp`doByteBufferView()+0xf0
              TestApp`main+0x13
              libdyld.dylib`start+0x1
              TestApp`0x1
            10000

the problem is that String(decoding:count:) does not seem to leverage withContiguousStorageIfAvaiable which is SR-12125. CC @milseman

We should investigate if we can find a workaround.

===

dev/make-single-file-spm test.swift mallocs

with dev/make-single-file-spm from the NIO repo.

===

// DEPENDENCY: https://github.com/apple/swift-nio 2.13.0 NIO
import NIO

func makeString<Bytes: Collection>(_ bytes: Bytes) -> String where Bytes.Element == UInt8 {
    return String(decoding: bytes, as: Unicode.UTF8.self)
}

func testArray(_ array: [UInt8]) -> String {
    return makeString(array)
}

func testArraySlice(_ array: ArraySlice<UInt8>) -> String {
    return makeString(array)
}

func testByteBufferView(_ array: ByteBufferView) -> String {
    return makeString(array)
}

@inline(never)
func doArray() {
    let array: [UInt8] = Array(repeating: UInt8(ascii: "X"), count: 15)

    for _ in 0..<10000 {
        precondition(testArray(array) == "XXXXXXXXXXXXXXX")
    }
}

@inline(never)
func doArraySlice() {
    let array: ArraySlice<UInt8> = Array(repeating: UInt8(ascii: "X"), count: 15)[...]

    for _ in 0..<10000 {
        precondition(testArraySlice(array) == "XXXXXXXXXXXXXXX")
    }
}

@inline(never)
func doByteBufferView() {
    var buffer = ByteBufferAllocator().buffer(capacity: 16)
    buffer.writeString(String(repeating: "X", count: 15))
    let view = buffer.readableBytesView

    for _ in 0..<10000 {
        precondition(testByteBufferView(view) == "XXXXXXXXXXXXXXX")
    }
}

doArray()
doArraySlice()
doByteBufferView()
@weissi weissi changed the title String(decoding: ByteBufferView, from: Unicode.UTF8.self) goes through intermediate array investigate ByteBufferView supporting fast String(decoding:as:) as a workaround for SR-12125 Feb 4, 2020
@weissi
Copy link
Member Author

weissi commented Jun 10, 2020

This is fixed. In both Swift and NIO.

@weissi weissi closed this as completed Jun 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant