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