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