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