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-1647] Compiler hangs on large array of NSLayoutConstraints, with a type annotation #44256

Open
swift-ci opened this issue May 31, 2016 · 6 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself performance regression swift 2.2 type checker Area → compiler: Semantic analysis

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-1647
Radar None
Original Reporter Nowak (JIRA User)
Type Bug
Environment

Xcode 7.3.1, Xcode 8.0 (8A218a)
iOS 9.3, iOS 10

Additional Detail from JIRA
Votes 5
Component/s Compiler
Labels Bug, 2.2Regression, Performance, TypeChecker
Assignee None
Priority Medium

md5: 6e1cac7c3070003bafb401696215795b

Issue Description:

I have an project without storyboard.
All Compounds are arrenged by constraints.

On Swift 1 I have set all constraints in one big array an set it, with one addConstraints() call

On Swift 2.2 the Compiler will hang and was killed after 8 hours without any useful error message

As workaround a have found, that I need to set the Constraints on

Here is the function which let the compiler hangs:

func setConstraints()
    {
        
        var constraints:[NSLayoutConstraint] = [
            
            
            NSLayoutConstraint(item: positiveLabel,attribute: NSLayoutAttribute.Top,relatedBy: NSLayoutRelation.Equal,toItem: view,attribute: NSLayoutAttribute.Top,multiplier: 1,constant: 0),
            
            NSLayoutConstraint(item:positiveLabel,attribute: NSLayoutAttribute.Left,relatedBy: NSLayoutRelation.Equal,toItem: view,attribute: NSLayoutAttribute.Left,multiplier: 1,constant: 0),
            
            NSLayoutConstraint(item:positiveLabel,attribute: NSLayoutAttribute.Width,relatedBy: NSLayoutRelation.Equal,toItem: nil,attribute: NSLayoutAttribute.NotAnAttribute,multiplier: 1,constant: 50),
            /*
            ]
        view.addConstraints(constraints)
        constraints = [
 */
            NSLayoutConstraint(item: positiveBox,attribute: NSLayoutAttribute.CenterY,relatedBy: NSLayoutRelation.Equal,toItem: positiveLabel,attribute: NSLayoutAttribute.CenterY,multiplier: 1,constant: 0),
            
            NSLayoutConstraint(item:positiveBox,attribute: NSLayoutAttribute.Left,relatedBy: NSLayoutRelation.Equal,toItem: positiveLabel,attribute: NSLayoutAttribute.Right,multiplier: 1,constant: 10),
            
            NSLayoutConstraint(item:positiveBox,attribute: NSLayoutAttribute.Height,relatedBy: NSLayoutRelation.Equal,toItem: positiveLabel,attribute: NSLayoutAttribute.Height,multiplier: 0.8,constant: 0),
            
            NSLayoutConstraint(item:positiveBox,attribute: NSLayoutAttribute.Width,relatedBy: NSLayoutRelation.Equal,toItem: positiveBox,attribute: NSLayoutAttribute.Height,multiplier: 1,constant: 0),
   /*
        ]
        view.addConstraints(constraints)
        
        
        constraints = [
     */
            NSLayoutConstraint(item:negativeLabel,attribute: NSLayoutAttribute.Top,relatedBy: NSLayoutRelation.Equal,toItem: positiveLabel,attribute: NSLayoutAttribute.Bottom,multiplier: 1,constant: 0),
            NSLayoutConstraint(item:negativeLabel,attribute: NSLayoutAttribute.Left,relatedBy: NSLayoutRelation.Equal,toItem: view,attribute: NSLayoutAttribute.Left,multiplier: 1,constant: 0),
            NSLayoutConstraint(item:negativeLabel,attribute: NSLayoutAttribute.Width,relatedBy: NSLayoutRelation.Equal,toItem: nil,attribute: NSLayoutAttribute.NotAnAttribute,multiplier: 1,constant: 50),
       /*
            ]
        view.addConstraints(constraints)
        constraints = [
 */
            NSLayoutConstraint(item:negativeBox,attribute: NSLayoutAttribute.CenterY,relatedBy: NSLayoutRelation.Equal,toItem: negativeLabel,attribute: NSLayoutAttribute.CenterY,multiplier: 1,constant: 0),
            NSLayoutConstraint(item:negativeBox,attribute: NSLayoutAttribute.Left,relatedBy: NSLayoutRelation.Equal,toItem: negativeLabel,attribute: NSLayoutAttribute.Right,multiplier: 1,constant: 10),
            NSLayoutConstraint(item:negativeBox,attribute: NSLayoutAttribute.Height,relatedBy: NSLayoutRelation.Equal,toItem: negativeLabel,attribute: NSLayoutAttribute.Height,multiplier: 0.8,constant: 0),
            NSLayoutConstraint(item:negativeBox,attribute: NSLayoutAttribute.Width,relatedBy: NSLayoutRelation.Equal,toItem: negativeBox,attribute: NSLayoutAttribute.Height,multiplier: 1,constant: 0),
   /*
        ]
        view.addConstraints(constraints)
        
        
        constraints = [
 */
            NSLayoutConstraint(item:neutralLabel,attribute: NSLayoutAttribute.Top,relatedBy: NSLayoutRelation.Equal,toItem: negativeLabel,attribute: NSLayoutAttribute.Bottom,multiplier: 1,constant: 0),
            NSLayoutConstraint(item:neutralLabel,attribute: NSLayoutAttribute.Left,relatedBy: NSLayoutRelation.Equal,toItem: view,attribute: NSLayoutAttribute.Left,multiplier: 1,constant: 0),
            NSLayoutConstraint(item:neutralLabel,attribute: NSLayoutAttribute.Width,relatedBy: NSLayoutRelation.Equal,toItem: nil,attribute: NSLayoutAttribute.NotAnAttribute,multiplier: 1,constant: 50),
   /*
            ]
        view.addConstraints(constraints)
        constraints = [
 */
            NSLayoutConstraint(item:neutralBox,attribute: NSLayoutAttribute.CenterY,relatedBy: NSLayoutRelation.Equal,toItem: neutralLabel,attribute: NSLayoutAttribute.CenterY,multiplier: 1,constant: 0),
            NSLayoutConstraint(item:neutralBox,attribute: NSLayoutAttribute.Left,relatedBy: NSLayoutRelation.Equal,toItem: neutralLabel,attribute: NSLayoutAttribute.Right,multiplier: 1,constant: 10),
            NSLayoutConstraint(item:neutralBox,attribute: NSLayoutAttribute.Height,relatedBy: NSLayoutRelation.Equal,toItem: neutralLabel,attribute: NSLayoutAttribute.Height,multiplier: 0.8,constant: 0),
            NSLayoutConstraint(item:neutralBox,attribute: NSLayoutAttribute.Width,relatedBy: NSLayoutRelation.Equal,toItem: neutralBox,attribute: NSLayoutAttribute.Height,multiplier: 1,constant: 0),
        ]
        view.addConstraints(constraints)


}

