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