-
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
Should we add "backend::none"? #564
Comments
I did go back and forth in my mind about it.
On the other hand, adding |
That's a good point. We should not write the core spec to be too proscriptive about what a backend can do. How about this? The core spec definition for
Each backend specification can then provide further guarantees if it wants. For example, the OpenCL backend specification might say something like:
However, I still think it was a mistake for the core SYCL spec to say that the default-constructed |
Sound good to me!
I think it's still useful to have a backend object for default-constructed events associated with the default-constructed queue. In short, I think we should let all those kinds of implementation-choise to the backend spec and not try to formalize anything too much on the "main" spec. |
This seems like an asymmetry in our API, though. You can create a default-constructed event only for the backend associated with the default device constructor. What if you wanted to create a default-constructed event for OpenCL or CUDA (on DPC++)? I think it was a mistake for the core SYCL API to favor one backend like this. If we really want an API to create a "signaled" event that is specific to a particular backend, we should instead create a backend interop API that does this. For example, Level Zero could have something like |
That makes sense. We should remove this requirement from the spec. But I still think we should not put the required 'backend::none' in the core spec; what default constructed
I can always do I'm just always a little concerned about "over-specifying" stuff and that this will beat us in the future. But I also like clear API. So to be honest I'm a little torn over on this one :) But the core idea of |
I can live with this. We can change the spec to say that the backend for the default-constructed event is implementation-defined. |
Clarify exactly what we mean by "backend". I think it has always been our intention that the `backend` enumeration and the `get_backend` member function tell an application what sort of interoperation is supported by a SYCL object. For example, if a SYCL object returns `backend::opencl` from its `get_backend` function, that SYCL object supports interoperation as defined by the OpenCL backend interoperation specification. This commit clarifies the spec to say that explicitly. It also became clear that we need a `backend::none` enumerator to indicate that a SYCL object does not support any backend interoperation. For example, this would be useful if a vendor implements SYCL directly on hardware, without using a documented low-level offload API. This commit also makes a minor change to the default `event` constructor. Previously, we required the backend for such an event to be the same as the backend for the default device. After some implementation experience, we decided that this is not practical. Requiring interoperation with a particular backend constrains the implementation too much. It also seems arbitrary to require the default-constructed event to have a particular backend. To address these concerns, this commit loosens the requirement, allowing an implementation to choose which backend (if any) the default-constructed event has. Closes KhronosGroup#564
Clarify exactly what we mean by "backend". I think it has always been our intention that the `backend` enumeration and the `get_backend` member function tell an application what sort of interoperation is supported by a SYCL object. For example, if a SYCL object returns `backend::opencl` from its `get_backend` function, that SYCL object supports interoperation as defined by the OpenCL backend interoperation specification. This commit clarifies the spec to say that explicitly. It also became clear that we need a `backend::none` enumerator to indicate that a SYCL object does not support any backend interoperation. For example, this would be useful if a vendor implements SYCL directly on hardware, without using a documented low-level offload API. Many of the changes in this commit merely remove sentences that imply that every SYCL object necessarily has some backend. This commit also makes a minor change to the default `event` constructor. Previously, we required the backend for such an event to be the same as the backend for the default device. After some implementation experience, we decided that this is not practical. Requiring interoperation with a particular backend constrains the implementation too much. It also seems arbitrary to require the default-constructed event to have a particular backend. To address these concerns, this commit loosens the requirement, allowing an implementation to choose which backend (if any) the default-constructed event has. Closes KhronosGroup#564
I'm not sure I'm convinced. This introduces an invalid backend value that now in principle needs to be handled by client code wherever in the SYCL API a backend is used, to solve something that is a design error only in the event backend interop API, or perhaps even the OpenCL backend specification (other backends can always say that events are not supported for interop). The fact that we need some non-trivial rules like you outline to me indicates that AdaptiveCpp does not support backend interop for events, for good reason. I think there can also be other cases where an event is not directly connected to a backend event (e.g. you do I think that fundamentally the event backend interop API is broken. The usual thing the SYCL API does when it is asked to do something it cannot comply with is to throw. Why don't we throw here as well? The fundamental solution to this problem, I think, would be to treat |
PR #577 makes two related changes. Let's take them separately for a moment. One change adds I think Some implementations may choose to return I think you are claiming that adding
This code will continue to work even if we add a new enumerator The other change that #577 makes is to relax the requirements on the backend that is associated with the default-constructed event. Previously, the spec required this to be a specific backend (the same backend as the default device.) In retrospect, that seems like it was a mistake. The PR changes this to say that the backend of the default-constructed event is implementation defined. This does not place any new requirement on implementations, so ACPP can continue to do whatever it does now. In our experience, applications don't want to use backend interop with the default-constructed event anyways, so I think this change will not have an impact on application code. Your observation that there could be cases where a SYCL Responding to this:
Most SYCL APIs provide a way to test for error condition beforehand, so you don't need to surround all your API calls with |
That's true, but what if we have some API in the future that accepts a backend as a non-template argument? AdaptiveCpp already does this internally, and in this case this change requires handling the invalid value everywhere.
Nothing in the SYCL specification requires implementations to expose any kind of backend interop if they don't want to for their own backends. In a non-layered implementation you could just as well have some
Interop is not required anyway. We do have a way already to advertise that no interop is available: By having a backend enum entry that is not one where a backend specification with an interop model exists. If we need a way to query interop abilities for cases where the existing
That's fair, but this is only the case because the main reason of using
Having My argument is: A proper solution requires changing the backend model for |
Doing this would be a really big API break. All the Perhaps our disagreement stems from the meaning of If we agree on this meaning, then I think it becomes clear that the current definition of the default-constructed event makes no sense. The spec currently states that the backend of this event must be the same backend as the device returned by the default selector, this means that the event's Focusing for now on just this one part of the PR, do you agree that it makes sense to relax this mandate and allow the implementation to choose the backend that is associated with the default-constructed event? |
Okay, that's a good point.
Maybe you're right and this is a source of disagreement. I think that ideally, the returned backend is aligned with interop as you say. But I think I see these edge cases more as a defect in the interop API and interop model rather than the backend model. I suspect that intuitively, users might also interpret
Yes, this change would be totally fine for me. I think mandating a specific backend here is probably a remnant of the host backend/host device model from SYCL 1.2.1. |
Side note: But before I forget ( I guess I should start a new thread...)
I guess that means, kernel cannot have a dependency of task running on device who doesn't have a backend (if we follow the interpretation that backend == interop) |
I think we made a mistake in SYCL 2020 for
event::get_backend
in two cases:event
event
that is returned when you submit a host taskIn both of these cases, there's no obvious backend. As a result, there's no obvious backend interop that you can do with these events. For example, what should
get_native
return for these events?I think there's an implicit assumption that when
object.get_backend
returnsbackend::opencl
, an application is allowed to use OpenCL backend interop APIs on that object. Therefore, I think it was a mistake to returnbackend::opencl
for events that are created in the two cases I list above.I think the cleanest solution would be to introduce a new enumerator called
backend::none
for cases like this. When an object reportsbackend::none
, we would not support any backend interop for that object.I also think
backend::none
would be useful for implementations that do not layer on any established "back end". For example, you could imagine an implementation that implements SYCL directly on hardware, without going through any documented backend API. Such an implementation could returnbackend::none
for all calls toget_backend
.I think the specification should clearly specify what
backend
enumerator is returned, though. Implementations should not have complete freedom to choose on an object-by-object basis. Here are the rules that make sense to me:An implementation has complete freedom to decide what backend is returned from
platform::get_backend
for eachplatform
object . This can be a Khronos-defined enumerator likebackend::opencl
, a vendor-defined enumerator likebackend::ext_oneapi_level_zero
, orbackend::none
. Each backend enumerator (except forbackend::none
) should have a matching backend interop specification. Khronos will define this specification if the backend enumerator is defined by Khronos. A vendor should define this specification if the backend enumerator is defined by the vendor.The SYCL specification should clearly document what is returned from all other
class::get_backend
member functions. In most cases, we will say that it returns the same backend as the associated platform. In the two "event" cases that I document above, we will say thatbackend::none
is returned.This seems like the right balance of implementation freedom and API consistency to me.
Since this affects behavior of SYCL 2020 APIs, I think we should consider this as a bug fix to the SYCL 2020 specification.
Comments?
The text was updated successfully, but these errors were encountered: