-
Notifications
You must be signed in to change notification settings - Fork 73
Clarify buffer and accessor lifetime #240
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6060,9 +6060,23 @@ to local memory on a <<device>>, and they define the *requirements* to memory | |
| objects which determine the scheduling of <<kernel,kernels>> (see | ||
| <<sub.section.memmodel.app>>). | ||
|
|
||
| A memory object requirement is created when an accessor is constructed, unless | ||
| the accessor is a placeholder in which case the requirement is created when | ||
| the accessor is bound to a <<command>> by calling [code]#handler::require()#. | ||
| A memory object requirement is created by a <<command-group-function-object>> | ||
| whenever a non-placeholder accessor is constructed during execution of that | ||
| function and whenever a placeholder accessor is bound to a <<command>> during | ||
| execution of that function by calling [code]#handler::require()#. These | ||
| requirements are created sometime after the <<command-group-function-object>> | ||
| returns to the [code]#submit()# function and before the [code]#submit()# | ||
| function itself returns. | ||
|
|
||
| [NOTE] | ||
| ==== | ||
| Since the memory object requirements aren't created until after the command | ||
| 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 | ||
| added. | ||
| ==== | ||
|
|
||
| There are several different {cpp} classes that implement accessors: | ||
|
|
||
|
|
@@ -6438,6 +6452,15 @@ being bound to a <<command-group>> with [code]#handler::require()#, the | |
| implementation throws a synchronous [code]#exception# with the | ||
| [code]#errc::kernel_argument# error code when the <<command>> is submitted. | ||
|
|
||
| An [code]#accessor# to a buffer is only a view over that buffer. 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 accessor. Calling any | ||
| member function on an accessor after its associated buffer has been destroyed | ||
| 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. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can give up on this. |
||
|
|
||
|
|
||
| ===== Interface for buffer command accessors | ||
|
|
||
|
|
@@ -7671,6 +7694,12 @@ The [code]#host_accessor# class supports the following access modes: | |
| [code]#access_mode::read#, [code]#access_mode::write# and | ||
| [code]#access_mode::read_write#. | ||
|
|
||
| A [code]#host_accessor# to a buffer is only a view over that buffer. | ||
| 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. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
|
||
|
|
||
| ===== Interface for buffer host accessors | ||
|
|
||
|
|
@@ -8472,6 +8501,16 @@ template parameter as [code]#image_target::host_task# and then use the | |
| [code]#unsampled_image_accessor# from a <<sycl-kernel-function>> are ill | ||
| formed. | ||
|
|
||
| An unsampled image accessor is only a view over its associated image. | ||
| Therefore, it is the application's responsibility to ensure that the lifetime | ||
| of the image is at least as long as the lifetime of the accessor. Calling any | ||
| member function on an unsampled image accessor after its associated image has | ||
| been 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. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we have more content about
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your comment simplify the implementation, so I am fine with it. |
||
|
|
||
|
|
||
| ===== Interface for unsampled image accessors | ||
|
|
||
|
|
@@ -8744,6 +8783,15 @@ from a <<host-task>> are ill formed. Likewise, programs which specify this | |
| template parameter as [code]#image_target::host_task# and then use the | ||
| [code]#sampled_image_accessor# from a <<sycl-kernel-function>> are ill formed. | ||
|
|
||
| A sampled image accessor is only a view over its associated image. Therefore, | ||
| it is the application's responsibility to ensure that the lifetime of the image | ||
| is at least as long as the lifetime of the accessor. Calling any member | ||
| function on a sampled image accessor after its associated image has been | ||
| 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. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
|
||
|
|
||
|
|
||
| ===== Interface for sampled image accessors | ||
|
|
||
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
submitlambda 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.