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

[SR-7542] Foundation.Data withUnsafeBytes and friends aren't inlineable #3712

Open
weissi opened this issue Apr 26, 2018 · 4 comments
Open

Comments

@weissi
Copy link
Member

weissi commented Apr 26, 2018

Previous ID SR-7542
Radar None
Original Reporter @weissi
Type Bug
Additional Detail from JIRA
Votes 1
Component/s Foundation
Labels Bug
Assignee None
Priority Medium

md5: 331f4f3551f67dccb54f450d23a70272

Issue Description:

in https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/Data.swift#L122 we find:

    @discardableResult
    public func withUnsafeBytes<Result>(in range: Range<Int>, apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {

in https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/Data.swift#L198 we find:

    @discardableResult
    public func withUnsafeMutableBytes<Result>(in range: Range<Int>, apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {

both those functions are generic and not inlineable, that means calling them will always get you an allocation for the generic and probably another one for the closure used (SR-904).

These should definitely be inlineable, otherwise they're pretty much useless 🙁.

For example, running this useless function 1024 times

    @inline(never)
    func doWrites1() {
        var z: UInt = 123
        foundationData.withUnsafeBytes { ptr in
            z += UInt(bitPattern: ptr.baseAddress!)
        }
        precondition(z > 128)
    }

gives me these allocations:

              libsystem_malloc.dylib`malloc
              libswiftCore.dylib`swift_slowAlloc+0x19
              libswiftCore.dylib`_swift_allocObject_+0x14
              PerfTestSwiftNIO`specialized doWrites1 #&#8203;1 () in closure #&#8203;2 in +0xbe
              PerfTestSwiftNIO`closure #&#8203;2 in +0xfe
              PerfTestSwiftNIO`$S16PerfTestSwiftNIO7measureySaySdGSiyKcKF+0x38
              PerfTestSwiftNIO`specialized PerfTestSwiftNIOmeasureAndPrintfn(_:_:)+0x1be
              PerfTestSwiftNIO`main+0x217
              libdyld.dylib`start+0x1
              PerfTestSwiftNIO`0x1
             1024

              libsystem_malloc.dylib`malloc
              libswiftCore.dylib`swift_slowAlloc+0x19
              libswiftCore.dylib`_swift_allocObject_+0x14
              PerfTestSwiftNIO`specialized doWrites1 #&#8203;1 () in closure #&#8203;2 in +0x3d
              PerfTestSwiftNIO`closure #&#8203;2 in +0xfe
              PerfTestSwiftNIO`$S16PerfTestSwiftNIO7measureySaySdGSiyKcKF+0x38
              PerfTestSwiftNIO`specialized PerfTestSwiftNIOmeasureAndPrintfn(_:_:)+0x1be
              PerfTestSwiftNIO`main+0x217
              libdyld.dylib`start+0x1
              PerfTestSwiftNIO`0x1
             1024

              libsystem_malloc.dylib`malloc
              libswiftCore.dylib`swift_slowAlloc+0x19
              libswiftCore.dylib`_swift_allocObject_+0x14
              PerfTestSwiftNIO`specialized doWrites1 #&#8203;1 () in closure #&#8203;2 in +0x5e
              PerfTestSwiftNIO`closure #&#8203;2 in +0xfe
              PerfTestSwiftNIO`$S16PerfTestSwiftNIO7measureySaySdGSiyKcKF+0x38
              PerfTestSwiftNIO`specialized PerfTestSwiftNIOmeasureAndPrintfn(_:_:)+0x1be
              PerfTestSwiftNIO`main+0x217
              libdyld.dylib`start+0x1
              PerfTestSwiftNIO`0x1
             1024

              libsystem_malloc.dylib`malloc
              libswiftCore.dylib`swift_slowAlloc+0x19
              libswiftCore.dylib`_swift_allocObject_+0x14
              PerfTestSwiftNIO`specialized doWrites1 #&#8203;1 () in closure #&#8203;2 in +0x86
              PerfTestSwiftNIO`closure #&#8203;2 in +0xfe
              PerfTestSwiftNIO`$S16PerfTestSwiftNIO7measureySaySdGSiyKcKF+0x38
              PerfTestSwiftNIO`specialized PerfTestSwiftNIOmeasureAndPrintfn(_:_:)+0x1be
              PerfTestSwiftNIO`main+0x217
              libdyld.dylib`start+0x1
              PerfTestSwiftNIO`0x1
             1024

which actually looks like 4 allocations per run!

@belkadan
Copy link

belkadan commented May 1, 2018

IIRC, the inlinable part was a deliberate decision at this time to be careful about adding new representations. But this particular case may be important enough to split the function into an inlinable fast path and a non-inlinable slow path, or a non-inlinable part for getting the address but the rest inlinable. (Also, non-escaping closures will soon not require a heap allocation, and generics already shouldn't.)

cc @phausler

@weissi
Copy link
Member Author

weissi commented May 13, 2018

CC @parkera

@parkera
Copy link
Member

parkera commented May 14, 2018

This seems really unfortunate, but I think a reasonable argument can be made that it is a language problem given the inability to guarantee the scope of a return value which leads us to this pattern in the first place.

@belkadan
Copy link

Hang on, withUnsafeBytes can be inlinable without the part that gets the actual pointer being inlinable.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants