Question about Unmanaged

I built a binary search tree with Swift and wanted to maximise performance, inserting nodes had a lot of retain/release overhead so I tried to reduce it with Unamanged as advised in optimisation tips.

First, I just wanted to be 100% sure : can I avoid using withExtendedLifetime(T) if I know the reference count of T won't drop to 0 ?

The docs mentions _withUnsafeGuaranteedRef saying :

Use the unmanaged reference in a call/variable access. The use of _withUnsafeGuaranteedRef allows the compiler to remove the ultimate retain/release across the call/access.

Does this mean that, given type Foo has a bar property and baz is a Unmanaged<Foo>, calling :

baz._withUnsafeGuaranteedRef { $0.bar }

Will cause no retain/release to the object referenced by $0, and won't cause retain/release to bar either ?

My issue is that using _withUnsafeGuaranteedRef causes a performance regression, in my tests :
if let existingChild = currentNode.takeUnretainedValue().rhs {
Is much faster than :
if let existingChild = currentNode._withUnsafeGuaranteedRef { $0.rhs }

I don't understand why.

Here is the full code example, do you think I am using Unamanged correctly ?

    func insert(word: String, position: Int) {
            var currentNode = Unmanaged.passUnretained(self)
            var wasInserted = false
            
            repeat {
                
                if word < currentNode.takeUnretainedValue().word {
                    if let existingChild = currentNode.takeUnretainedValue().lhs {
                        currentNode = Unmanaged.passUnretained(existingChild)
                    } else {
                        let newNode = Node(word: word, occurences: [position])
                        newNode.parent = currentNode.takeUnretainedValue()
                        currentNode.takeUnretainedValue().lhs = newNode
                        wasInserted = true
                    }
                    
                } else if word > currentNode.takeUnretainedValue().word {
                    if let existingChild = currentNode.takeUnretainedValue().rhs {
                        currentNode = Unmanaged.passUnretained(existingChild)
                    } else {
                        let newNode = Node(word: word, occurences: [position])
                        newNode.parent = currentNode.takeUnretainedValue()
                        currentNode.takeUnretainedValue().rhs = newNode
                        wasInserted = true
                    }
                } else {
                    currentNode.takeUnretainedValue().occurences.insert(position)
                    wasInserted = true
                }
                
            } while !wasInserted
            
        }

Thank you !

1 Like

I have not taken a deeper look yet. It is possible that the compiler has regressed here recently.