From be0cf3c18e67732d8363137f6a44166f0c2b8071 Mon Sep 17 00:00:00 2001 From: Michel Schanen Date: Thu, 18 Jun 2026 15:44:10 +0000 Subject: [PATCH] Use the cached task-local SYCL queue for oneMKL FFT plans `_create_descriptor` built fresh syclDevice/syclContext/syclQueue objects for every FFT plan. Once those wrappers become garbage their finalizers (syclQueueDestroy etc.) tear down SYCL runtime state for the still-in-use underlying Level Zero queue, corrupting later DFT commits and crashing at process exit. Use the cached task-local `sycl_queue(global_queue(...))` accessor that every other oneMKL wrapper already uses, so the plan shares the managed queue lifetime instead of owning a throwaway one. Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/mkl/fft.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/mkl/fft.jl b/lib/mkl/fft.jl index 745ff65f..4429801b 100644 --- a/lib/mkl/fft.jl +++ b/lib/mkl/fft.jl @@ -105,11 +105,13 @@ function _create_descriptor(sz::NTuple{N,Int}, T::Type, complex::Bool) where {N} desc = desc_ref[] # Do not program descriptor scaling; we'll perform inverse normalization manually. # Set placement explicitly based on plan type later - # Construct a SYCL queue from current Level Zero context/device (reuse global queue) + # Use the task-local cached SYCL queue wrapping the global Level Zero queue, like the + # other oneMKL wrappers do. Creating fresh syclContext/syclQueue objects per plan is + # unsound: once they become garbage their finalizers (syclQueueDestroy etc.) tear down + # SYCL runtime state for the still-in-use underlying queue, corrupting later DFT + # commits and crashing at process exit. ze_ctx = oneAPI.context(); ze_dev = oneAPI.device() - sycl_dev = SYCL.syclDevice(SYCL.syclPlatform(oneAPI.driver()), ze_dev) - sycl_ctx = SYCL.syclContext([sycl_dev], ze_ctx) - q = SYCL.syclQueue(sycl_ctx, sycl_dev, oneAPI.global_queue(ze_ctx, ze_dev)) + q = oneAPI.sycl_queue(oneAPI.global_queue(ze_ctx, ze_dev)) return desc, q end