Skip to content

[SourceKit] Support cancellation of requests while an AST is being built #38782

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
Sep 28, 2021

Conversation

ahoppen
Copy link
Member

@ahoppen ahoppen commented Aug 6, 2021

This commit refactors the way ASTs are being built in SourceKit and how SwiftASTConsumers are served by the built ASTs. SwiftASTManager.h should give an overview of the new design.

This commit does not change the cancellation paradigm in SourceKit (yet). That is, subsequent requests with the same OncePerASTToken still cancel previous requests with the same token. But while previously, we were only able to cancel requests that haven’t started an AST build yet, we can now also cancel the AST build of the to-be-cancelled requests.

With this change in place, we can start looking into explicit cancellation of requests or other cancellation paradigms.

rdar://83391478

@ahoppen ahoppen force-pushed the pr/sourcekit-cancellation branch from 9fa75c3 to c599eaf Compare August 9, 2021 14:56
@ahoppen ahoppen changed the title [WIP][SourceKit] Allow cancellation of AST building [SourceKit] Support cancellation of requests while an AST is being built Aug 9, 2021
@ahoppen
Copy link
Member Author

ahoppen commented Aug 9, 2021

@swift-ci Please build toolchain macOS

@swift-ci
Copy link
Contributor

swift-ci commented Aug 9, 2021

macOS Toolchain
Download Toolchain
Git Sha - c599eaf235a41fdebbd3c551e12affce57d065e5

Install command
tar -zxf swift-PR-38782-1068-osx.tar.gz --directory ~/

@ahoppen
Copy link
Member Author

ahoppen commented Aug 10, 2021

@swift-ci Please smoke test

@ahoppen ahoppen marked this pull request as ready for review August 10, 2021 12:48
@ahoppen ahoppen requested review from benlangmuir and akyrtzi August 10, 2021 12:48
/// typechecking should be aborted at the next possible opportunity.
/// This is used by SourceKit to cancel requests for which the result is no
/// longer of interest.
std::shared_ptr<bool> CancellationFlag = nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

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

@xedin does this seem okay to put the shared cancellation state in TypeCheckerOptions?

@ahoppen this should wrap a std::atomic<bool> to avoid data races, and use load(std::memory_order_relaxed) and store(true, std::memory_order_relaxed).

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 about race conditions here a bit and think it should be fine with a plain pointer. We should only have one location setting the cancellation flag to true and that’s independent of what it’s previous content was, so there shouldn’t be any write races. And if setting the flag to true doesn’t immediately propagate to the thread that is building the AST, it’s also fine since nobody expects the cancellation to be immediate – it’s totally fine for the type checker to e.g. continue type checking for a few more cycles. But I might be missing something.

But we could of course make it a std::atomic. Not quite sure if that will add some performance overhead though…

Copy link
Contributor

Choose a reason for hiding this comment

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

We cannot ignore the read-write race:

  • The compiler is free optimize this code based on the assumption no other thread modifies the value, since it's not valid to do so.
  • TSan will raise an error on this race.

But we could of course make it a std::atomic. Not quite sure if that will add some performance overhead though…

Using relaxed memory order atomic operations shouldn't cost much. On x86_64 it should be basically free.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, I changed it to a std::atomic.

Out of curiosity though: How would the race condition manifest at runtime except for the TSan failure?

Copy link
Contributor

Choose a reason for hiding this comment

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

How would the race condition manifest at runtime except for the TSan failure?

Likely it wouldn't manifest in practice under any current compiler, but in principle it could only check the flag once and never again (for a single AST build).

@ahoppen ahoppen force-pushed the pr/sourcekit-cancellation branch from c599eaf to 3309b78 Compare August 11, 2021 15:10
@ahoppen
Copy link
Member Author

ahoppen commented Aug 11, 2021

@swift-ci Please smoke test

@ahoppen ahoppen force-pushed the pr/sourcekit-cancellation branch from 3309b78 to 082cea4 Compare August 12, 2021 06:47
@ahoppen
Copy link
Member Author

ahoppen commented Aug 12, 2021

@swift-ci Please smoke test

@ahoppen
Copy link
Member Author

ahoppen commented Aug 25, 2021

@swift-ci Please smoke test Windows

Once this flag is set, the type checker will bail out with a “expression to complex” error.
@ahoppen ahoppen force-pushed the pr/sourcekit-cancellation branch from 082cea4 to 2694d0b Compare September 22, 2021 11:10
@ahoppen
Copy link
Member Author

ahoppen commented Sep 22, 2021

@swift-ci Please smoke test

Copy link
Contributor

@benlangmuir benlangmuir left a comment

Choose a reason for hiding this comment

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

Basically looking good, just a few minor things.

/// typechecking should be aborted at the next possible opportunity.
/// This is used by SourceKit to cancel requests for which the result is no
/// longer of interest.
std::shared_ptr<std::atomic<bool>> CancellationFlag = nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

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

@xedin or @hborla any concerns about this mutable state living in TypeCheckerOptions?

Copy link
Member

Choose a reason for hiding this comment

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

I don't have concerns but I've also never touched this thing 🙂 @CodaFi do you have any thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

It’s a fine place to put it to start. I just hope we move off a cooperative cancellation model and push this into the request evaluator at some point.

This commit refactors the way ASTs are being built in SourceKit and how `SwiftASTConsumer`s are served by the built ASTs. `SwiftASTManager.h` should give an overview of the new design.

This commit does not change the cancellation paradigm in SourceKit (yet). That is, subsequent requests with the same `OncePerASTToken` still cancel previous requests with the same token. But while previously, we were only able to cancel requests that haven’t started an AST build yet, we can now also cancel the AST build of the to-be-cancelled requests.

With this change in place, we can start looking into explicit cancellation of requests or other cancellation paradigms.
@ahoppen ahoppen force-pushed the pr/sourcekit-cancellation branch from 2694d0b to 7a80034 Compare September 23, 2021 09:54
@ahoppen
Copy link
Member Author

ahoppen commented Sep 23, 2021

@swift-ci Please test

Copy link
Contributor

@benlangmuir benlangmuir left a comment

Choose a reason for hiding this comment

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

I'd still like someone other than me to comment on putting the cancellation state into the TypeCheckerOptions. LGTM otherwise.

@ahoppen ahoppen merged commit 4521c99 into swiftlang:main Sep 28, 2021
@ahoppen ahoppen deleted the pr/sourcekit-cancellation branch September 28, 2021 18:08
swift-ci pushed a commit that referenced this pull request Oct 5, 2021
Seems that VS2019 and other C++ standard libraries include <atomic> as
part of either <string> or <vector>, but not VS2017. When #38782 landed
a new usage of std::atomic started creating compilation problems in the
VS2017 builders (eg. https://ci-external.swift.org/job/oss-swift-windows-x86_64/8736/).

Including the <atomic> header solves the problem.
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.

5 participants