Skip to content

[Syntax] Perf: Optimize 'root' and 'ancestorOrSelf' #2842

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 1 commit into from
Sep 10, 2024

Conversation

rintaro
Copy link
Member

@rintaro rintaro commented Sep 6, 2024

Accessing Syntax.parent requires retain/release traffic. Especially when traversing ancestors to the root, that ARC traffic is not negligible.

Introduce UnownedSyntax that provides a way to access the parents temporarily without causing ARC traffics.

@rintaro
Copy link
Member Author

rintaro commented Sep 6, 2024

@swift-ci Please test

@rintaro
Copy link
Member Author

rintaro commented Sep 7, 2024

@swift-ci Please test macOS

Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Nice idea

@@ -129,6 +132,7 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
}

/// "designated" memberwise initializer of `Syntax`.
@_transparent
Copy link
Member

Choose a reason for hiding this comment

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

Do we need @_transparent here? It does make debugging odd because you can no longer step into the function. Isn‘t @inline(__always) enough? Same for the other @_transparent functions. https://github.com/swiftlang/swift/blob/main/docs/TransparentAttr.md for reference.

Copy link
Member Author

@rintaro rintaro Sep 9, 2024

Choose a reason for hiding this comment

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

Unfortunately normal inlining is too late for eliminating ARC operations for:

  func withValue<T>(_ body: (Syntax) -> T) ->  T {
    info._withUnsafeGuaranteedRef {
      body(Syntax(self.raw, info: $0))
    }
  }

In https://godbolt.org/z/j1o6YM4Pz Try changing @_transparent to @inline(__always) on Syntax.init, and see the difference of withValue

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, that’s unfortunate. Could you add a comment with this explanation to the @_transparent attribute?

@@ -380,6 +384,57 @@ extension Syntax {
}
}

/// Temporary non-owning Syntax.
///
/// This can be used for handing Syntax node without ARC traffic.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// This can be used for handing Syntax node without ARC traffic.
/// This can be used for handling Syntax node without ARC traffic.

switch $0.info.unsafelyUnwrapped {
case .nonRoot(let info):
return UnownedSyntax(info.parent)
case .root(_):
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
case .root(_):
case .root:

Copy link
Member Author

@rintaro rintaro Sep 9, 2024

Choose a reason for hiding this comment

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

Looks like we're inconsistent. var nonRootInfo uses case .root(_). I personally prefer (_) style because it's more explicit on ignoring associated values.

walk = unwrappedParent.parent
return withUnownedSyntax(self) {
var node = $0
repeat {
Copy link
Member

Choose a reason for hiding this comment

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

If this is an infinite loop, would while true be easier to read than repeat { } while true?

@rintaro rintaro force-pushed the unownedsyntax branch 3 times, most recently from a53bccf to 4fb4c0c Compare September 9, 2024 18:16
@rintaro
Copy link
Member Author

rintaro commented Sep 9, 2024

@swift-ci Please test

@rintaro
Copy link
Member Author

rintaro commented Sep 9, 2024

@swift-ci Please test Windows

@@ -129,6 +132,7 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
}

/// "designated" memberwise initializer of `Syntax`.
@_transparent
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, that’s unfortunate. Could you add a comment with this explanation to the @_transparent attribute?

Comment on lines 391 to 392
var raw: RawSyntax
var info: Unmanaged<Syntax.Info>
Copy link
Member

Choose a reason for hiding this comment

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

Should these be private (or at least info be private). Seems like the intended access paths are via value and parent.

///
/// This guarantees the life time of the `node` during the `body` is executed.
@inline(__always)
func withUnownedSyntax<T>(_ node: some SyntaxProtocol, _ body: (UnownedSyntax) -> T) -> T {
Copy link
Member

Choose a reason for hiding this comment

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

Would this be better as a member on SyntaxProtocol so that you would do self.withUnownedSyntax instead of withUnownedSyntax(self)?

@rintaro
Copy link
Member Author

rintaro commented Sep 10, 2024

swiftlang/swift#76360
@swift-ci Please test

@rintaro
Copy link
Member Author

rintaro commented Sep 10, 2024

swiftlang/swift#76360
@swift-ci Please test Windows

@rintaro rintaro merged commit 9b9765b into swiftlang:main Sep 10, 2024
3 checks passed
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.

2 participants