xref: /libCEED/backends/sycl/ceed-sycl-common.sycl.cpp (revision ee4ca9cbfe2be39196684117442f3ce8d00b6506)
1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other
2 // CEED contributors. All Rights Reserved. See the top-level LICENSE and NOTICE
3 // files for details.
4 //
5 // SPDX-License-Identifier: BSD-2-Clause
6 //
7 // This file is part of CEED:  http://github.com/ceed
8 
9 #include "ceed-sycl-common.hpp"
10 
11 #include <string>
12 #include <sycl/sycl.hpp>
13 
14 //------------------------------------------------------------------------------
15 // Get root resource without device spec
16 //------------------------------------------------------------------------------
17 int CeedSyclGetResourceRoot(Ceed ceed, const char *resource, char **resource_root) {
18   const char *device_spec       = std::strstr(resource, ":device_id=");
19   size_t      resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1;
20   CeedCallBackend(CeedCalloc(resource_root_len, resource_root));
21   memcpy(*resource_root, resource, resource_root_len - 1);
22 
23   return CEED_ERROR_SUCCESS;
24 }
25 
26 //------------------------------------------------------------------------------
27 // Device information backend init
28 //------------------------------------------------------------------------------
29 int CeedSyclInit(Ceed ceed, const char *resource) {
30   const char *device_spec = std::strstr(resource, ":device_id=");
31   const int   device_id   = (device_spec) ? atoi(device_spec + 11) : 0;
32 
33   sycl::info::device_type device_type;
34   if (std::strstr(resource, "/gpu/sycl")) {
35     device_type = sycl::info::device_type::gpu;
36   } else if (std::strstr(resource, "/cpu/sycl")) {
37     device_type = sycl::info::device_type::cpu;
38   } else {
39     return CeedError(ceed, CEED_ERROR_BACKEND, "Unsupported SYCL device type requested");
40   }
41 
42   auto sycl_devices = sycl::device::get_devices(device_type);
43   int  device_count = sycl_devices.size();
44 
45   if (0 == device_count) {
46     return CeedError(ceed, CEED_ERROR_BACKEND, "No SYCL devices of the requested type are available");
47   }
48 
49   // Validate the requested device_id
50   if (device_count < device_id + 1) {
51     return CeedError(ceed, CEED_ERROR_BACKEND, "Invalid SYCL device id requested");
52   }
53 
54   sycl::device sycl_device{sycl_devices[device_id]};
55   // Check that the device supports explicit device allocations
56   if (!sycl_device.has(sycl::aspect::usm_device_allocations)) {
57     return CeedError(ceed, CEED_ERROR_BACKEND,
58                      "The requested SYCL device does not support explicit "
59                      "device allocations.");
60   }
61 
62   // Creating an asynchronous error handler
63   sycl::async_handler sycl_async_handler = [&](sycl::exception_list exceptionList) {
64     for (std::exception_ptr const &e : exceptionList) {
65       try {
66         std::rethrow_exception(e);
67       } catch (sycl::exception const &e) {
68         std::ostringstream error_msg;
69         error_msg << "SYCL asynchronous exception caught:\n";
70         error_msg << e.what() << std::endl;
71         return CeedError(ceed, CEED_ERROR_BACKEND, error_msg.str().c_str());
72       }
73     }
74     return CEED_ERROR_SUCCESS;
75   };
76 
77   sycl::context sycl_context{sycl_device.get_platform().get_devices()};
78   sycl::queue   sycl_queue{sycl_context, sycl_device, sycl_async_handler};
79 
80   Ceed_Sycl *data;
81   CeedCallBackend(CeedGetData(ceed, &data));
82 
83   data->sycl_device  = sycl_device;
84   data->sycl_context = sycl_context;
85   data->sycl_queue   = sycl_queue;
86 
87   return CEED_ERROR_SUCCESS;
88 }
89 
90 //------------------------------------------------------------------------------
91 // Backend destroy
92 //------------------------------------------------------------------------------
93 int CeedDestroy_Sycl(Ceed ceed) {
94   Ceed_Sycl *data;
95   CeedCallBackend(CeedGetData(ceed, &data));
96   CeedCallBackend(CeedFree(&data));
97   return CEED_ERROR_SUCCESS;
98 }
99 
100 //------------------------------------------------------------------------------
101 // Use an external queue
102 //------------------------------------------------------------------------------
103 int CeedSetSyclStream(Ceed ceed, void *handle) {
104   Ceed_Sycl *data;
105   CeedCallBackend(CeedGetData(ceed, &data));
106 
107   if (!handle) {
108     return CeedError(ceed, CEED_ERROR_BACKEND, "Stream handle is null");
109   }
110   sycl::queue *q = static_cast<sycl::queue *>(handle);
111 
112   // Ensure we are using the expected device
113   if (data->sycl_device != q->get_device()) {
114     return CeedError(ceed, CEED_ERROR_BACKEND, "Device mismatch between provided queue and ceed object");
115   }
116   data->sycl_device  = q->get_device();
117   data->sycl_context = q->get_context();
118   data->sycl_queue   = *q;
119 
120   // Revisit this when we have a hierarchy of delegates
121   Ceed ceed_delegate = NULL;
122   CeedCallBackend(CeedGetDelegate(ceed, &ceed_delegate));
123   if (ceed_delegate) {
124     Ceed_Sycl *delegate_data;
125     CeedCallBackend(CeedGetData(ceed_delegate, &delegate_data));
126     delegate_data->sycl_device  = q->get_device();
127     delegate_data->sycl_context = q->get_context();
128     delegate_data->sycl_queue   = *q;
129   }
130 
131   return CEED_ERROR_SUCCESS;
132 }
133 
134 //------------------------------------------------------------------------------
135