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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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