Skip to content

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

@weissi

Description

@weissi

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()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions