KhronosGroup / SYCL-Docs

SYCL Open Source Specification
Other
109 stars 67 forks source link

Placeholder behavior in SYCL kernel functions and host_task #368

Open steffenlarsen opened 1 year ago

steffenlarsen commented 1 year ago

The exception thrown for passing a placeholder accessor to a command is described as:

If a placeholder accessor is passed as an argument to a command without first being bound to a command group with handler::require(), the implementation throws a synchronous exception with the errc::kernel_argument error code when the command is submitted.

Based on it it also follows that a host_task should throw an exception with errc::kernel_argument synchronously when being passed a placeholder accessor. This has the following issues:

  1. It require introspection into the arguments captured or stored in a host_task function objects.
  2. Throwing an exception with errc::kernel_argument from a host_task launch is potentially confusing, given a host task isn't considered a SYCL kernel function.

Suggested solution: Change the wording to specify that the above statement only applies to SYCL kernel functions. Additionally, clarify that operations useable inside a host_task that require non-placeholder accessors (e.g. interop_handle::get_native_mem()) throws a more appropriate exception during the execution of the host task function, which in turn would be an asynchronous exception.

gmlueck commented 1 year ago

clarify that operations useable inside a host_task that require non-placeholder accessors (e.g. interop_handle::get_native_mem()) throws a more appropriate exception during the execution of the host task function

Just pointing out that there is a more common case that does not rely on the interop APIs. You can create a placeholder accessor that has target::host_task.

I wonder if there is some more fundamental problem with target::host_task placeholder accessors, though. For example, a case like this:

accessor acc{buf, read_write_host_task};  // placeholder
q.submit([&](handler &cgh) {
  cgh.require(acc);
  cgh.host_task([=] {
    // use acc
  });
});
q.submit([&](handler &cgh) {
  cgh.require(acc);
  cgh.host_task([=] {
    // use acc
  });
});

Consider the case where both host tasks are queued before either executes. Can we implement this correctly, or will the second call to cgh.require overwrite the effect of the first call, causing the first task's accessor to be bound to the second handler?