Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 51 additions & 3 deletions adoc/chapters/programming_interface.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

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.

Copy link
Member

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.

added.
====

There are several different {cpp} classes that implement accessors:

Expand Down Expand Up @@ -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.
Copy link
Member

@keryell keryell Apr 7, 2022

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.

Copy link
Member

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.



===== Interface for buffer command accessors

Expand Down Expand Up @@ -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.
Copy link
Member

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.

Copy link
Member

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.



===== Interface for buffer host accessors

Expand Down Expand Up @@ -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.
Copy link
Member

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.

Copy link
Member

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.



===== Interface for unsampled image accessors

Expand Down Expand Up @@ -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.
Copy link
Member

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.




===== Interface for sampled image accessors
Expand Down