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

Optimize layout flattening #982

Merged
merged 4 commits into from
Jun 22, 2018
Merged

Optimize layout flattening #982

merged 4 commits into from
Jun 22, 2018

Conversation

Adlai-Holler
Copy link
Member

Layout flattening is one of the most common operations in our framework and it currently involves a ton of needless retain/release traffic (4 rr pairs per layout). This diff reduces that to 0.

Since I hope to make more use of the __unsafe_unretained qualifier in the future, I added an unowned alias for it, to make it prettier.

Obviously please review this diff carefully, since no optimization is worth crashing.


return YES;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to make this a method so that it can see the _sublayouts ivar for direct access (remove retain/release pair per sublayout).

}
queue.insert(queue.cbegin(), sublayoutContexts.begin(), sublayoutContexts.end());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bottom here (the search expansion) is far and away the biggest win. We no longer create another vector (heap allocation) and we remove 2 retain/release pairs per sublayout. The first is inserting into the vector then destroying the vector, the second is inserting into the queue and then removing from the queue.

const NSArray<ASLayout *> *sublayouts = layout.sublayouts;
const NSUInteger sublayoutsCount = sublayouts.count;
unowned ASLayout *layout = context.layout;
const NSUInteger sublayoutsCount = layout->_sublayouts.count;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direct ivar access isn't so much about avoiding the message-send, it's about avoiding the retain/release pair. _sublayouts is already a +1 so let's use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind adding this comment in code?

Copy link
Member

@nguyenhuy nguyenhuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. This is a very hot path that is worth this kind of optimization.

@@ -18,6 +18,7 @@
#import <Foundation/NSObjCRuntime.h>

#define AS_EXTERN FOUNDATION_EXTERN
#define unowned __unsafe_unretained
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we should just be consistent and use __unsafe_unretained in a framework.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pros:

  • Less underscores
  • Shorter, cleaner

Cons:

  • Not standard
  • Could one day be a collision and we'd have to revert

- (BOOL)isFlattened
{
// A layout is flattened if its position is null, and all of its sublayouts are of type displaynode with no sublayouts.
if (! ASPointIsNull(_position)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove whitespace?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return NO;
}

for (ASLayout *sublayout in _sublayouts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would NSFastEnumeration allow us to cast that as unowned void * and cast down with a bridge to the type we need? In fact does it do a retain for the sub layouts in here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fast enumeration doesn't retain the objects.

Copy link
Member

@garrettmoon garrettmoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a good performance win to me! Nice!

const NSArray<ASLayout *> *sublayouts = layout.sublayouts;
const NSUInteger sublayoutsCount = sublayouts.count;
unowned ASLayout *layout = context.layout;
const NSUInteger sublayoutsCount = layout->_sublayouts.count;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind adding this comment in code?

Add comment
@Adlai-Holler Adlai-Holler merged commit 0fe991f into master Jun 22, 2018
@Adlai-Holler Adlai-Holler deleted the AHOptimizeFlattening branch June 22, 2018 21:20
mikezucc pushed a commit to mikezucc/Texture that referenced this pull request Oct 2, 2018
* Optimize layout flattening

* Changelog

* Remove whitespace

* Update ASLayout.mm

Add comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants