-
Notifications
You must be signed in to change notification settings - Fork 67
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
Clarify buffer and accessor lifetime #240
base: main
Are you sure you want to change the base?
Conversation
Clarify that the application must not use an accessor after its associated buffer / image is destroyed, Also clarify the point at which requisites are added for a command. This happens after the command group function object returns, not during the call to `parallel_for` (etc.) Closes internal issue 420
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Diving more into it, I have the feeling it requires more discussion.
Selecting Request changes to avoid merging for now.
Therefore, it is the application's responsibility to ensure that the lifetime | ||
of the buffer is at least as long as the lifetime of the host accessor. | ||
Calling any member function on a host accessor after its associated buffer has | ||
been destroyed results in undefined behavior. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand how it is an issue in a conforming implementation.
If you you have a live accessor, the buffer is still kept alive though for example an internal shared_ptr
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The case of the host accessor looks simpler, very synchronous without any lazy lambda evaluation and should keep a buffer internal state alive.
group function object returns, it is generally unwise to construct a buffer or | ||
image inside of command group scope. The destructor for the buffer or image | ||
only blocks when there is a memory requirement, but variables defined in the | ||
command group function object go out of scope before those requirements are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem I can see in my implementation is more like a deadlock.
But thinking more about it, I am unsure that not dealing with dependencies at accessor construction time instead of postponing after submit
lambda execution can be a generic enough C++ implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks more like implementation detail & trade-off, so I can give up my previous comment.
results in undefined behavior. In some cases the buffer destructor is defined | ||
to block until commands with requisites on that buffer have completed. This | ||
results in well defined behavior so long as all invocations to member functions | ||
of accessors for that buffer occur before those commands complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the feeling that the buffer destructor should block if there are accessors using it or at least being internally kept alive if there is no side effect on buffer use or buffer destruction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can give up on this.
destructor is defined to block until commands with requisites on that image | ||
have completed. This results in well defined behavior so long as all | ||
invocations to member functions of accessors for that image occur before those | ||
commands complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have more content about image
lifetime and synchronization?
I have the feeling we only addressed buffers up to now in the specification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your comment simplify the implementation, so I am fine with it.
destroyed results in undefined behavior. In some cases the image destructor is | ||
defined to block until commands with requisites on that image have completed. | ||
This results in well defined behavior so long as all invocations to member | ||
functions of accessors for that image occur before those commands complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the feeling it depends only on construction and not member functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still thinking that the host_accessor
could keep a buffer alive internally.
Therefore, it is the application's responsibility to ensure that the lifetime | ||
of the buffer is at least as long as the lifetime of the host accessor. | ||
Calling any member function on a host accessor after its associated buffer has | ||
been destroyed results in undefined behavior. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The case of the host accessor looks simpler, very synchronous without any lazy lambda evaluation and should keep a buffer internal state alive.
results in undefined behavior. In some cases the buffer destructor is defined | ||
to block until commands with requisites on that buffer have completed. This | ||
results in well defined behavior so long as all invocations to member functions | ||
of accessors for that buffer occur before those commands complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can give up on this.
group function object returns, it is generally unwise to construct a buffer or | ||
image inside of command group scope. The destructor for the buffer or image | ||
only blocks when there is a memory requirement, but variables defined in the | ||
command group function object go out of scope before those requirements are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks more like implementation detail & trade-off, so I can give up my previous comment.
destructor is defined to block until commands with requisites on that image | ||
have completed. This results in well defined behavior so long as all | ||
invocations to member functions of accessors for that image occur before those | ||
commands complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your comment simplify the implementation, so I am fine with it.
What about a case like this:
Note that both the To me, it seems better to adopt one of these two clarifications:
|
I converted this to a draft because there is at least one thing that needs to be fixed before it can be merged. Recent discussion in the internal issue 420 revealed that the current wording of this PR causes the following code snippet to be UB:
The current PR makes this UB because the command could run even after the buffer is destroyed. Code like this is currently legal according to the current wording of SYCL 2020, and I think we want to continue to allow code like this. I see two options:
|
use cases and examples needed |
Book 1 hour in advance to discuss this. |
a good F2F |
Thanks for the great presentation today explaining your proposal with all the corner cases about the life of |
@gmlueck can you send me your presentation so I can make a new version commenting your examples with a different hypothesis? |
I have update my presentation about this on the Khronos-internal https://members.khronos.org/wg/SYCL/document/31310 |
Clarify that the application must not use an accessor after its
associated buffer / image is destroyed, Also clarify the point at
which requisites are added for a command. This happens after the
command group function object returns, not during the call to
parallel_for
(etc.)Closes internal issue 420