The short project to show the Error can be found here:

https://github.com/tn0/swiftError.git

@swift-ci
Copy link
Collaborator Author

Comment by Ayaka Nonaka (JIRA)

I’ve run into this issue multiple times as well. Happened to me with a view that has only three subviews, and just 12 constraints. My workaround was to split the activation out into multiple calls to activateConstraints, but initially it was not apparently why the compile time got so slow. I deleted derived data, restarted Xcode, restarted computer before I realized that it was the activateConstraints call that was causing the issue.

I’d love to help track down the root issue if anyone with more compiler knowledge could also take a look! 🙂

@swift-ci
Copy link
Collaborator Author

swift-ci commented Oct 4, 2016

Comment by Ayaka Nonaka (JIRA)

This is still a huge issue in Swift 3.0. It is unfortunate because the alternative is to use isActive = true instead, which is way faster for compiling but slower at runtime and UI performance(1). Let me know how I can help track this issue down, because it’s not ideal to have to trade off between compile time and performance at runtime.

1. from WWDC 2015 Session 219 (http://asciiwwdc.com/2015/sessions/219)

"It turns out that changing a constraint inside update constraints is actually faster than changing a constraint at other times.

The reason for that is because the engine is able to treat all the constraint changes that happen in this pass as a batch.

This is the same kind of performance benefit that you get by calling activate constraints on an entire array of constraints as opposed to activating each of those constraints individually."

@belkadan
Copy link
Contributor

belkadan commented Oct 4, 2016

I don't think that's fair. append gets the same behavior without multiple calls to addConstraints.

@swift-ci
Copy link
Collaborator Author

swift-ci commented Oct 4, 2016

Comment by Ayaka Nonaka (JIRA)

@belkadan Thanks for your reply. Yes we ended up converting almost all of our AL code to `append` after we realized we could do that instead. It would still be nice to be able to pass in an array directly like

`NSLayoutConstraint.activate([NSLayoutConstraint(...), NSLayoutConstraint(...), ...])`

mostly for readability and also to prevent bugs from forgetting to call `NSLayoutConstraint.activate(theArrayWeWereAppendingTo)` because that was I was most afraid of forgetting while refactoring the code to use `append` instead.

@rnapier
Copy link

rnapier commented Oct 4, 2016

Adding an extra initializer to NSLayoutConstraint fixes this. I believe the problem is the Any? in particular. If you can remove that, things are dramatically faster (basically instant). For example:

extension NSLayoutConstraint {
    public convenience init(item view1: AnyObject, attribute attr1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation, toItem view2: AnyObject?, attribute attr2: NSLayoutAttribute, multiplier: CGFloat, constant c: CGFloat) {
        self.init(item: view1 as Any, attribute: attr1, relatedBy: relation, toItem: view2 as Any?, attribute: attr2, multiplier: multiplier, constant: c)
    }
}

Here I've changed view1 and view2 to be AnyObject and AnyObject? rather than Any and Any? (and use as to make sure I call the original version). Similar improvements occur if you make them UIView and UIView? or even just both Any (so there is no Any?). Basically the entire problem is in the Any?.

(In Swift 2.2, these were AnyObject and it also had a problem. I suspect adding a non-optional version would fix 2.2, but I haven't tested that.)

@swift-ci
Copy link
Collaborator Author

Comment by Rudd T (JIRA)

Confirming that @rnapier's extension fixes this issue nicely, and that this bug still exists as of Xcode Version 8.1 (8T61a)

@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 regression swift 2.2 type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

4 participants