Skip to content

Make SyntaxCollections conform to BidirectionalCollection #149

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

Merged
merged 2 commits into from
Nov 8, 2019

Conversation

ahoppen
Copy link
Member

@ahoppen ahoppen commented Oct 7, 2019

This makes SyntaxCollections conform to BidirectionalCollection, allowing multiple traversals of the collections. It also happens to clean the code in SyntaxChildren up a little.

@ahoppen
Copy link
Member Author

ahoppen commented Oct 7, 2019

@swift-ci Please test

Copy link
Contributor

@harlanhaskins harlanhaskins left a comment

Choose a reason for hiding this comment

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

This is much nicer and removes so many nested types. Thanks!

Would be worth doing a binary diff of libSwiftSyntax.dylib to see how big the wins are.

@ahoppen
Copy link
Member Author

ahoppen commented Oct 7, 2019

@harlanhaskins You mean in terms of binary size?

Before After Improvement
Debug 15.53 MB 15.39 MB 0.9%
Release 6.59 MB 6.40 MB 2.9%

Copy link
Contributor

@akyrtzi akyrtzi left a comment

Choose a reason for hiding this comment

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

Looks great, I only have some suggestions. Also did you measure to check if there is any difference in visitation performance?

@@ -118,7 +121,10 @@ extension _SyntaxBase {
guard let parent = self.parent else {
return nil
}
for absoluteRaw in PresentRawSyntaxNextSiblings(self) {
let siblings = PresentRawSyntaxChildren(self.parent!)
let selfIndex = SyntaxChildrenIndex(self.data.absoluteRaw.info)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should selfIndex be a property on Syntax/_SyntaxBase for convenience?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds reasonable. That way the index can also be retrieved externally and library users are able to efficiently slice the collection.

Comment on lines 47 to 48
let startIndex: SyntaxChildrenIndex
let endIndex: SyntaxChildrenIndex
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the RawSyntaxChildren struct size will be smaller if you just store the given AbsoluteRawSyntax and make the existing fields calculated properties. Calculating the startIndex/endIndex should be cheap.

Copy link
Member Author

Choose a reason for hiding this comment

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

My idea was that recomputing the endIndex might have an ever so slight performance impact that occurs every time the collection is iterated which might happen multiple times.
Increasing the size of the collection by 32 bytes means we only need to allocate 32 more bytes on the stack once which should not make a noticeable performance difference since we are already allocating the space for the rest of the struct anyway.

Anyway, there should not be a noticable performance difference with either implementation, I believe.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest to measure both ways. For example, the visitation performance regression could be because RawSyntaxChildren is constructed all the time for every index iteration access for a SyntaxCollection, while if RawSyntaxChildren is just a wrapper of the existing SyntaxCollection's AbsoluteRawSyntax then the optimizer may do a better job to remove overhead.

Comment on lines 103 to 109
let startIndex: SyntaxChildrenIndex
let endIndex: SyntaxChildrenIndex
Copy link
Contributor

Choose a reason for hiding this comment

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

startIndex does some amount of traversing so probably ok to store as field but endIndex can be a calculated property.

Copy link
Member Author

Choose a reason for hiding this comment

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

See comment above.

Copy link
Contributor

Choose a reason for hiding this comment

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

Right now PresentRawSyntaxChildren.endIndex is initialized like this though:self.endIndex = allChildren.endIndex
It's not avoiding any calculation, it is storing the same value twice unnecessarily.

Comment on lines 210 to 245
private var presentRawChildren: PresentRawSyntaxChildren {
return PresentRawSyntaxChildren(self.data.absoluteRaw)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

SyntaxCollection types are essentially arrays of nodes, they should not be containing nil children (e.g. note that the implementation of SyntaxCollection.count is based on this invariant), we should use RawSyntaxChildren here since that one has more efficient index iteration.

They could also get a distance(from:to:) implementation.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. Thanks!

self.indexInTree = indexInTree
}
}

/// Provides a stable and unique identity for `Syntax` nodes.
public struct SyntaxIdentifier: Hashable {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not related to the overall PR but it occurred to me that this could use the Identifiable protocol.

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought the same and then forgot about it. Will do so in a follow-up PR.

@ahoppen ahoppen force-pushed the syntax-collections branch from 3f5fc46 to 4eb99be Compare October 7, 2019 23:02
@ahoppen
Copy link
Member Author

ahoppen commented Oct 7, 2019

@akyrtzi Thanks for the feedback. Incorporated some of your suggestions and commented on others.

I just checked visitor performance as well (running an empty visitor 50 times on bvc2.swift) and there appears to be a performance decrease. I will look into it.

Before After Performance decrease
Debug 4.97s 7.56s -52.2%
Release 0.78s 0.93s -20%

@ahoppen
Copy link
Member Author

ahoppen commented Oct 8, 2019

Due to the performance problems, I’m holding merging this back until we figured out what causes the degression and how to fix this.

@ahoppen ahoppen force-pushed the syntax-collections branch 3 times, most recently from 8e8089a to 6259a4f Compare November 7, 2019 23:19
@ahoppen ahoppen force-pushed the syntax-collections branch from 6259a4f to f8ef071 Compare November 8, 2019 01:00
@ahoppen
Copy link
Member Author

ahoppen commented Nov 8, 2019

I have pretty much completely rewritten the PR to use custom iterators for forward iteration to speed up the common case. That way we still have the old Sequence performance while providing the BidirectionalCollection APIs.

@ahoppen
Copy link
Member Author

ahoppen commented Nov 8, 2019

@swift-ci Please test

@swift-ci
Copy link
Contributor

swift-ci commented Nov 8, 2019

Build failed
Swift Test OS X Platform
Git Sha - f8ef071

Copy link
Contributor

@akyrtzi akyrtzi left a comment

Choose a reason for hiding this comment

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

Nice!👍

@ahoppen
Copy link
Member Author

ahoppen commented Nov 8, 2019

swiftlang/swift-stress-tester#111

@swift-ci Please test

@ahoppen ahoppen merged commit 6887c19 into swiftlang:master Nov 8, 2019
@ahoppen ahoppen deleted the syntax-collections branch November 8, 2019 06:19
adevress pushed a commit to adevress/swift-syntax that referenced this pull request Jan 14, 2024
Add a group around member types used in return clauses.
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.

4 participants