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

[MLIR] Improve concurrency when using async. #424

Merged
merged 12 commits into from Jan 4, 2024

Conversation

erick-xanadu
Copy link
Contributor

@erick-xanadu erick-xanadu commented Jan 3, 2024

Context: The initial implementation of async had a naive algorithm that serialized a lot of potentially concurrent code. This PR improves the algorithm and guarantees maximum concurrency.

Description of the Change:

The async.execute instruction returns a token and a promise.

 %token, %promise = async.execute {
   // body...
   async.yield %0 : !some.type
}

We can then wait on the promise or the token

async.await %token // doesn't return a value but waits for all execution in region to finish
%val = async.await %promise // does return a value, whatever is yielded

If async.await is used for the first time and the value is not available, the thread will wait
until the value becomes available. If the value is available, the function returns practically immediately. For example.

%1 = async.await %promise // promise is not yet available, will wait.
%2 = async.await %promise // promise is now available, will not wait.

This makes the job of deciding where to place awaits really easy.
We just need to place awaits just before every use of the original value.
For example, take the following piece of code

%quantum_results = call @qnode

// Arbitrary control flow
// This use might be inside a different basic block.
%some_val = some.op %quantum_results

First we translate the call to an async.execute (which was performed before this
function was called) When this function was called, the transformation is not yet
complete. Because there are still uses of %quantum_results.

%async_quantum_results = call @qnode

// Arbitrary control flow
// This use might be inside a different basic block.
%some_val = some.op %quantum_results

This function will perform the following change:

%async_quantum_results = call @qnode

// Arbitrary control flow
// This use might be inside a different basic block.
%await_quantum_results = async.await %async_quantum_results
%some_val = some.op %await_quantum_results

And it will do so for every use of %quantum_results. Eg.

%async_quantum_results = call @qnode

// Arbitrary control flow
// This use might be inside a different basic block.
%await_quantum_results_0 = async.await %async_quantum_results
%some_val_0 = some.op %await_quantum_results_0
%await_quantum_results_1 = async.await %async_quantum_results
%some_val_1 = some.op %await_quantum_results_1

Benefits: Improved concurrency.

Possible Drawbacks: Not really a drawback, but potential improvement point (which is independent of this commit). We could have a heuristic to decide when async is profitable locally. I believe async is always profitable in remote execution, but not locally.

[sc-52637]

Copy link
Contributor

@rmoyard rmoyard left a comment

Choose a reason for hiding this comment

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

Thanks, great solution!

doc/changelog.md Show resolved Hide resolved
mlir/lib/Catalyst/Transforms/QnodeToAsyncPatterns.cpp Outdated Show resolved Hide resolved
Co-authored-by: Romain Moyard <rmoyard@gmail.com>
Copy link
Member

@maliasadi maliasadi left a comment

Choose a reason for hiding this comment

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

Thanks @erick-xanadu! I have a few questions..

mlir/lib/Catalyst/Transforms/QnodeToAsyncPatterns.cpp Outdated Show resolved Hide resolved
mlir/lib/Catalyst/Transforms/QnodeToAsyncPatterns.cpp Outdated Show resolved Hide resolved
mlir/lib/Catalyst/Transforms/QnodeToAsyncPatterns.cpp Outdated Show resolved Hide resolved
@erick-xanadu erick-xanadu merged commit 285866a into main Jan 4, 2024
20 checks passed
@erick-xanadu erick-xanadu deleted the eochoa/2024-01-03/async branch January 4, 2024 20:20
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

3 participants