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