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-10614] Assigning arrays of tuples to arrays of similar tuples surprisingly allocates. #53014

Open
Lukasa opened this issue May 3, 2019 · 4 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself performance standard library Area: Standard library umbrella

Comments

@Lukasa
Copy link
Contributor

Lukasa commented May 3, 2019

Previous ID SR-10614
Radar None
Original Reporter @Lukasa
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Compiler, Standard Library
Labels Bug, Performance
Assignee None
Priority Medium

md5: cc552939b1fbd98ddc37640577572edd

Issue Description:

The following code, when run, allocates 200,000 transient _ContiguousArrayStorage objects:

struct ArrayCounter {
    private var storage: [(name: String, value: String)]

    init(_ array: [(name: String, value: String)]) {
        self.storage = array
    }

    var count: Int {
        return self.storage.count
    }
}

@inline(never)
func countTester(_ array: [(String, String)]) -> Int {
    let arrayCounter = ArrayCounter(array)
    return arrayCounter.count
}

let array = [("hello", "world"), ("I am", "Array")]
var count = 0
for _ in 0..<200_000 {
    count += countTester(array)
}

print(count)

The allocation stack is

   0 libsystem_malloc.dylib malloc_zone_malloc
   1 libsystem_malloc.dylib malloc
   2 libswiftCore.dylib swift_slowAlloc
   3 libswiftCore.dylib _swift_allocObject_(swift::TargetHeapMetadata<swift::InProcess> const*, unsigned long, unsigned long)
   4 libswiftCore.dylib _swift_allocObject_(swift::TargetHeapMetadata<swift::InProcess> const*, unsigned long, unsigned long)
   5 NIOLoopPerformanceTester specialized ContiguousArray.reserveCapacity(_:) /Users/lukasa/Documents/Cocoa/NIOLoopPerformanceTester/<compiler-generated>:0
   6 NIOLoopPerformanceTester specialized _arrayForceCast<A, B>(_:) /Users/lukasa/Documents/Cocoa/NIOLoopPerformanceTester/<compiler-generated>:0
   7 NIOLoopPerformanceTester countTester(_:) /Users/lukasa/Documents/Cocoa/NIOLoopPerformanceTester/NIOLoopPerformanceTester/main.swift:23
   8 NIOLoopPerformanceTester main /Users/lukasa/Documents/Cocoa/NIOLoopPerformanceTester/NIOLoopPerformanceTester/main.swift:30
   9 libdyld.dylib start

The issue appears to be that the cast from [(String, String)] to [(name: String, value: String)] triggers an allocation and copy, despite the fact that the two types are sufficiently close to identical that the compiler will simply let you assign one to the other.

Either this should not allocate, or it should not be possible to assign the array of one type to a variable of the other.

@belkadan
Copy link
Contributor

belkadan commented May 3, 2019

An Array carries its type around, so it'd be a stretch to share ownership here. But Swift does not have a convention that conversions that can cause allocations need to be explicit. The same is true for concrete type -> protocol.

@Lukasa
Copy link
Contributor Author

Lukasa commented May 3, 2019

This is definitely my lack of understanding here, but there are some cases in which this conversion does not need to allocate.

Storing [(String, String)] in a variable of [(name: String, value: String)]: allocates.
Storing [S] in a variable of [P] where protocol P and struct S: P: allocates.
Storing [S] in a variable of [Super] where class Super and class S: Super: does not allocate.

What don't I understand about why subclasses don't need a reallocation?

@belkadan
Copy link
Contributor

belkadan commented May 3, 2019

I'm not saying this change can't be done, and the class case is a good point. I'm just saying "it should not be possible to assign the array of one type to a variable of the other" is not something that Swift plans to do. We had piles of complaints when [S] to [P] didn't work, even with that justification.

@Lukasa
Copy link
Contributor Author

Lukasa commented May 3, 2019

Oh sure, I totally understand that that's a genie that cannot be put back into the bottle.

I should note that this is low-priority for us: the case where we hit this issue is easily resolved and I'll be putting a patch up soon to fix it.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself performance standard library Area: Standard library umbrella
Projects
None yet
Development

No branches or pull requests

2 participants