1 // Copyright (c) 2017-2026, 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 <sstream>
12 #include <string>
13 #include <sycl/sycl.hpp>
14
15 //------------------------------------------------------------------------------
16 // Device information backend init
17 //------------------------------------------------------------------------------
CeedInit_Sycl(Ceed ceed,const char * resource)18 int CeedInit_Sycl(Ceed ceed, const char *resource) {
19 Ceed_Sycl *data;
20 const char *device_spec = std::strstr(resource, ":device_id=");
21 const int device_id = (device_spec) ? atoi(device_spec + 11) : 0;
22
23 sycl::info::device_type device_type;
24 if (std::strstr(resource, "/gpu/sycl")) {
25 device_type = sycl::info::device_type::gpu;
26 } else if (std::strstr(resource, "/cpu/sycl")) {
27 device_type = sycl::info::device_type::cpu;
28 } else {
29 return CeedError(ceed, CEED_ERROR_BACKEND, "Unsupported SYCL device type requested");
30 }
31
32 auto sycl_devices = sycl::device::get_devices(device_type);
33 int device_count = sycl_devices.size();
34
35 if (0 == device_count) {
36 return CeedError(ceed, CEED_ERROR_BACKEND, "No SYCL devices of the requested type are available");
37 }
38
39 // Validate the requested device_id
40 if (device_count < device_id + 1) {
41 return CeedError(ceed, CEED_ERROR_BACKEND, "Invalid SYCL device id requested");
42 }
43
44 sycl::device sycl_device{sycl_devices[device_id]};
45 // Check that the device supports explicit device allocations
46 if (!sycl_device.has(sycl::aspect::usm_device_allocations)) {
47 return CeedError(ceed, CEED_ERROR_BACKEND,
48 "The requested SYCL device does not support explicit "
49 "device allocations.");
50 }
51
52 // Creating an asynchronous error handler
53 sycl::async_handler sycl_async_handler = [&](sycl::exception_list exceptionList) {
54 for (std::exception_ptr const &e : exceptionList) {
55 try {
56 std::rethrow_exception(e);
57 } catch (sycl::exception const &e) {
58 std::ostringstream error_msg;
59 error_msg << "SYCL asynchronous exception caught:\n";
60 error_msg << e.what() << std::endl;
61 return CeedError(ceed, CEED_ERROR_BACKEND, error_msg.str().c_str());
62 }
63 }
64 return CEED_ERROR_SUCCESS;
65 };
66
67 sycl::context sycl_context{sycl_device.get_platform().get_devices()};
68 sycl::queue sycl_queue{sycl_context, sycl_device, sycl_async_handler, sycl::property::queue::in_order{}};
69
70 CeedCallBackend(CeedGetData(ceed, &data));
71
72 data->sycl_device = sycl_device;
73 data->sycl_context = sycl_context;
74 data->sycl_queue = sycl_queue;
75 return CEED_ERROR_SUCCESS;
76 }
77
78 //------------------------------------------------------------------------------
79 // Backend destroy
80 //------------------------------------------------------------------------------
CeedDestroy_Sycl(Ceed ceed)81 int CeedDestroy_Sycl(Ceed ceed) {
82 Ceed_Sycl *data;
83
84 CeedCallBackend(CeedGetData(ceed, &data));
85 CeedCallBackend(CeedFree(&data));
86 return CEED_ERROR_SUCCESS;
87 }
88
89 //------------------------------------------------------------------------------
90 // Use an external queue
91 //------------------------------------------------------------------------------
CeedSetStream_Sycl(Ceed ceed,void * handle)92 int CeedSetStream_Sycl(Ceed ceed, void *handle) {
93 Ceed ceed_delegate = NULL, ceed_fallback = NULL;
94 Ceed_Sycl *data;
95
96 CeedCallBackend(CeedGetData(ceed, &data));
97
98 CeedCheck(handle, ceed, CEED_ERROR_BACKEND, "Stream handle is null");
99 sycl::queue *q = static_cast<sycl::queue *>(handle);
100
101 // Ensure we are using the expected device
102 CeedCheck(data->sycl_device == q->get_device(), ceed, CEED_ERROR_BACKEND, "Device mismatch between provided queue and ceed object");
103 data->sycl_device = q->get_device();
104 data->sycl_context = q->get_context();
105 data->sycl_queue = *q;
106
107 CeedCallBackend(CeedGetDelegate(ceed, &ceed_delegate));
108 if (ceed_delegate) {
109 CeedCallBackend(CeedSetStream_Sycl(ceed_delegate, handle));
110 }
111 CeedCallBackend(CeedDestroy(&ceed_delegate));
112
113 // Set queue and context for Ceed Fallback object
114 CeedCallBackend(CeedGetOperatorFallbackCeed(ceed, &ceed_fallback));
115 if (ceed_fallback) {
116 CeedCallBackend(CeedSetStream_Sycl(ceed_fallback, handle));
117 }
118 CeedCallBackend(CeedDestroy(&ceed_fallback));
119 return CEED_ERROR_SUCCESS;
120 }
121
122 //------------------------------------------------------------------------------
123