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 CeedCallBackend(CeedDestroy(&ceed_delegate)); 111 112 // Set queue and context for Ceed Fallback object 113 CeedCallBackend(CeedGetOperatorFallbackCeed(ceed, &ceed_fallback)); 114 if (ceed_fallback) { 115 CeedCallBackend(CeedSetStream_Sycl(ceed_fallback, handle)); 116 } 117 CeedCallBackend(CeedDestroy(&ceed_fallback)); 118 return CEED_ERROR_SUCCESS; 119 } 120 121 //------------------------------------------------------------------------------ 122