-
Notifications
You must be signed in to change notification settings - Fork 68
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
Move description of shared_ptr buffer destructor #298
base: main
Are you sure you want to change the base?
Changes from 1 commit
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 |
---|---|---|
|
@@ -5029,20 +5029,30 @@ copy of data back to host. | |
When the buffer is destroyed, the destructor will block until all work | ||
in queues on the buffer have completed. | ||
-- | ||
. A buffer can be constructed using a [code]#shared_ptr# to host | ||
data. This pointer is shared between the SYCL application and the | ||
runtime. In order to allow synchronization between the application and | ||
the runtime a [code]#mutex# is used which will be locked by the | ||
runtime whenever the data is in use, and unlocked when it is no longer | ||
needed. | ||
. A buffer can be constructed using a [code]#std::shared_ptr# to host | ||
data. This is similar to the case when the buffer is constructed using a | ||
raw [code]#hostData# pointer, except that the SYCL runtime holds a | ||
reference count to the [code]#shared_ptr# for the lifetime of the buffer. | ||
Thus, the application can release its [code]#shared_ptr# even before the | ||
buffer is destroyed. The buffer will use this host memory for its full | ||
lifetime, but the contents of this host memory are unspecified for the | ||
lifetime of the buffer. If the host memory is modified on the host or if | ||
it is used to construct another buffer or image during the lifetime of this | ||
buffer, then the results are undefined. The initial contents of the buffer | ||
will be the contents of the host memory at the time of construction. | ||
+ | ||
-- | ||
The [code]#shared_ptr# reference counting is used in order to prevent | ||
destroying the buffer host data prematurely. If the [code]#shared_ptr# | ||
is deleted from the user application before buffer destruction, the buffer | ||
can continue securely because the pointer hasn't been destroyed yet. It will | ||
not copy data back to the host before destruction, however, as the | ||
application side has already deleted its copy. | ||
When the buffer is destroyed, the destructor is guaranteed to block if the | ||
application still holds a reference count to the [code]#shared_ptr# at the | ||
point when the destructor runs. In this case, the destructor will block until | ||
all work in queues on the buffer have completed. The buffer destructor may | ||
also copy-back data to host memory. This happens only if the application still | ||
holds a reference count to the [code]#shared_ptr# and only if it is otherwise | ||
necessary to copy this data back. | ||
|
||
If the underlying type of the [code]#shared_ptr# is [code]#const#, then the | ||
buffer is read-only; only read accessors are allowed on the buffer and no | ||
copy-back to host memory is performed. | ||
|
||
Note that since there is an implicit conversion of a | ||
[code]#std::unique_ptr# to a [code]#std::shared_ptr#, a | ||
|
@@ -6057,57 +6067,6 @@ buffer construction. | |
---- | ||
|
||
|
||
==== Shared SYCL ownership of the host memory | ||
|
||
When an instance of [code]#std::shared_ptr# is passed to the buffer | ||
constructor, then the buffer object and the developer's application share | ||
the memory region. If the shared pointer is still used on the application's | ||
side then the data will be copied back from the buffer or image and will be | ||
available to the application after the buffer or image is destroyed. | ||
|
||
If the [code]#shared_ptr# is not empty, the contents of the referenced | ||
memory are used to initialize the buffer. If the [code]#shared_ptr# is | ||
empty, then the buffer is created with uninitialized memory. | ||
|
||
When the buffer is destroyed and the data have potentially been updated, if | ||
the number of copies of the shared pointer outside the runtime is 0, there | ||
is no user-side shared pointer to read the data. Therefore the data is not | ||
copied out, and the buffer destructor does not need to wait for the data | ||
processes to be finished, as the outcome is not needed on the application's | ||
side. | ||
|
||
This behavior can be overridden using the [code]#set_final_data()# | ||
member function of the buffer class, which will by any means force the buffer | ||
destructor to wait until the data is copied to wherever the | ||
[code]#set_final_data()# member function has put the data (or not wait nor copy | ||
if set final data is [code]#nullptr)#. | ||
|
||
[source,,linenums] | ||
---- | ||
{ | ||
std::shared_ptr<int> ptr { data }; | ||
{ | ||
buffer<int, 1> b { ptr, range<2>{ 10, 10 } }; | ||
// update the data | ||
[...] | ||
} // Data is copied back because there is an user side shared_ptr | ||
} | ||
---- | ||
|
||
[source,,linenums] | ||
---- | ||
{ | ||
std::shared_ptr<int> ptr { data }; | ||
{ | ||
buffer<int, 1> b { ptr, range<2>{ 10, 10 } }; | ||
// update the data | ||
[...] | ||
ptr.reset(); | ||
} // Data is not copied back, there is no user side shared_ptr. | ||
} | ||
---- | ||
|
||
|
||
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 keep these examples? 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 checked again : these were the only 2 code examples showing 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 agree that the examples are good to keep. I was hoping to move all of the normative description of the buffer APIs to section 4.7.2 Buffers, and in particular the normative description of the blocking behavior and copy-back behavior to section 4.7.2.3 Buffer synchronization rules. How do you feel about the following ... I'll still augment section 4.7.2.3 to contain a complete description of the blocking behavior and copy-back behavior, so all of that information is together in one place. We can still keep section 4.7.4, though, as a set of examples. In this case, I'd probably retitle the section to something like "Buffer examples", and the introduction of that section will read something like:
Over time, we can add more examples to this section to clarify other behavior about buffers. 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 restored the examples, and converted section 4.7.4 to an examples section as I describe in the comment above. See commit 15e8eab. Note that this PR is incomplete at this point because I need answers to the questions in (https://gitlab.khronos.org/sycl/Specification/-/issues/478) |
||
[[subsec:mutex]] | ||
=== Synchronization primitives | ||
|
||
|
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.
This line require a comment, for casual readers not using routinely
std::shared_ptr
.